Как получить сумму строк в Django Admin
Я хочу показать в админке общее количество денег, использованных в компьютере, добавляя в него вставные части.
models.py
class Material(models.Model):
name = models.CharField(max_length=30, null=False, blank=False)
class Computer(models.Model):
name = models.CharField(max_length=90)
class UsedMaterial(models.Model):
computer = models.ForeignKey(Computer, on_delete=models.SET_NULL, null=True)
material = models.ForeignKey(Material, on_delete=models.SET_NULL, null=True)
cost = models.DecimalField(max_digits=11, decimal_places=2, null=False, blank=False, default=0)
quantity = models.IntegerField(null=False, blank=False, default=0)
admin.py
class UsedMaterialAdmin(admin.TabularInline):
model = UsedMaterial
def total(self, obj):
return obj.cost * obj.quantity
readonly_fields = ("total",)
fields = ("material", "cost", "quantity", "total" )
@admin.register(Computer)
class ComputerAdmin(admin.ModelAdmin):
inlines = [UsedMaterialInline]
fields = ("name",)
Я нашел способ показать общее количество на статью в строке, как вы можете видеть показать снимок экрана Но как мне получить общее количество всех материалов в инлайне?
У меня есть решение, я считаю, что вы можете получить нужную вам информацию. Таким образом, вы можете видеть общее количество товаров (если вы измените его, общую стоимость товаров), и иметь его выписанным в list_display профилей.
Поскольку это мой проект в процессе разработки, я не стал слишком много в нем менять, поэтому я прокомментировал и объяснил все как можно лучше. Английский - не мой родной язык, так что если что-то трудно понять, не стесняйтесь спрашивать ниже! Я протестировал все, это работает просто отлично и может быть хорошим решением, пока вы не найдете способ иметь его внутри вашей модели.
Редактирование: Если вы хотите иметь 1 предмет для каждого инвентаря (чтобы избежать дублирования предметов (пример))
| item | qty |
|---|---|
| car_license | 1 |
| car_license | 1 |
последняя строка - "случайная"
Это будет принято, но если вы хотите сделать их уникальными (пример)
| item | qty |
|---|---|
| car_license | 1 |
Тогда использование Меты ниже поможет вам отбросить ошибку, если вы случайно указали один и тот же элемент несколько раз.
включите это в вашу Inventory модель
class Meta:
unique_together = ('profile', 'item',) # so you can have multiple profiles with multiple items, but you can't have the same item listed 73 times
Отдых:
My admin.py
from django.contrib import admin
from core.models import Profile, Item, Achievement, Inventory
# Register your models here.
# specify the item inline
class InventoryInline(admin.TabularInline):
model = Inventory # which remember, has fields called "profile" (Profile), "item" (item) and "quantity" (quantity).
extra = 0 # just so you can add as many as you want, without removing pre-added ones.
fields = ("item", "quantity",) # You want to be able to specify the 'item' and the 'quantity', the Profile will be selected by default.
class ProfileAdmin(admin.ModelAdmin):
list_display = ('user', 'total_items',) # list_display can call functions too, so we're good to go
inlines = [InventoryInline] # here you specify the inline(s)
filter_horizontal = ['achievements'] # 'items', ignore this comment
raw_id_fields = ['user'] # just so you get a pop-up window instead of a dropdown, it's easier to use in my opinion.
def total_items(self, obj):
items = Inventory.objects.filter(profile=obj) # query the inventory (which had 'profile' and 'items' linked to eachother and had a quantity)
qty = 0 # This is going to be the value we return
for item in items: # we iterate through the queryset we got
qty += item.quantity # we add the quantity of it to the qty variable. If you want to get the sum of costs, you could just do 'item.quantity * item.cost', or make a read-only field that has the value already.
return qty
total_items.short_description = 'Total items' # This is going to be the name of the column.
admin.site.register(Profile, ProfileAdmin) # register so you can access the Profile model as you specified it above.
admin.site.register(Item) # register so you can make items from the admin
admin.site.register(Achievement) # ignore
admin.site.register(Inventory) # if you want to see all the items, register this one too
и
My models.py
from django.db import models
from django.contrib.auth.models import User
from django.core.validators import MinValueValidator
# Create your models here.
# Items model, here you can make unique items.
class Item(models.Model):
name = models.CharField(max_length=32, blank=False, unique=True)
price = models.IntegerField(validators=[MinValueValidator(0)], default=0, help_text="0 means Free")
# IGNORE THIS
# inv = models.ForeignKey(Profile, on_delete=models.CASCADE, blank=False, verbose_name="Item", null=True)
# IGNORE THIS
# Including this you can return the object's name, instead of "Item Object (1)".
def __str__(self) -> str:
return "%s" %(self.name)
# Here you can make achievements with the mentioned method.
class Achievement(models.Model):
name = models.CharField(max_length=32, blank=False, unique=True)
def __str__(self) -> str:
return "%s" %(self.name)
# Here you can make inventories, linkind one Profile to one user.
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, blank=False, verbose_name="Belongs to")
achievements = models.ManyToManyField(Achievement, blank=True)
# IGNORE THIS
# items = models.ManyToManyField(Item, blank=True)
# IGNORE THIS
def __str__(self) -> str:
return "Profile of %s" %(self.user)
# You need to register a new model where you store the items you give in the inventories.
class Inventory(models.Model):
profile = models.ForeignKey(Profile, on_delete=models.SET_NULL, null=True) # to which Profile you want to link the item
item = models.ForeignKey(Item, on_delete=models.SET_NULL, null=True) # which item
quantity = models.IntegerField(null=False, blank=False, default=0, validators=[MinValueValidator(0)]) # how many of it
def __str__(self) -> str:
return "%s's %s of %s" %(self.profile.user, self.item, self.quantity) # This is just so you'll see the user, the given item and quantity better instead of just "Inventory Item (1)", etc...