从数据库层次结构中的Django中的父表中获取数据

时间:2013-10-21 22:10:40

标签: python django

this回答之后,我尝试将我的SQL Story表拆分为父/子项 - 子项包含特定用户数据,父项更通用数据。现在我遇到了一个问题,背叛了我在Django中缺乏经验。我的用户页面试图显示用户编写的所有故事的列表。以前,当我的用户页面只从故事表中提取数据时,它运行正常。现在我需要从两个带有链接信息的表中提取数据,而我却无法理解如何做到这一点。

在尝试从父故事表中提取数据之前,这是我的user_page视图:

def user_page(request, username):
    user = get_object_or_404(User, username=username)
    userstories = user.userstory_set.order_by('-id')
    variables = RequestContext(request, {
    'username': username,
    'userstories': userstories,
    'show_tags': True
    })
    return render_to_response('user_page.html', variables)

这是我的models.py:

class story(models.Model):
    title = models.CharField(max_length=400)
    thetext = models.TextField()

class userstory(models.Model):
    main = models.ForeignKey(story)
    date = models.DateTimeField()
    user = models.ForeignKey(User)

我真的不知道从父表中查找适当的信息并将其分配给变量的方式开始。我需要做的是按照用户表的'main'键进入故事表,并将故事表指定为变量。但我只是看不出如何在定义中实现它。

编辑:我已经尝试过story = userstory.objects.get(user = user),但我得到'userstory匹配查询不存在。'

1 个答案:

答案 0 :(得分:1)

通过阅读您之前链接的问题,我发现了混乱所在。我的印象是Story可能有许多UserStory与之关联。请注意,我正在使用Capital作为类名,这是常见的Python实践。我已经做了这个假设,因为你的模型结构允许在你的UserStory模型中使用外键来实现这一点。您的模型结构应该,而不是:

class Story(models.Model):
    title = models.CharField(max_length=400)
    thetext = models.TextField()

class UserStory(models.Model):
    story = models.OneToOneField(Story) # renamed field to story as convention suggests
    date = models.DateTimeField()
    user = models.ForeignKey(User)

class ClassicStory(models.Model)
    story = models.OneToOneField(Story)
    date = models.DateTimeField()
    author = models.CharField(max_length=200)

请参阅OneToOne relationships here的使用。 OneToOne字段表示一对一关系,这意味着一个Story有一个,只有一个UserStory。这也意味着UserStory与一个Story完全相关。这是“父子关系”,父母只有一个孩子的额外约束。您之前使用ForeignKey意味着Story有多个与之关联的UserStories,这对您的用例是错误的。

现在您的查询(和属性访问者)的行为与您预期的一样。

# get all of the users UserStories:
user = request.user
stories = UserStory.objects.filter(user=user).select_related('story')

# print all of the stories:

for s in stories:
    print s.story.title
    print s.story.thetext

请注意select_related将创建一个SQL连接,因此每次打印故事文本时都不会执行另一个查询。阅读本文,这非常非常重要!

您之前的问题提到您有另一张桌子,ClassicStories。它也应该有一个OneToOneField,就像UserStories一样。以这种方式使用OneToOne字段使得迭代Story模型非常困难,因为它可能是“ClassicStory”,但它可能是“UserStory”而不是:

# iterate over ALL stories

allstories = Story.objects.all()
for s in allstories:
    print s.title
    print s.thetext
    print s.userstory     # this might error!
    print s.classicstory  # this might error!

看到问题?你不知道它是什么样的故事。在访问子表中的字段之前,您需要检查它的类型。有些项目可以帮助管理这种类型的继承,例如django-model-utils InheritanceManager,但这有点推荐。如果您永远不需要遍历Story模型并访问它的子表,您不必担心。只要你只从ClassicStories或UserStories访问Story,你就可以了。