How to make add replies to comments in Django?

2024/11/18 8:44:29

I'm making my own blog with Django and I already made a Comments system.. I want to add the replies for each comment (like a normal comment's box) and I don't know what to do this is my current models.py comments:

class Comment(models.Model):post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='comments')author = models.ForeignKey(User, on_delete=models.CASCADE)text = models.TextField()created_date = models.DateField(auto_now_add=True)parent = models.ForeignKey('self', null=True, related_name='replies')def __str__(self):return self.text

and this is the .html where I use the comments

  {% for comment in post.comments.all %}<ul>{{ comment.text }}{% for reply in comment.replies.all %}<li>{{ reply.text }}</li>{% endfor %}<ul>{% endfor %}

and apparently It is working but when I try to make a comment in the admin site of Django it forces me to put a "Parent" to each comment (and this is not obligatory beacuse not every comment is a reply) I also don't know how to add the reply "button" in the HTML file. Please help tell me what changes can I do to make a simple comment box with replies . Thanks a lot

Answer

I had the same problem and resolved it as follows:

1. For admin site as mentioned above just set blank=True for parent field. My comment model:

class Comment(models.Model):post = models.ForeignKey(Post, related_name='comments')name = models.CharField(max_length=80)email = models.EmailField(max_length=200, blank=True)body = models.TextField()created = models.DateTimeField(auto_now_add=True)updated = models.DateTimeField(auto_now=True)# manually deactivate inappropriate comments from admin siteactive = models.BooleanField(default=True)parent = models.ForeignKey('self', null=True, blank=True, related_name='replies')class Meta:# sort comments in chronological order by defaultordering = ('created',)def __str__(self):return 'Comment by {}'.format(self.name)
  • remember to run makemigrations and migrate

2.Let's start with views. I'm using the post_detail view to display the post and its comments. We add a QuerySet to retrieve all parent active comments for this post. After this, we validate the submitted data using the form's is_valid(). If the form is valid we check if submitted data comes from hidden input in replay button form. Next if parent_id exits we create parent object(parent_obj) for replay comment and replay_comment object, then we assign parent_obj to replay_comment. If parent_obj is equal to None we just proceed with normal comment by creating new_comment object and saving it to the database.

def post_detail(request, post):# get post objectpost = get_object_or_404(Post, slug=post)# list of active parent commentscomments = post.comments.filter(active=True, parent__isnull=True)if request.method == 'POST':# comment has been addedcomment_form = CommentForm(data=request.POST)if comment_form.is_valid():parent_obj = None# get parent comment id from hidden inputtry:# id integer e.g. 15parent_id = int(request.POST.get('parent_id'))except:parent_id = None# if parent_id has been submitted get parent_obj idif parent_id:parent_obj = Comment.objects.get(id=parent_id)# if parent object existif parent_obj:# create replay comment objectreplay_comment = comment_form.save(commit=False)# assign parent_obj to replay commentreplay_comment.parent = parent_obj# normal comment# create comment object but do not save to databasenew_comment = comment_form.save(commit=False)# assign ship to the commentnew_comment.post = post# savenew_comment.save()return HttpResponseRedirect(post.get_absolute_url())else:comment_form = CommentForm()return render(request,'core/detail.html',{'post': post,'comments': comments,'comment_form': comment_form})

Simple comment form:

class CommentForm(forms.ModelForm):class Meta:model = Commentfields = ('name', 'email', 'body')

* More about ModelForm

And lastly template. We need to create two forms. One form for comments and the second one for replays. Here you have simple template:

<!-- Comments Form --> 
<h2>Add a new comment</h2>
<form action="." method="post">{{ comment_form.as_p }}{% csrf_token %}<button type="submit">Add comment</button>
</form><!-- Comment with nested comments -->
{% for comment in comments %}<div class="comment" style="background-color: powderblue"><p class="info">{{ comment.name }} | {{ comment.created }}</p>{{ comment.body|linebreaks }}{% for replay in comment.replies.all %}<p class="info">{{ replay.name }} | {{ replay.created }}</p><li>{{ replay.body }}</li>{% endfor %}<h5>Replay</h5><form action="." method="post">{{ comment_form.as_p }}{% csrf_token %}<!-- Hidden input for parent comment.id --><input type="hidden" name="parent_id" value="{{ comment.id }}"><input class="btn btn-primary" type="submit" value="Replay"></form></div>
{% empty %}
<h4>There are no comments yet.</h4>
{% endfor %}

just add some nice css and maybe jquery to have fade in reply comments and that's all.

https://en.xdnf.cn/q/71080.html

Related Q&A

Which Regular Expression flavour is used in Python?

I want to know which RegEx-flavour is used for Python? Is it PCRE, Perl compatible or is it ICU or something else?

Python regex: Including whitespace inside character range

I have a regular expression that matches alphabets, numbers, _ and - (with a minimum and maximum length).^[a-zA-Z0-9_-]{3,100}$I want to include whitespace in that set of characters.According to the Py…

Python - how can I override the functionality of a class before its imported by a different module?

I have a class thats being imported in module_x for instantiation, but first I want to override one of the classs methods to include a specific feature dynamically (inside some middleware that runs bef…

Calling a stateful LSTM as a functional model?

I have a stateful LSTM defined as a Sequential model:model = Sequential() model.add(LSTM(..., stateful=True)) ...Later, I use it as a Functional model:input_1, input_2 = Input(...), Input(...) output_1…

How to cluster Gantt bars without overlap?

Using create_gantt I have overlapping start and end dates: import plotly.plotly as py import plotly.figure_factory as ff import plotlydf = [dict(Task="Milestone A", Start=2017-01-01, Finish=2…

Fail to install lxml using pip

This is the command I used to install lxml:sudo pip install lxmlAnd I got the following message in the Cleaning Up stage:Cleaning up... Command /usr/bin/python -c "import setuptools, tokenize;…

Python 3.x list comprehension VS tuple generator

Is there any reason for memory, speed or whatever, that I would want to use:tuple(i for i in range(5000))instead of:[i for i in range(5000)]If I didnt mind the immutability of tuples

Using Sphinx with a distutils-built C extension

I have written a Python module including a submodule written in C: the module itself is called foo and the C part is foo._bar. The structure looks like:src/ foo/__init__.py <- contains the public …

PyYAML error: Could not determine a constructor for the tag !vault

I am trying to read a YAML file that has the tag !vault in it. I get the error:could not determine a constructor for the tag !vaultUpon reading a couple of blogs, I understood that I need to specify so…

Accessing a XAMPP mysql via Python

Im attempting to use mysql after only having worked with sqlite in the past.Ive installed XAMPP on Linux (ubuntu) and have mysql up and running fine (seems like that with phpMyadmin at least). However,…