目录
blog/models.py
class Comment(models.Model):
post = models.ForeignKey(Post,on_delete=models.CASCADE,related_name='comments')
name = models.CharField(max_length=80)
email = models.EmailField()
body = models.TextField()
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
active = models.BooleanField(default=True)
class Meta:
ordering = ('created',)
def __str__(self):
return 'Comment by {} on {}'.format(self.name, self.post)
📌related_name让我们可以使用属性命名相互关联的对象。通过Post.comments.all()检索文章所有评论。如果没有定义related_name属性,Django将使用小写的模型名,后面跟着_set (comment_set)
更新数据库
python .\\manage.py makemigrations blog?
python .\\manage.py migrate
from .models import Post,Comment
#...
@admin.register(Comment)
class CommentAdmin(admin.ModelAdmin):
? ? list_display = ('name','email','post','created','active')
? ? list_filter = ('active','created','updated')
? ? search_fields = ('name','email','body')
模型关联 API 用法示例 | Django 文档 | Django (djangoproject.com)
Django有两个基类来构建表单:Form和ModelForm。之前使用了第一种方法让您的用户通过电子邮件共享帖子。关于Form类更多内容,请看Django发送QQ邮件-CSDN博客
在本例中,使用 ?ModelForm,因为必须从Comment模型动态地构建表单。
blog/forms.py
from django import forms
from .models import Comment
#...
class CommentForm(forms.ModelForm):
? ? class Meta:
? ? ? ? model = Comment
? ? ? ? fields = ('name','email','body')
添加一个视图来处理表单并将新注释保存到数据库中 ?
编辑blog/views.py
from .forms import EmailPostForm,CommentForm
#...
def post_detail(request,year,month,day,post):
? ? post = get_object_or_404(Post,slug=post,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?status='published',
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?publish__year=year,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?publish__month=month,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?publish__day=day
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?)
? ? comments = post.comments.filter(active=True)
? ? new_comment = None
? ? if request.method == 'POST':
? ? ? ? comment_form = CommentForm(data=request.POST)
? ? ? ? if comment_form.is_valid():
? ? ? ? ? ? new_comment = comment_form.save(commit=False)
? ? ? ? ? ? new_comment.post = post
? ? ? ? ? ? new_comment.save()
? ? else:
? ? ? ? comment_form = CommentForm()
? ? template = "blog/post/detail.html"
? ? context = {
? ? ? ? "post":post,
? ? ? ? "comments":comments,
? ? ? ? "new_comment":new_comment,
? ? ? ? "comment_form":comment_form
? ? }
? ? return render(request,template,context)
将new_comment变量设置为None。将在创建新注释时使用该变量。如果视图被GET请求调用,用comment_form = CommentForm()构建一个表单实例。如果请求是POST,使用提交的数据实例化表单,并使用is_valid()方法验证它。如果表单无效,则呈现带有验证错误的模板。
如果表单有效,通过调用表单的save()方法创建一个新的Comment对象,并将其赋值给new_comment变量
📌save()方法可用于ModelForm,但不能用于Form实例,因为它们没有链接到任何模型。
显示评论总数
/blog/templates/post/detail.html
? ? {% with comments.count as total_comments %}
? ? ? ? <h2>
? ? ? ? ? ? {{ total_comments }} comment {{ total_comments|pluralize ?}}
? ? ? ? </h2>
? ? {% endwith%}
我们在模板中使用Django ORM,执行QuerySet comments.count()。
📌注意Django模板语言不使用圆括号来调用方法。
{% with %}标签允许我们为一个新变量赋值,该变量将在{% endwith %}标签之前可用。
📌{% with %}模板标签对于避免多次访问数据库或访问昂贵的方法非常有用。
显示评论列表
/blog/templates/post/detail.html
? ? {% for comment in comments %}
? ? ? ? <div class="comment">
? ? ? ? ? ? <p class="info">
? ? ? ? ? ? ? ? Comment {{ forloop.counter}} by {{ comment.name}}
? ? ? ? ? ? ? ? {{ comment.created }}
? ? ? ? ? ? </p>
? ? ? ? ? ? {{ comment.body|linebreaks ?}}
? ? ? ? </div>
? ? {% empty %}
? ? ? ? <p>There are no comments yet.</p>
? ? {% endfor %}
使用{% for %}模板标签来循环遍历评论。如果评论列表为空,我们将显示一条默认消息,通知用户这篇文章还没有评论。{{forloop.counter}}包含每次迭代的循环计数器。然后,显示发布评论的用户的姓名、日期和评论正文。
/blog/templates/post/detail.html
? ? {% if new_comment %}
? ? ? ? <h2>Your commet has been added.</h2>
? ? {% else %}
? ? ? ? <h2>Add a new comment</h2>
? ? ? ? <form action="." method="post">
? ? ? ? ? ? {{ comment_form.as_p}}
? ? ? ? ? ? {% csrf_token %}
? ? ? ? ? ? <p>
? ? ? ? ? ? ? ? <input type="submit" value="Add comment">
? ? ? ? ? ? </p>
? ? ? ? </form>
? ? {% endif %}
如果new_comment对象存在,我们将显示一条成功消息,因为注释已成功创建。否则,将为评论模型每个字段呈现带有段落<p>元素的表单,并包含POST请求所需的CSRF令牌。