【问题标题】:How to do a multi-table join in Django with aliases如何使用别名在 Django 中进行多表连接
【发布时间】:2019-05-31 17:19:50
【问题描述】:

好的,我在理解 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]

这给了我一个“问题”对象没有属性“名称”错误。

注意:这是 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]

感谢两位回答者,他们很有启发性。

【问题讨论】:

    标签: python django postgresql orm


    【解决方案1】:

    这不起作用的原因是因为您的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 QuerySetQuestions 将有两个额外字段 answer_texts_name 以及相关 FieldnameAnswer( s),以及s_nameSurvey 的名称。

    【讨论】:

    • 这也有效。我认为这比第一个答案更好,因为我怀疑这也将解决我的别名问题。当我完成这项工作时,我将更新/标记为正确。谢谢。
    • 是的,这就是有效的。我将在原始问题中发布我的最终查询以供参考。
    【解决方案2】:

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

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

    我想,这就是你需要的。

    【讨论】:

    • 你已经回答了我的部分问题,但我怀疑不是故意的。我的问题不在于是使用 select_related 还是 prefetch_related。而是您使用嵌套的点表示法来引用该字段,即。 x.survey.name。这使我的初始测试查询工作。现在我必须让其余的表加入并处理别名。谢谢
    猜你喜欢
    • 1970-01-01
    • 2014-06-19
    • 2019-07-29
    • 1970-01-01
    • 2018-07-17
    • 1970-01-01
    • 1970-01-01
    • 2018-06-13
    • 2018-06-16
    相关资源
    最近更新 更多