簡體   English   中英

帶有注釋的 Django 查詢集

[英]Django Queryset with annotate

我正在 Django Manager 模型中編寫一種方法。 我想編寫一種方法來找出每位作者的所有已售副本(書籍)的數量。

我有兩個用Manager編寫的模型和方法。 我的問題是該方法也應該可以從任何作者查詢集鏈接,例如

Author.objects.filter(...).exlucde(...).total_copies_sold()

也應該工作。

例子:

author = Author.objects.create(...)
Book.objects.create(..., author=author, copies_sold=10)
Book.objects.create(..., author=author, copies_sold=20)

author_total_books = Author.objects.total_copies_sold().first()
>>> author_total_books.copies
30

在我的代碼下面。 它的工作原理類似於上面的示例,但隨后我嘗試了以下操作:

author_books = Author.objects.filter(id=2).total_copies_sold()

我有

'QuerySet' 對象沒有屬性 'annotate'

class AuthorManager(models.Manager):

    def total_copies_sold(self):
        return self.get_queryset().annotate(copies=Sum('book__copies_sold')



class Author(models.Model):
    first_name = models.CharField(max_length=120)
    last_name = models.CharField(max_length=120)

    objects = AuthorManager()


class Book(models.Model):
    title = models.CharField(max_length=120)
    copies_sold = models.PositiveIntegerField()
    author = models.ForeignKey(Author, on_delete=models.CASCADE, related_name='books')

[編輯]

謝謝 schillingt 的回復。 我補充說:

class AuthorQueryset(models.QuerySet):
    def total_copies_sold(self):
        return self.annotate(copies=Sum('books__copies_sold'))

我試過類似的東西:

author_books = Author.objects.filter(id=2).total_copies_sold()

>>> author_books.copies

我有

“AuthorQueryset”對象沒有“副本”屬性

您需要使用Manager.from_queryset來設置您的經理。 這是文檔

class AuthorQueryset(models.QuerySet):
    def total_copies_sold(self):
        ...

class Author(models.Model):
    objects = models.Manager.from_queryset(AuthorQueryset)()

你要找的是:

from django.db import models
from django.db.models import Sum
from django.db.models.functions import Coalesce


class AuthorManager(models.Manager):
    def get_queryset(self):
        return AuthorQuerySet(self.model, using=self._db)

    def annotate_with_copies_sold(self):
        return self.get_queryset().annotate_with_copies_sold()


class AuthorQuerySet(models.QuerySet):
    def annotate_with_copies_sold(self):
        return self.annotate(copies_sold=Sum('books__copies_sold'))


class Author(models.Model):
    objects = AuthorManager()
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)


class Book(models.Model):
    title = models.CharField(max_length=30)
    copies_sold = models.PositiveIntegerField()
    author = models.ForeignKey(Author, on_delete=models.CASCADE, related_name='books')

現在可以鏈接查詢,例如:

author_total_books = Author.objects.total_copies_sold().first()

但是,您將無法在 QuerySet 對象上使用它,例如:

author_books = Author.objects.filter(id=2).total_copies_sold()

那是因為您正在注釋 Author 對象,而不是 QuerySet。 要獲得該結果,您應該執行:

Author.objects.annotate_with_copies_sold().get(id=2)
author.copies_sold 
15
from django.db import models
from django.db.models import Sum
from django.db.models.functions import Coalesce

class AuthorManager(models.Manager):
    def get_queryset(self):
        return AuthorQuerySet(self.model, using=self._db)
    
    def annotate_with_copies_sold(self):
        return self.get_queryset().annotate_with_copies_sold()

class AuthorQuerySet(models.QuerySet):
    def annotate_with_copies_sold(self):
        # Write your solution here
        return self.annotate(copies_sold=Coalesce(Sum('books__copies_sold'), 0))


class Author(models.Model):
    # Make sure this manager is available.
    objects = AuthorManager()
    # objects = models.Manager.from_queryset(AuthorQuerySet)()
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)


class Book(models.Model):
    title = models.CharField(max_length=30)
    copies_sold = models.PositiveIntegerField()
    author = models.ForeignKey(Author, on_delete=models.CASCADE, related_name='books')
    enter code here
class AuthorManager(models.Manager):
    def get_queryset(self):
        return AuthorQuerySet(self.model, using=self._db)

    def annotate_with_copies_sold(self):
        return self.get_queryset().annotate_with_copies_sold()

class AuthorQuerySet(models.QuerySet):
    def annotate_with_copies_sold(self):
        return self.annotate(copies_sold=Sum('Book_Author__copies_sold'))


class Author(models.Model):
    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)
    objects = AuthorManager()

    class Meta:
        verbose_name_plural = "Author" 
        verbose_name = 'Author'
        ordering = ('first_name','last_name')

class Book(models.Model):
    title = models.CharField(max_length=250, unique=True)
    copies_sold = models.PositiveIntegerField(default=0)
    author = models.ForeignKey(Author, on_delete=models.CASCADE, related_name='Book_Author')

    class Meta:
        verbose_name_plural = "Book" 
        verbose_name = 'Book'
        ordering = ('title','copies_sold')




from vehicles.models import Author, Book
try:
    author  = Author.objects.get(first_name='Mark', last_name='Twain')
except Author.DoesNotExist:
    author  = Author.objects.create(first_name='Mark', last_name='Twain')

try:
    book = Book.objects.get(author=author, title='Adventrure of Huckleberry Finn', copies_sold=7)
except Book.DoesNotExist:
    book = Book.objects.create(author=author, title='Adventrure of Huckleberry Finn', copies_sold=7)
    pass
try:
    book = Book.objects.get(author=author, title='Adventrure of Tomm Saywer', copies_sold=4)
except Book.DoesNotExist:
    book = Book.objects.create(author=author, title='Adventrure of Tomm Saywer', copies_sold=4)
    pass

author = Author.objects.annotate_with_copies_sold().first()
print(author.copies_sold)
11

1.Create AuthorManager, AuthorQuerySet classes from Author and Books
2.Create Author, Book models 
3.Prepare Test Data and use model manager to filter the queryset

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM