Как получить сумму строк в 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...
Вернуться на верх