Django ORM: Selecting related set

后端 未结 4 1078
遥遥无期
遥遥无期 2020-12-24 13:51

Say I have 2 models:

class Poll(models.Model):
    category = models.CharField(u\"Category\", max_length = 64)
    [...]

class Choice(models.Model):
    pol         


        
相关标签:
4条回答
  • 2020-12-24 14:20

    Update: Since Django 1.4, this feature is built in: see prefetch_related.

    First answer: don't waste time writing something like qbind until you've already written a working application, profiled it, and demonstrated that N queries is actually a performance problem for your database and load scenarios.

    But maybe you've done that. So second answer: qbind() does what you'll need to do, but it would be more idiomatic if packaged in a custom QuerySet subclass, with an accompanying Manager subclass that returns instances of the custom QuerySet. Ideally you could even make them generic and reusable for any reverse relation. Then you could do something like:

    Poll.objects.filter(category='foo').fetch_reverse_relations('choices_set')
    

    For an example of the Manager/QuerySet technique, see this snippet, which solves a similar problem but for the case of Generic Foreign Keys, not reverse relations. It wouldn't be too hard to combine the guts of your qbind() function with the structure shown there to make a really nice solution to your problem.

    0 讨论(0)
  • 2020-12-24 14:20

    I think what you are trying to do is the term "eager loading" of child data - meaning you are loading the child list (choice_set) for each Poll, but all in the first query to the DB, so that you don't have to make a bunch of queries later on.

    If this is correct, then what you are looking for is 'select_related' - see https://docs.djangoproject.com/en/dev/ref/models/querysets/#select-related

    I noticed you tried 'select_related' but it didn't work. Can you try doing the 'select_related' and then the filter. That might fix it.


    UPDATE: This doesn't work, see comments below.

    0 讨论(0)
  • 2020-12-24 14:25

    I think what you're saying is, "I want all Choices for a set of Polls." If so, try this:

    polls = Poll.objects.filter(category='foo')
    choices = Choice.objects.filter(poll__in=polls)
    
    0 讨论(0)
  • 2020-12-24 14:30

    Time has passed and this functionality is now available in Django 1.4 with the introduction of the prefetch_related() QuerySet function. This function effectively does what is performed by the suggested qbind function. ie. Two queries are performed and the join occurs in Python land, but now this is handled by the ORM.

    The original query request would now become:

    polls = Poll.objects.filter(category = 'foo').prefetch_related('choice_set')
    

    As is shown in the following code sample, the polls QuerySet can be used to obtain all Choice objects per Poll without requiring any further database hits:

    for poll in polls:
        for choice in poll.choice_set:
            print choice
    
    0 讨论(0)
提交回复
热议问题