mirror of
https://github.com/django/django.git
synced 2025-07-17 16:19:12 +00:00
[3.1.x] Modernized custom manager example
Since this example was added 15 years ago in a8ccdd0fcd631e8e928ef20547e1fe3e313dc607, the ORM has gained the ability to do the `COUNT(*)` related query, so do it with the ORM to avoid misleading users that raw SQL is only supported from manager methods. Backport of 59e503b6708d41a44f2aa320272de3e2ecb5d65c from master
This commit is contained in:
parent
82e1294602
commit
a271d8c15c
@ -55,47 +55,34 @@ functionality to your models. (For "row-level" functionality -- i.e., functions
|
|||||||
that act on a single instance of a model object -- use :ref:`Model methods
|
that act on a single instance of a model object -- use :ref:`Model methods
|
||||||
<model-methods>`, not custom ``Manager`` methods.)
|
<model-methods>`, not custom ``Manager`` methods.)
|
||||||
|
|
||||||
A custom ``Manager`` method can return anything you want. It doesn't have to
|
For example, this custom ``Manager`` adds a method ``with_counts()``::
|
||||||
return a ``QuerySet``.
|
|
||||||
|
|
||||||
For example, this custom ``Manager`` offers a method ``with_counts()``, which
|
|
||||||
returns a list of all ``OpinionPoll`` objects, each with an extra
|
|
||||||
``num_responses`` attribute that is the result of an aggregate query::
|
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.db.models.functions import Coalesce
|
||||||
|
|
||||||
class PollManager(models.Manager):
|
class PollManager(models.Manager):
|
||||||
def with_counts(self):
|
def with_counts(self):
|
||||||
from django.db import connection
|
return self.annotate(
|
||||||
with connection.cursor() as cursor:
|
num_responses=Coalesce(models.Count("response"), 0)
|
||||||
cursor.execute("""
|
)
|
||||||
SELECT p.id, p.question, p.poll_date, COUNT(*)
|
|
||||||
FROM polls_opinionpoll p, polls_response r
|
|
||||||
WHERE p.id = r.poll_id
|
|
||||||
GROUP BY p.id, p.question, p.poll_date
|
|
||||||
ORDER BY p.poll_date DESC""")
|
|
||||||
result_list = []
|
|
||||||
for row in cursor.fetchall():
|
|
||||||
p = self.model(id=row[0], question=row[1], poll_date=row[2])
|
|
||||||
p.num_responses = row[3]
|
|
||||||
result_list.append(p)
|
|
||||||
return result_list
|
|
||||||
|
|
||||||
class OpinionPoll(models.Model):
|
class OpinionPoll(models.Model):
|
||||||
question = models.CharField(max_length=200)
|
question = models.CharField(max_length=200)
|
||||||
poll_date = models.DateField()
|
|
||||||
objects = PollManager()
|
objects = PollManager()
|
||||||
|
|
||||||
class Response(models.Model):
|
class Response(models.Model):
|
||||||
poll = models.ForeignKey(OpinionPoll, on_delete=models.CASCADE)
|
poll = models.ForeignKey(OpinionPoll, on_delete=models.CASCADE)
|
||||||
person_name = models.CharField(max_length=50)
|
# ...
|
||||||
response = models.TextField()
|
|
||||||
|
|
||||||
With this example, you'd use ``OpinionPoll.objects.with_counts()`` to return
|
With this example, you'd use ``OpinionPoll.objects.with_counts()`` to get a
|
||||||
that list of ``OpinionPoll`` objects with ``num_responses`` attributes.
|
``QuerySet`` of ``OpinionPoll`` objects with the extra ``num_responses``
|
||||||
|
attribute attached.
|
||||||
|
|
||||||
Another thing to note about this example is that ``Manager`` methods can
|
A custom ``Manager`` method can return anything you want. It doesn't have to
|
||||||
access ``self.model`` to get the model class to which they're attached.
|
return a ``QuerySet``.
|
||||||
|
|
||||||
|
Another thing to note is that ``Manager`` methods can access ``self.model`` to
|
||||||
|
get the model class to which they're attached.
|
||||||
|
|
||||||
Modifying a manager's initial ``QuerySet``
|
Modifying a manager's initial ``QuerySet``
|
||||||
------------------------------------------
|
------------------------------------------
|
||||||
|
Loading…
x
Reference in New Issue
Block a user