Django为每个对象不成功地查询数据库

时间:2013-10-08 20:08:02

标签: django django-models django-templates django-views

我的models.py:

来自django.db导入模型     来自django.contrib.auth.models导入用户

class SkillCategory(models.Model):
    title = models.CharField(max_length=255)

    def __unicode__(self):
        return self.title

    class Meta:
        verbose_name_plural = "Skill Categories"


class Skill(models.Model):
    title = models.CharField(max_length=255)
    category = models.ForeignKey(
        SkillCategory, default=None, null=True, blank=True
    )

    def __unicode__(self):
        return self.title


class UserProfile(models.Model):
    user = models.OneToOneField(User)
    skill = models.ManyToManyField(Skill)
    avatar = models.URLField(
        max_length=400, default=None, null=True, blank=True
    )

    def __unicode__(self):
        return self.user.username

我的views.py:

def ShowUserProfile(request, username=None, template_name='user_profile.html'):
    if not username:
         username = request.user.username

    profile = get_object_or_404(
        UserProfile.objects.select_related(), user__username=username
    )
    ...

在我的模板中,我这样迭代:

 ...
 {% if skill.category.title == 'Some Skill' %}
   {% for skill in profile.skill.all %}
     <li>{{ skill }}</li>
   {% endfor %}
 {% endif %}
 ...

但是如果我查看Django Debug Toolbar,我会看到每个Skill,Django正在查询数据库以获取Category。我在select_related对象上使用UserProfile但它不会影响查询的数量。肯定有一个更好的方法,Django可以一次性获得所有Skill和相关的SkillCategory引用?

非常感谢任何帮助。

修改

根据准确的反馈,正确的视图如下所示:

def ShowUserProfile(request, username=None, template_name='user_profile.html'):
    if not username:
         username = request.user.username
    profile = get_object_or_404(
        UserProfile.objects.prefetch_related(
            'skill__category'), user__username=username
    )

2 个答案:

答案 0 :(得分:2)

select_related无法处理ManyToMany关系。查看prefetch_related,它通过运行两个查询并在Python中连接结果来处理ManyToMany字段。

  

select_related通过创建SQL连接并在SELECT语句中包含相关对象的字段来工作。因此,select_related在同一数据库查询中获取相关对象。但是,为了避免加入“多”关系会产生更大的结果集,select_related仅限于单值关系 - 外键和一对一。

     另一方面,

prefetch_related对每个关系进行单独查找,并在Python中进行“加入”。这允许它预取多对多和多对一对象,除了select_related支持的外键和一对一关系之外,这些对象无法使用select_related完成。它还支持预取GenericRelation和GenericForeignKey。

答案 1 :(得分:1)

Django的select_related不适用于many-to-many关系。 查看prefetch_related