如何在Django中使用别名进行多表联接

时间:2019-05-31 17:19:50

标签: python django postgresql orm

好的,我在理解Django的加入和别名方面有些麻烦。我在模型中定义了四个表:(我删除了不相关的列)

class Field(models.Model):
    name = models.CharField(max_length=200, default='')

class Survey(models.Model):
    name = models.CharField(max_length=200, default='')

class Question(models.Model):
    text = models.CharField(max_length=200, default='')
    survey = models.ForeignKey(Survey)

class Answer(models.Model):
    question = models.ForeignKey(Question)
    field = models.ForeignKey(Field)

现在,我可以编写一个非常简单易懂的sql查询,以获取所需的确切信息。看起来像这样:

SELECT s.id, s.name, 
  q.id as q_id, q.text, 
  f.id as f_id, f.name as answer  
FROM "App_survey" s 
JOIN "App_question" q 
  ON q.survey_id = s.id
JOIN "App_answer" a 
  ON a.question_id = q.id 
JOIN "App_field" f 
  ON a.field_id = f.id;

但是我无法终生想出如何使用orm做到这一点。我什至无法连接两个表并从两个表中选择数据,更不用说处理别名了。据我所知:

questions = Question.objects.prefetch_related('survey')
questions_dict = [{'form':x.name, 'id':x.id, 'question':x.text} for x in questions]

这给了我一个'Question'对象,没有属性'name'错误。

注意:这是postgres和python,两者都是我的新手。

更新:这是我使用的最终代码,可以使用:

answers = Answer.objects.annotate(
    s_id=F('question__survey__id'),
    s_name=F('question__survey__name'),
    q_id=F('question__id'),
    text=F('question__text'),
    f_id=F('field__id'),
    answer=F('field__name')
)

surveys_dict = [{
    'id': x.s_id,
    'name':x.s_name,
    'q_id':x.q_id,
    'text':x.text,
    'f_id':x.f_id,
    'answer':x.answer
} for x in answers]

感谢两位答辩人,他们很有启发性。

2 个答案:

答案 0 :(得分:2)

当您具有select_related(*fields)关系时(执行ManyToOne),应使用SQL JOINS

questions = Question.objects.select_related('survey')
questions_dict = [{'form':x.survey.name, 'id':x.id, 'question':x.text} for x in questions]

我认为,这就是您所需要的。

答案 1 :(得分:2)

之所以不起作用,是因为您的Question没有name属性。 .prefetch_related只会自动填充相关模型。

您可以做的是注释 Question对象,例如:

from django.db.models import F

Question.objects.annotate(
    answer_text=F('answer__field__name'),
    s_name=F('survey__name')
)

现在 this Question中的QuerySet s将有两个额外的字段answer_texts_name,其中{相关name中的Field,以及Answer的名称s_name