开发者

Django: backward ForeignKey queries

My models:

class NewsItem(models.Model):
    title    = ...
    content  = ...

class Image(models.Model):
    newsItem = models.ForeignKey(NewsItem)
    url      = ....

I want to display 50 NewsItems with their images ( 2-5 images for each NewsItem ). Can i do it with only one or two queries? Can i query "backwars" related information?

I found some information about it, but didn't unders开发者_开发问答tand how to show _related items in template (in my case "backward" _related items are Images). The link is http://blog.roseman.org.uk/2010/01/11/django-patterns-part-2-efficient-reverse-lookups/

Article was posted on Jan 2010 - may be there is more efficient way?


Here's an example that might be easier to follow (naming).

Thank you to Daniel Roseman for setdefault! I learn something on stack every day. I've been using ugly try/except blocks to solve this same issue.

View:

newsitems = NewsItem.objects.all()[0:50]
related_images = Image.objects.filter(newsitem__in=newsitems)
newsitem_images_map = {}

for image in related_images:
    # start appending to a list keyed by the newsitem ID for all related images
    newsitem_images_map.setdefault(image.newsitem_id, []).append(image)

for newsitem in newsitems:
    # set an attribute on the newsitem that is the list created above
    newsitem.images = newsitem_images_map.get(newsitem.id)

    # this attribute is accessible from the template.

Template:

{% for newsitem in newsitems %}
    {{ newsitem.title }}
    {% for image in newsitem.images %}
        {{ image }}
    {% endfor %}
{% endfor %}


qs = NewsItem.objects.all()
obj_dict = dict([(obj.id, obj) for obj in qs])

objects = Image.objects.filter(newsitem__in=qs)

relation_dict = {}

for obj in objects:
    relation_dict.setdefault(obj.newsitem_id, []).append(obj)
for id, related_items in relation_dict.items():
    obj_dict[id]._related_images = related_items

...
{% for newsitem in obj_dict %}
    {% for image in newsitem._related_images %}

You will get your related data in 2 queries

UPDATE: In Django 1.4 available new method prefetch_related

Btw, prefetch_related doesn't work with deprecated generic view direct_to_template.

newitems = NewItem.objects.prefetch_related('images')


You scenario is NOT a reverse relation:

news_item.images     # forward relation

image.newsitem_set  # reverse relation

So, all you need to do is:

news_items = NewsItem.objects.select_related().all()[:50]

and pass it to your template, image objects should already be cached.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜