Python Django关系在没有_集的情况下向后工作,但在

Python Django关系在没有_集的情况下向后工作,但在,python,django,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) l

我有以下数据库表:

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说注释集没有定义。在文档中,它指出,如果您试图访问另一个数据库表中未定义外来项的字段,则可以使用_set方法,其中前面的单词是类的名称

在尝试了不同的方法后,我发现这是可行的:

c = Comment.objects.all()
for com in c:
    com.story.title
c = Comment.objects.all()
for com in c:
    print com.story.title
既然外键是在Comment中定义的,我看不出它是如何工作的,但是它确实工作了,为什么设置不工作呢。因为我在定义外键的模型中处理一个对象,我需要转到故事,然后我需要根据文档使用_set…当处理故事对象时,我可以在定义相关的_name属性时引用注释模型,所以我也不需要在那里设置。。你为什么不在这里工作

更新: 现在,当我使用story对象并通过以下方式引用comment类时,关系可以反向工作:

s = Story.objects.all()
for st in s:
    print st.comment_set.all()
我使用的是st.story_集而不是st.comment_集,但我仍然觉得这样做很奇怪:

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

当尝试从故事对象开始工作时,我没有任何注释表的外键(只有注释表中外键上的相关名称),因此我似乎没有获得相同的访问权限。

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

这就是为什么
st.comment\u set
有效的原因,因为它“向后看”指向它的注释,而注释只是直接指向它相关的故事(即
com.story

如果您有兴趣了解其工作原理,请参见此处:

这就是Django的ORM如此酷的部分原因…

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
您的数据库将如下所示(除非您另有指定):

向前

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

向后

Comment
有一个外键指向
Story
,因此
Story
的实例可以访问名为
Comment\u set
的管理器,该管理器可以跟踪从
Story
Comment
的关系

>>> s = Story.objects.get(title='first post')
>>> s.comment_set.comment_text  # accesses Comment model from Story instance
'hello, world'
或者,如果您想重复您在注释中提到的所有
注释集
s,请尝试以下操作:

>>> 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

谢谢你这么详细的解释。但是,在指定以下内容时,我无法使您的上一个代码正常工作:>>>s=Story.objects.all()>>>for Story in s:。。。打印story.comment\u set.comment\u文本。。。回溯(最近一次调用):文件“”,第2行,在AttributeError:“RelatedManager”对象中没有属性“comment\u text”…啊,不知道如何在注释中获得良好的格式:/@user2959896我很乐意提供帮助。我更新了上面的答案。有关如何迭代查询集的示例,请参见答案的末尾。实例s有一个
注释集
,但该实例中的查询项
故事
没有
注释集
。(另外,您可以使用键盘上的“back tick”设置注释中的代码格式。)@user2959896好的,我的上一次编辑将执行您在收到上述错误消息时尝试执行的操作。您必须遍历顶级查询集和查询集的子级别。我在上面举了一个有效的例子。祝你好运!