Django关系落后工作没有_set但没有

时间:2014-03-15 12:54:58

标签: python django

我有以下数据库表:

class Story(models.Model):
    user = models.ForeignKey(User)
    group = models.ForeignKey(Group, blank=True, null=True)
    date_added = models.DateTimeField(auto_now_add=True)
    date_modified = models.DateTimeField(auto_now=True)
    location = models.CharField(max_length=100)
    title = models.CharField(max_length=150)
    description = models.CharField(blank=True, null=True, max_length=2000)
    exp_text = models.TextField()
    category = models.ForeignKey(Category, blank=True, null=True)

    def __unicode__(self):
        return self.title

class Comment(models.Model):
    user = models.ForeignKey(User)
    date_added = models.DateTimeField(auto_now_add=True)
    date_modified = models.DateTimeField(auto_now=True)
    emailOnReply = models.NullBooleanField(blank=True, null=True)
    comment_text = models.TextField()
    story = models.ForeignKey(Story)

    def __unicode__(self):
        return self.comment_text

当我创建了一个评论对象并需要访问故事的标题时,我希望能够做到这一点:

c = Comment.objects.all()
for com in c:
    com.comment_set.title

但django说comment_set没有定义。在文档中,它说如果你想要在另一个数据库表中找到未定义外来字段的字段,你可以使用_set方法,其中前面的单词是类的名称。

在尝试不同的方式后,我发现这有效:

c = Comment.objects.all()
for com in c:
    com.story.title

由于外键是在Comment中定义的,所以我看不出它是如何工作的,但确实如此,以及为什么_set不起作用。由于我正在模拟定义外键的模型中的对象,我需要转到故事然后我需要根据文档使用_set ...当使用故事对象时,我可以将straigt引用到注释模型在定义related_name属性时所以我不需要在那里设置..为什么不在这里工作?

更新: 现在,当我使用一个故事对象并通过以下方式引用评论类时,我的关系正在向后发展:

s = Story.objects.all()
for st in s:
    print st.comment_set.all()

我使用的是st.story_set而不是st.comment_set,但我觉得这很有效:

c = Comment.objects.all()
for com in c:
    print com.story.title

当试图从故事对象工作时,我没有任何外键到评论表(只有评论表中的外键上的相关名称)所以我似乎没有获得相同的访问权。

2 个答案:

答案 0 :(得分:1)

实际上一切都按预期工作 Comment对象没有注释外键,它有一个“故事”外键。 评论是“指向”故事。因此 - 评论只有一个故事,但故事可能有一套“评论”。

这就是st.comment_set有效的原因 - 因为它向指向它的评论“向后看”,而评论只是直接指向与之相关的故事(即com.story)。

如果您有兴趣了解其工作原理 - 请参阅此处:
https://docs.djangoproject.com/en/dev/topics/db/queries/#how-are-the-backward-relationships-possible   这是让Django的ORM变得如此酷的一部分......

答案 1 :(得分:0)

Django中的以下关系有点隐含。以下是模型的简化版本:

class Story(models.Model):  # instances have access to Manager comment_set (backward)
    title = models.CharField(max_length=150)
    description = models.CharField(blank=True, null=True, max_length=2000)

class Comment(models.Model):  # has access to Story (forward)
    comment_text = models.TextField()
    story = models.ForeignKey(Story)  # stored in database as story_id, which refers to (implicit) id column in Story

您的数据库将如下所示(除非您另行指定):

Story (table)
    id  # automatically inserted by Django, unless you specify otherwise
    title
    description

Comment (table)
    id  # automatically inserted by Django, unless you specify otherwise
    comment_text
    story_id  # points back to id in Story table

转发

Comment的实例可以通过将Story的story_id列与Comment的id列匹配来访问Story(后者隐含在Django表中,而不是您的模型,但绝对在您的数据库表中,除非您另有指定)。

>>> c = Comment.objects.get(comment_text='hello, world')
>>> c.story.title  # c => story_id => row in Story where id == c.story_id
'first post'

<强> BACKWARD

Comment的ForeignKey指向Story,因此Story的实例可以访问名为comment_set的经理,该经理可以关注Story之间的关系Comment

>>> s = Story.objects.get(title='first post')
>>> s.comment_set.comment_text  # accesses Comment model from Story instance
'hello, world'

或者,如果您想要在评论中提及的所有comment_set进行迭代,请尝试以下方法:

>>> s = Story.objects.get(title='first post')  # returns a single, non-iterable query object
>>> for story in s.comment_set.all():  # each comment_set object can have more than one item
    print story.comment_text  # story does not have a comment_set attribute
'hello, world'  # my comment set here just happens to have one item

<强>更新

或者,根据您的评论,您希望将迭代更高一级,请尝试以下操作:

>>> s = Story.objects.all()
>>> for story in s:  # iterate over top level
>>>     for row in story.comment_set.all():
>>>         print row.comment_text  # again, row does not have a comment_set attribute
'hello, world'  # again, my comment set has only one item