我的第三个“ Django中的抓取对象”文章

时间:2018-08-07 18:42:32

标签: python django

很显然,我正在为Django中的各种抓取对象而苦苦挣扎。这是另一个。

这是针对我一直在使用的同一库应用程序(以防您遇到其他问题)。

在主页上,我显示活动用户的名称和信息(这很好)。然后,我希望显示活动用户撰写的所有评论。我基本上也可以做到这一点,除了它只显示评论而不参考他们应该描述的书。

所以...我需要能够通过其Review对象来获取Book对象。换句话说,每次我显示评论时,我都希望能够获取与之相关的书(书名和作者)。请记住,我无法由用户(使用created_by)来抓取书,因为用户可以为未添加到数据库中的书撰写评论。我希望这是有道理的,但我相信您可以看到我正在为此类问题而苦苦挣扎。

在models.py中,我像这样设置表(请注意,User表位于其他应用程序中):

class Book(models.Model):
    title = models.CharField(max_length=100)

    author = models.ForeignKey("Author", on_delete=models.CASCADE, related_name="books")

    created_by = models.ForeignKey(User, on_delete=models.CASCADE, related_name="books_added")
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    objects = BookManager()

class Author(models.Model):
    first_name = models.CharField(max_length=100)
    last_name = models.CharField(max_length=100)

    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    objects = AuthorManager()

class Review(models.Model):
    rating = models.IntegerField()
    comments = models.TextField()

    book = models.ForeignKey("Book", on_delete=models.CASCADE, related_name="reviews")

    created_by = models.ForeignKey(User, on_delete=models.CASCADE, related_name="reviews_added")
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    objects = ReviewManager()

然后在views.py中,我试图通过引用Review对象来定义变量“ book”(因为book是review中的一个字段)。像这样:

def books_home(request):
    if request.method == "GET":
        first_name = User.objects.get(id=request.session['uid']).first_name
        last_name = User.objects.get(id=request.session['uid']).last_name
        email = User.objects.get(id=request.session['uid']).email
        user_id = User.objects.get(id=request.session['uid']).id
        reviews = Review.objects.filter(created_by=user_id)
        book = Review.objects.filter(created_by=user_id).book
        context = {
            'first_name' : first_name, 
            'email' : email,
            'last_name' : last_name,
            'reviews' : reviews,
            'book' : book
            }
        return render(request, 'html_files/home.html', context=context)

请记住,在上下文中,book = Review.objects.filter(created_by=user_id).book' and“ book”:book`之外的所有内容基本上都可以使用。

还请记住,我是Django和一般编程人员的新手。我敢肯定有更优雅的方法可以做到这一点,但是我坚持使用我所理解的方法,因此在回答时,请尽量保持与当前代码尽可能接近。 “使它工作,然后使其更好地工作。”

我相信我知道该在模板中做什么以显示上下文指示,所以这不是问题。如果有帮助的话,代码在GitHub上。

谢谢。

1 个答案:

答案 0 :(得分:0)

评论过滤器将返回一个评论查询集,该查询集可以是Book的一个或多个实例,因此您无法访问查询集上的.book

您要从哪几本评论归还一本书?

相反,在模板中,使用{{ review.book }}来访问每个评论的书。为防止每次访问书籍时都触及数据库,请使用select_related()

通常,数据库访问不是最佳的,您要多次访问数据库(每次.get())。而是访问一次,并将其存储在变量中。

此外,当您对用户进行过滤时,使用用户实例本身进行过滤,Django将处理簿记:

        user = User.objects.get(id=request.session['uid'])
        reviews = Review.objects.filter(created_by=user)

但是,您已经为反向外键关系定义了related_name,为什么不使用它呢?

修改为:

def books_home(request):
    if request.method == "GET":
        user = User.objects.get(id=request.session['uid'])
        reviews = user.reviews_added.select_related('book')
        context = {
            'first_name' : user.first_name, 
            'email' : user.email,
            'last_name' : user.last_name,
            'reviews' : reviews,
            }
        return render(request, 'html_files/home.html', context=context)

每个评论都将具有相关的书籍实例,因此在模板中:

{% for review in reviews %}
   {{ review.book.title }}
{% endfor %}

有关信息,请参见Related objects reference