1

I have a problem that I would like to solve using Django's ORM. I have the following classes:

class Company:
    name = models.CharField(max_length=200)

class Event:
    title = models.CharField(max_length=200)
    company = models.ForeignKey(Company)

class Registration:
    attended = models.BooleanField(default=False)
    event = models.ForeignKey(Event)

These are simple examples, but basically a Company can have several Events. When a user registers to attend an Event, a Registration is created for that user (I know that field isn't there, that's not the issue). If the user actually shows up to the Event, then that user's Registration object will have "attended=True".

I'm currently generating reports, and what I need is essentially a way to have a Company see all of their Events, and sort by the number of attendees (Registrations with "attended=True").

I have a SQL statement that may give you an idea of what I need (except that instead of just "e.title", obviously a QuerySet would give me back the whole object):

SELECT e.title FROM example_event e LEFT JOIN (SELECT event_id,
COUNT(*) attendees FROM example_registration WHERE attended=1 GROUP BY
event_id) r ON (e.id=r.event_id) ORDER BY r.attendees DESC;

That gives me a properly sorted result set of Event titles. But I'd really like to do this within the ORM and return a QuerySet. Is there any way to do this? I would basically need something like:

events.annotate(attendees=Count('registration__attended=True'))
                .order_by('attendees')

... I know that statement is invalid, but it hopefully gets the point across of what I'm trying to accomplish. Also, I need to always return all of the Events for a Company, because it's a report. They will want to see how all of their Events are performing, even if they have 0 attendees (so something like events.filter(registration__attended=True) won't give me what I need, because it returns only a subset of a Company's Events).

Thanks in advance, I'd really appreciate someone's help here!

4

2 回答 2

3

我不确定您是否要排除使用该extra方法,但您可以执行以下操作:

events = Event.objects.extra(
    select={'attendees': 'SELECT COUNT(*) from event_registration' + \
        ' where attended=1 and event_id=event_event.id'}
).order_by('attendees')
于 2012-10-10T12:41:01.053 回答
0

这应该有效:

events.filter(registration__attended=True)\
      .annotate(attendees=Count('registration'))\
      .order_by('attendees')

注意,那filter()annotate()方法是不可交换的。所以查询之间有区别:

>>> events.annotate(attendees=Count('registration')).filter(registration__attended=True)

>>> events.filter(registration__attended=True).annotate(attendees=Count('registration'))

在文档中阅读更多内容。

于 2012-10-10T11:00:32.723 回答