Django - 间接加入查询

时间:2012-02-20 15:09:16

标签: python django model

如何返回间接连接查询,该查询为我提供了问题模型中的所有问题。需要注意的是,对于每个问题,我都需要能够访问UserData模型。间接关系是问题 - >用户和用户< - UserData(如果可能,我不想更改模型结构)。

class Question(models.Model):
    description = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')
    image_url = models.CharField(max_length=200)
    user = models.ForeignKey(User)

class Answer(models.Model):
    question = models.ForeignKey(Question)
    text = models.CharField(max_length=16000)
    user = models.ForeignKey(User)

class UserData(models.Model):
    user = models.OneToOneField(User)
    access_token = models.CharField(max_length=32)
    profile_image_url = models.CharField(max_length=200)

编辑:我认为这种关系被认为是“反向关系”。

2 个答案:

答案 0 :(得分:2)

Question.objects.select_related('user__userdata').all()

将为每个问题同时获取User对象和UserData对象。不支持除{/ 1}}关系中的之外的反向关系(As seen here

答案 1 :(得分:1)

考虑select_related()

从3个查询到只有select_related()的2个查询,再到select_related()的1个查询给出更好的参数。

In [17]: [q.user.userdata.access_token for q in Question.objects.all()]
DEBUG (0.000) SELECT "testapp_question"."id", "testapp_question"."description", "testapp_question"."pub_date", "testapp_question"."image_url", "testapp_question"."user_id" FROM "testapp_question"; args=()
DEBUG (0.000) SELECT "auth_user"."id", "auth_user"."username", "auth_user"."first_name", "auth_user"."last_name", "auth_user"."email", "auth_user"."password", "auth_user"."is_staff", "auth_user"."is_active", "auth_user"."is_superuser", "auth_user"."last_login", "auth_user"."date_joined" FROM "auth_user" WHERE "auth_user"."id" = 1 ; args=(1,)
DEBUG (0.000) SELECT "testapp_userdata"."id", "testapp_userdata"."user_id", "testapp_userdata"."access_token", "testapp_userdata"."profile_image_url" FROM "testapp_userdata" WHERE "testapp_userdata"."user_id" = 1 ; args=(1,)
Out[17]: [u'1']

In [18]: [q.user.userdata.access_token for q in Question.objects.all().select_related()]
DEBUG (0.000) SELECT "testapp_question"."id", "testapp_question"."description", "testapp_question"."pub_date", "testapp_question"."image_url", "testapp_question"."user_id", "auth_user"."id", "auth_user"."username", "auth_user"."first_name", "auth_user"."last_name", "auth_user"."email", "auth_user"."password", "auth_user"."is_staff", "auth_user"."is_active", "auth_user"."is_superuser", "auth_user"."last_login", "auth_user"."date_joined" FROM "testapp_question" INNER JOIN "auth_user" ON ("testapp_question"."user_id" = "auth_user"."id"); args=()
DEBUG (0.000) SELECT "testapp_userdata"."id", "testapp_userdata"."user_id", "testapp_userdata"."access_token", "testapp_userdata"."profile_image_url" FROM "testapp_userdata" WHERE "testapp_userdata"."user_id" = 1 ; args=(1,)
Out[18]: [u'1']

In [19]: [q.user.userdata.access_token for q in Question.objects.all().select_related('user__userdata')]
DEBUG (0.000) SELECT "testapp_question"."id", "testapp_question"."description", "testapp_question"."pub_date", "testapp_question"."image_url", "testapp_question"."user_id", "auth_user"."id", "auth_user"."username", "auth_user"."first_name", "auth_user"."last_name", "auth_user"."email", "auth_user"."password", "auth_user"."is_staff", "auth_user"."is_active", "auth_user"."is_superuser", "auth_user"."last_login", "auth_user"."date_joined", "testapp_userdata"."id", "testapp_userdata"."user_id", "testapp_userdata"."access_token", "testapp_userdata"."profile_image_url" FROM "testapp_question" INNER JOIN "auth_user" ON ("testapp_question"."user_id" = "auth_user"."id") LEFT OUTER JOIN "testapp_userdata" ON ("auth_user"."id" = "testapp_userdata"."user_id"); args=()
Out[19]: [u'1']

请注意,您无需与('user', 'user__userdata')调用所选的相关内容:您可以看到上一个查询仅使用“user__userdata”从3个表中提取数据:

SELECT 
    "testapp_question"."id", "testapp_question"."description" [...]
    "auth_user"."id", "auth_user"."username" [...]
    "testapp_userdata"."id", "testapp_userdata"."user_id"  [...]
FROM
    "testapp_question" INNER JOIN 
    "auth_user" ON ("testapp_question"."user_id" = "auth_user"."id") LEFT OUTER JOIN 
    "testapp_userdata" ON ("auth_user"."id" = "testapp_userdata"."user_id")