Search code examples
djangofilteringdetailview

Passing objects to Detail View with filter (Django)


I am trying to pass query of comments (Comment model) to a DetailView of Post model using filter to get in DetailView only comments, related to particlural post.

Post model:

class Post(models.Model):
    title = models.CharField(max_length=300)
    content = models.TextField()
    date_posted = models.DateTimeField(default=timezone.now)
    author = models.ForeignKey(User, on_delete=models.CASCADE)

Comment model:

class Comment(models.Model):
    content = models.CharField(max_length=500, help_text='Не более 500 знаков')
    date_posted = models.DateTimeField(default=timezone.now)
    author = models.ForeignKey(on_delete=models.CASCADE)
    post_id = models.ForeignKey(on_delete=models.CASCADE)

Detail veiw:

class PostDetailView(DetailView):
    context_object_name = 'post'
    model = Post

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['comments'] = Comment.objects.filter(post_id = self.model.id)
        return context

And it returns TypeError:

int() argument must be a string, a bytes-like object or a number, not 'DeferredAttribute'

Could you please help with recommendation regarding how correctly use a filter to get in DetailView only comments, related to this Post? Thanks!


Solution

  • Well here your self.model will return Post (a reference to the model class), not the post object.

    You can access the object with self.object, as is specified in the documentation:

    While this view is executing, self.object will contain the object that the view is operating upon.

    class PostDetailView(DetailView):
        context_object_name = 'post'
        model = Post
    
        def get_context_data(self, **kwargs):
            context = super().get_context_data(**kwargs)
            context['comments'] = Comment.objects.filter(post_id=self.object)
            return context

    You can also make use of the reversed relationship, like:

    class PostDetailView(DetailView):
        context_object_name = 'post'
        model = Post
    
        def get_context_data(self, **kwargs):
            context = super().get_context_data(**kwargs)
            context['comments'] = self.object.comment_set.all()
            return context

    Note: note that a ForeignKey field typically does not end with an _id suffix, Django will automatically add an extra field named fieldname_id, so here you have two fields, post_id, and post_id_id, which is quite strange.