如何通过计算列表中的相关项目来更新实例列表?

问题描述 投票:1回答:1

我想更新一个实例列表,其中包含该类别的书籍链接总数。

回答如下。例如,我有一些书籍链接到 "历史"。我如何在每次调用时更新列表中的总数?

[
    {
        "id": 1,
        "category_name": "History",
        "category_code": "his",
        "is_tab": true,
        "add_time": "2020-03-02T15:56:58.469917Z",
        "total_number": 0
    },
    {
        "id": 2,
        "category_name": "Romance",
        "category_code": "ROM",
        "is_tab": true,
        "add_time": "2020-05-22T17:02:47.919479Z",
        "total_number": 0
    },
    {
        "id": 3,
        "category_name": "Sci-fic",
        "category_code": "S-F",
        "is_tab": true,
        "add_time": "2020-05-22T17:04:57.896846Z",
        "total_number": 0
    }
]

serializer.py

class CategorySerializer(serializers.ModelSerializer):
    class Meta:
        model = BookCategory
        fields = ('id', 'category_name', 'category_code', "is_tab", 'add_time', 'total_number')

view.py

class BookCategoryDetailView(ListCreateAPIView, RetrieveModelMixin):
    queryset = BookCategory.objects.all()
    serializer_class = CategorySerializer

模型.py

class BookCategory(models.Model):
    category_name = models.CharField(default="", max_length=30, verbose_name='Category name')
    category_code = models.CharField(default="", max_length=30, verbose_name='Category code')
    is_tab = models.BooleanField(default=False, verbose_name='is Navigate')
    add_time = models.DateTimeField(auto_now_add=True, verbose_name='Added time')
    total_number = models.BigIntegerField(default=0, verbose_name='Total Number', editable=False)

    class Meta:
        verbose_name = 'Type Category'
        verbose_name_plural = verbose_name
        db_table = 'Book Genre'

    def __str__(self):
        return self.category_name

书籍模型

class Book(models.Model):
    BOOK_STATUS = (
        ('Ongoing', u'Ongoing'),
        ('Completed', u'Completed')
    )
    book_name = models.CharField(default="", max_length=30, verbose_name='Book name', unique=True)
    book_image = models.ImageField(default="", max_length=30, verbose_name='Book image')
    book_status = models.CharField(choices=BOOK_STATUS, default='Ongoing', verbose_name='Book Status', max_length=150,
                                   null=True)
    book_author = models.ForeignKey(settings.AUTH_USER_MODEL,
                                    on_delete=models.SET_NULL,
                                    verbose_name='author',
                                    related_name='author',
                                    null=True)
    book_type = models.ForeignKey(BookCategory,
                                  on_delete=models.CASCADE,
                                  verbose_name='book type',
                                  related_name='book_type',
                                  null=True)
    book_short_description = models.TextField(verbose_name='Short description', default='')
    book_description = models.TextField(verbose_name='Book Description', default='')
    # non-editable values
    total_words = models.IntegerField(verbose_name='Total_words', default=0, editable=False)
    chapter_count = models.IntegerField(verbose_name='Chapter Count', default=0, editable=False)
    total_vote = models.IntegerField(verbose_name='Total vote', default=0, editable=False)
    weekly_vote = models.IntegerField(verbose_name='Weekly vote', default=0, editable=False)
    total_click = models.IntegerField(verbose_name='Total Click', default=0, editable=False)
    fav_num = models.IntegerField(verbose_name='Total favorite number', default=0, editable=False)
    added_time = models.DateTimeField(verbose_name='Added time', auto_now_add=True, editable=False)
    last_update = models.DateTimeField(verbose_name='last update', auto_now=True, editable=False)

    def get_chapter_number(self):
        chapter_count = Chapter.objects.filter(self.id).count()
        return chapter_count

    def get_book_name(self):
        return self.book_name

    class Meta:
        db_table = 'Books'
        verbose_name = 'Novel'
        verbose_name_plural = verbose_name

任何帮助将是非常感激!

python django-rest-framework
1个回答
0
投票

一个常见的误区是给th related_name=… 参数[Django-doc] 与关系本身同名。该 related_name 是关系的名称,在 反面,所以Django创建的关系是为了获得 Book从一个给定的 BookCategory 比如说,你可以把这些名字改成: 因此你可以将这些改名为。

class Book(models.Model):
    # …
    book_author = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        verbose_name='author',
        related_name='authored_books',
        null=True
    )
    book_type = models.ForeignKey(
        BookCategory,
        on_delete=models.CASCADE,
        verbose_name='book type',
        related_name='books',
        null=True
    )
    # …

这也是比较好的 来在数据库中存储重复(聚合)的数据,所以存储书的数量通常不是一个好主意。事实证明,即使是在同一个数据库上,保持数据的同步也比人们想象的要难。这意味着,如果你创建了一本书,删除了一本书,或者改变了一本书的类别,你需要更新计数。此外,有些删除会被其他的删除(级联删除),或者通过Django ORM以外的其他工具触发,所以这只会让问题更加复杂。

因此最好删除该字段。

class BookCategory(models.Model):
    category_name = models.CharField(default="", max_length=30, verbose_name='Category name')
    category_code = models.CharField(default="", max_length=30, verbose_name='Category code')
    is_tab = models.BooleanField(default=False, verbose_name='is Navigate')
    add_time = models.DateTimeField(auto_now_add=True, verbose_name='Added time')
    # no total_number

    class Meta:
        verbose_name = 'Type Category'
        verbose_name_plural = 'Type categories'
        db_table = 'Book Genre'

    def __str__(self):
        return self.category_name

你可以通过Django ORM获取每本图书的数量 BookCategory 通过注释。

from django.db.models import Count

BookCategory.objects.annotate(
    total_number=Count('books')
)

这意味着 BookCategory从这个查询集产生的s将有一个额外的属性。.total_number 的数量,其中包含 相关 Book 对象。

接下来,我们可以更新serialzier,使其与这个 total_number:

class CategorySerializer(serializers.ModelSerializer):
    total_number = serializers.IntegerField(read_only=True)
    class Meta:
        model = BookCategory
        fields = ('id', 'category_name', 'category_code', "is_tab", 'add_time', 'total_number')

最后,在 BookCategoryDetailView 我们通过注释的查询集。

from django.db.models import Count

class BookCategoryDetailView(RetrieveModelMixin, ListCreateAPIView):
    queryset = BookCategory.objects.annotate(total_number=Count('books'))
    serializer_class = CategorySerializer
© www.soinside.com 2019 - 2024. All rights reserved.