In the age of no Internet, we use diaries to record our daily experience. When I was young, I had a diary with a lock. I was afraid that others would see what was written in it. The key was hidden in it.
Now the times have changed, the online version of the diary: blog, but the more people want to see the better.
After others have read your deep and good writing, they will inevitably want to talk about it. This is the function of "comment".
There are few new knowledge points in the comment module to be written in this chapter, but the comprehensive application of the content of the previous chapter.
It is strongly recommended that readers try to compile this part of the content and test their knowledge level.
Dead work
Comments are a relatively independent function, so create a new app for comments:
(env) E:\django_project\my_blog > ppython manage.py startapp comment
Some people find it strange that there is no comment without blog posts. Why do you say that comment is an "independent" function?
That's because not only blog posts can be commented on, but photos, videos and even the website itself can be "commented on". It can be encapsulated as a separate module to facilitate future expansion.
After confirming that the app was created successfully, remember to register in settings.py:
my_blog/settings.py ... INSTALLED_APPS = [ ... 'comment', ] ... TIME_ZONE = 'Asia/Shanghai' ...
Because we want to show the time of comment, modify the time zone to set TIME_ZONE as the time zone of Shanghai.
Then register the root route in my_blog/urls.py:
my_blog/urls.py ... urlpatterns = [ ... # comment path('comment/', include('comment.urls', namespace='comment')), ] ...
Writing Core Functions
Commentary Model
First, write a review model:
comment/models.py from django.db import models from django.contrib.auth.models import User from article.models import ArticlePost # Comments on Bowen class Comment(models.Model): article = models.ForeignKey( ArticlePost, on_delete=models.CASCADE, related_name='comments' ) user = models.ForeignKey( User, on_delete=models.CASCADE, related_name='comments' ) body = models.TextField() created = models.DateTimeField(auto_now_add=True) class Meta: ordering = ('created',) def __str__(self): return self.body[:20]
There are two foreign keys in the model:
- Article is a commented article
- user is the publisher of comments
Don't forget that every time you add or modify a Model, you have to migrate data.
Tip: You must register an app in set.py before the data migration in this app can take effect.
A form of comments
Forms are used when users submit comments, so create a new form class:
comment/forms.py from django import forms from .models import Comment class CommentForm(forms.ModelForm): class Meta: model = Comment fields = ['body']
Because the two foreign keys in the model will be filled in automatically through the view logic, it is enough to submit the body here.
Commentary url
Create a new routing file in comment app:
comment/urls.py from django.urls import path from . import views app_name = 'comment' urlpatterns = [ # Comment path('post-comment/<int:article_id>/', views.post_comment, name='post_comment'), ]
Comments must be associated with a specific blog post, so the id of the blog post is passed in to facilitate subsequent calls.
The post_comment() view has not been written yet, so take a name first.
View of comments
The view functions of the comments are as follows:
comment/views.py from django.shortcuts import render, get_object_or_404, redirect from django.contrib.auth.decorators import login_required from django.http import HttpResponse from article.models import ArticlePost from .forms import CommentForm # Article review @login_required(login_url='/userprofile/login/') def post_comment(request, article_id): article = get_object_or_404(ArticlePost, id=article_id) # Processing POST requests if request.method == 'POST': comment_form = CommentForm(request.POST) if comment_form.is_valid(): new_comment = comment_form.save(commit=False) new_comment.article = article new_comment.user = request.user new_comment.save() return redirect(article) else: return HttpResponse("The form is incorrect. Please fill it in again.") # Handling error requests else: return HttpResponse("Comments are accepted only POST Request.")
There are two new faces in the code.
get_object_or_404(): It basically has the same function as Model.objects.get(). The difference is that in a production environment, if a user requests a non-existent object, Model.objects.get() returns Error 500 (server internal error), while get_object_or_404 () returns Error 404. By contrast, returning 404 errors is more accurate.
redirect(): Return to an appropriate url: that is, after the user sends a comment, redirect to the article details page. When its parameter is a Model object, the get_absolute_url() method of the Model object is automatically called. So I'll modify the article model right away.
In fact, redirect() has been used in previous chapters. The functions are the same and the implementation is slightly different.
Model of article
As mentioned above, add the get_absolute_url() method to the article model:
article/models.py ... # Remember to import from django.urls import reverse class ArticlePost(models.Model): ... # Get the article address def get_absolute_url(self): return reverse('article:article_detail', args=[self.id])
The reverse() method is used to return the url of the article details page, and the route redirection is realized.
Detailed View of Articles
The comment module needs to be displayed on the article details page, so the context of the comment module must also be passed to the template.
So modify article_detail() in article/views.py:
article/views.py ... from comment.models import Comment def article_detail(request, id): # Existing code article = ArticlePost.objects.get(id=id) # Remove article reviews comments = Comment.objects.filter(article=id) ... # Add comments context context = { 'article': article, 'toc': md.toc, 'comments': comments } ...
filter() can take out more than one satisfying object, but get() can only take out one, pay attention to distinguishing between use
Article Details Template
At the last step, stick to it. All the back-end functions have been written, so it's almost impossible to show them all on the page.
Modify the article details page:
templates/article/detail.html ... <div class="col-9"> ... <!-- Existing code, text of article --> <div class="col-12"> ... </div> <!-- Comment --> <hr> {% if user.is_authenticated %} <div> <form action="{% url 'comment:post_comment' article.id %}" method="POST" > {% csrf_token %} <div class="form-group"> <label for="body"> <strong> //I would also like to make a statement: </strong> </label> <textarea type="text" class="form-control" id="body" name="body" rows="2"></textarea> </div> <!-- Submit button --> <button type="submit" class="btn btn-primary ">Send out</button> </form> </div> <br> {% else %} <br> <h5 class="row justify-content-center"> //Please <a href="{% URL'userprofile: login'%}"> login </a> and reply </h5> <br> {% endif %} <!-- Display comments --> <h4>Share{{ comments.count }}Article comment</h4> <div> {% for comment in comments %} <hr> <p> <strong style="color: pink"> {{ comment.user }} </strong> to <span style="color: green"> {{ comment.created|date:"Y-m-d H:i:s" }} </span> He said: </p> <pre style="font-family: inherit; font-size: 1em;"> {{ comment.body }}</pre> {% endfor %} </div> </div> <!-- Catalog --> <div class="col-3 mt-4"> ... </div> ...
- action in the form component specifies which url the data is submitted to
- Displaying comments.count in comments is a built-in method in template objects that counts the elements contained
- | date:"Y-m-d H:i:s": Pipeline characters are familiar to you and are used to "paste" certain attributes or functions to objects. Here is how to format the date. Please try to modify some of the characters to try the effect.
-
The key role of <pre> in defining pre-formatted text in our project is to preserve spaces and newline characters. This tag changes the font, size, etc. of the text, so it redefines the relevant content with the style attribute. Try to replace < pre > with div, and enter multiple lines of text to try the effect.
Previously, it was said that it was better not to copy and paste code, otherwise you would not notice some "pits". For example, text in the <pre> tag must not be indented.
test
It's time for exciting testing.
Log in to your account and go to the details page of an article. You find that you can leave a message.
If logged out, the prompt is displayed:
Click login to go back to the login page.
The publishing and displaying functions of the comment module are completed.
Sweeping work
Data deletion, change function has been done many times, here do not intend to repeat.
Comments can also support Markdown grammar or insert Emoji emoticons.
Readers can realize their own functions of interest.
Some websites simply do not have the function of deleting and updating comments. Because for small stations, the number of times these functions are used is too small, it is better to focus on more valuable places. such as My blog No.
Other websites provide soft deletion, deletion is only not shown, in fact, the data still exist.
What you should do depends on your preferences.
summary
This chapter realizes the function of commenting and displaying comments. As I said at the beginning, the content of this chapter is a synthesis of the previous chapters.
If you don't read the code in this chapter, but complete the comment function on your own, congratulations on winning the title of "Django Initial Programmer"! Don't underestimate the word "entry". Everything is difficult at the beginning.
- If you have any questions, please Dussey's personal website Leave a message, I will reply as soon as possible.
- Or Email to me: dusaiphoto@foxmail.com
- Project complete code: Django_blog_tutorial
Please indicate the source for reprinting.