我有以下数据库表:
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
当试图从故事对象工作时,我没有任何外键到评论表(只有评论表中的外键上的相关名称)所以我似乎没有获得相同的访问权。
答案 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