创建Entry列表页,提供创建Entry文章入口
- 添加路由
app_demo/urls.py
path('entry', views.entry_list_view, name='entry_list'),
- 添加视图函数
app_demo/views.py
def entry_list_view(request):
entry_list = Entry.objects.all()
count = Entry.objects.count()
context = {"entry_list": entry_list, "count": count}
return render(request, 'app_demo/entry_list.html', context=context)
- 添加显示模板
app_demo/templates/app_demo/entry_list.html
{% extends 'app_demo/base.html' %}
{% load static %}
{% block css %}
<link rel="stylesheet" href="{% static 'app_demo/style.css' %}">
{% endblock %}
{% block content %}
<h1>Entry列表</h1>
<a type="button" class="btn btn-primary" href="/blog/entry/normal_add">添加Entry</a>
<table class="table table-bordered">
<thead>
<tr>
<th>#</th>
<th>所属博客</th>
<th>文章标题</th>
<th>文章内容</th>
<th>作者</th>
<th>评论数</th>
<th>点赞数</th>
<th>评级</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for entry in entry_list %}
<tr>
<th scope="row">{{ entry.id }}</th>
<td>{{ entry.blog }}</td>
<td>{{ entry.headline }}</td>
<td>{{entry.body_text}}</td>
<td>{% for author in entry.authors.all %}{{ author}}|{% endfor %}</td>
<td>{{entry.number_of_comments}}</td>
<td>{{entry.number_of_likes}}</td>
<td>{{entry.rating}}</td>
<td><a href="#">编辑</a> <a href="#">删除</a></td>
</tr>
{% empty %}
<tr>
<td scope="row" colspan="8" style="text-align: center">暂无Entry数据...</td>
</tr>
{% endfor %}
</tbody>
</table>
<div>博客总数:{{ count }}</div>
{% endblock %}
通过传统的方式处理表单-创建Entry文章
添加路由
app_demo/urls.py
path('entry/normal_add', views.entry_normal_add_view, name='entry_normal_add'),
视图函数处理表单数据
app_demo/views.py
def entry_normal_add_view(request):
if request.method == 'GET':
# GET 请求时,渲染空表单,关联表单部分默认值
blogs = Blog.objects.all()
authors = Author.objects.all()
return render(request, 'app_demo/entry_normal_add.html', {"blogs": blogs, "authors": authors})
# POST 请求时,获取表单POST过来的数据
blog_id = request.POST.get("blog")
headline = request.POST.get("headline")
body_text = request.POST.get("body_text")
authors = request.POST.getlist("authors")
# 根据用户所传的数据,存储到数据库
e = Entry.objects.create(
blog_id=blog_id,
headline=headline,
body_text=body_text
)
e.authors.set(authors)
return redirect(reverse("entry_list"))
前端通过form表单渲染和提交
app_demo/templates/app_demo/entry_normal_add.html
{% extends 'app_demo/base.html' %}
{% load static %}
{% block css %}
<link rel="stylesheet" href="{% static 'app_demo/style.css' %}">
{% endblock %}
{% block content %}
<h1>添加Entry</h1>
<form method="post" action="">
{% csrf_token %}
<div class="form-group">
<label for="blog">所属博客</label>
<select id="blog" class="form-control" name="blog">
{% for blog in blogs %}
<option value="{{ blog.id }}">{{ blog.name }}</option>
{% endfor %}
</select>
</div>
<div class="form-group">
<label for="headline">文章标题</label>
<input type="text" class="form-control" id="headline" placeholder="文章标题" name="headline">
</div>
<div class="form-group">
<label for="body_text">文章内容</label>
<textarea class="form-control" id="body_text" placeholder="文章内容" name="body_text"></textarea>
</div>
<div class="form-group">
<label for="authors">作者</label>
<select multiple id="authors" class="form-control" name="authors">
{% for author in authors %}
<option value="{{ author.id }}">{{ author.name }}</option>
{% endfor %}
</select>
</div>
<button type="submit" class="btn btn-default">提交</button>
</form>
{% endblock %}
GET请求,页面渲染如下:
存在的问题
- 用户提交的数据没有校验
- 页面上缺少对应错误信息提示
- 前端需要每个字段编写一个html控件
- 关联的字段,需要后端手动获取然后前端循环显示
通过Django组件-Form
组件处理表单-创建Entry文章
添加路由
app_demo/urls.py
path('entry/forms_add', views.entry_forms_add_view, name='entry_forms_add'),
定义Form表单
app_demo/forms.py
from django import forms
from django.core.exceptions import ValidationError
from app_demo.models import Blog, Author
class EntryForm(forms.Form):
# label 指定 form.label的值,默认为属性名,如blog
# queryset 指定关联model字段默认值
# widge 指定样式
blog = forms.ModelChoiceField(label="所属博客",
queryset=Blog.objects.all(),
widget=forms.Select(attrs={"class": "form-control"}))
# form 字段校验,required=False 非必填项;nitial='xxx',设置默认值
headline = forms.CharField(label="文章标题",
min_length=2,
error_messages={ # 定制错误信息
'min_length': '长度不能小于2'
}
)
body_text = forms.CharField(label="文章内容",
widget=forms.Textarea(attrs={"cols": "40", "rows": "5"}))
authors = forms.ModelMultipleChoiceField(label="作者", queryset=Author.objects.all())
# 批量添加样式:attrs={'class':'form_control'}应用bootstrap样式
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for name, field in self.fields.items():
if name != 'blog':
field.widget.attrs.update({"class": "form-control"})
# 通过钩子方法进行字段校验,clean_字段名
def clean_headline(self):
headline = self.cleaned_data.get("headline")
if len(str(headline).strip()) > 32:
# 验证不通过
raise ValidationError("长度不能大于32!")
# 验证通过,返回用户输入信息
return headline
视图函数处理表单数据
app_demo/views.py
def entry_forms_add_view(request):
if request.method == "GET":
# GET请求,渲染一个空的form
form = EntryForm()
return render(request, "app_demo/entry_forms_add.html", {"form": form})
# form绑定用户输入数据
form = EntryForm(request.POST)
# form内置的数据校验
if form.is_valid():
# 逐个取出传入的数据,将数据存储到数据库中。
e = Entry.objects.create(
blog=form.cleaned_data.get("blog"),
headline=form.cleaned_data.get("headline"),
body_text=form.cleaned_data.get("body_text")
)
e.authors.set(form.cleaned_data.get("authors"))
return redirect(reverse("entry_list"))
# 如果POST输入数据校验失败,form.errors 中包含其验证失败信息,重新渲染表单
return render(request, "app_demo/entry_forms_add.html", {"form": form})
form = EntryForm(request.POST)
: form表单数据绑定form.is_valid()
: form表单校验
前端通过form表单渲染和提交
app_demo/templates/app_demo/entry_forms_add.html
{% extends 'app_demo/base.html' %}
{% load static %}
{% block css %}
<link rel="stylesheet" href="{% static 'app_demo/style.css' %}">
{% endblock %}
{% block content %}
<h1>添加Entry</h1>
<form method="post" action="" novalidate>
{% csrf_token %}
{% for filed in form %}
<div class="form-group">
{{ filed.label }}
{{ filed }}
<span class="label label-danger">{{ filed.errors.0 }}</span>
</div>
{% endfor %}
<button type="submit" class="btn btn-default">提交</button>
</form>
{% endblock %}
form组件的主要功能总结
- 生成页面可用的HTML标签
- 对用户提交的数据进行校验
- 保留上次输入内容,包含验证失败信息
通过Django组件-ModelForm
组件处理表单-创建Entry文章
添加路由
app_demo/urls.py
path('entry/model_forms_add', views.entry_model_forms_add_view),
定义ModelForm表单
app_demo/forms.py
class EntryModelForm(forms.ModelForm):
class Meta:
model = Entry
# fields="__all__"
# exclude=["authors"]
fields = ["blog", "headline", "body_text", "authors"]
widgets = {
"body_text": forms.Textarea(attrs={"cols": "40", "rows": "5"})
}
# 批量添加样式:attrs={'class':'form_control'}应用bootstrap样式
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for name, field in self.fields.items():
field.widget.attrs.update({"class": "form-control"})
# 通过钩子方法进行字段校验,clean_字段名
def clean_headline(self):
headline = self.cleaned_data.get("headline")
if len(str(headline).strip()) > 32:
# 验证不通过
raise ValidationError("长度不能大于32!")
# 验证通过,返回用户输入信息
return headline
ModelForm
和 Form
的不同点:ModelForm
中直接绑定models,根据models中定义的字段生成form属性,无需一个个字段重新定义。
class Meta:
model = Entry
视图函数处理表单数据
app_demo/views.py
def entry_model_forms_add_view(request):
if request.method == "GET":
form = EntryModelForm()
return render(request, "app_demo/entry_forms_add.html", {"form": form})
form = EntryModelForm(request.POST)
if form.is_valid():
# 默认保存的是用户的输入值,如果想在用户输入以外增加一些逻辑处理值:form.instance.字段名=值
form.instance.rating=2
form.save()
return redirect(reverse("entry_list"))
return render(request, "app_demo/entry_forms_add.html", {"form": form})
ModelForm
和Form
的不同点:ModelForm
中多了一个save()
方法,直接保存到数据库,而Form
则需要逐个请求数据提取出来传入到Model构造函数中进行创建。
前端通过form表单渲染和提交
app_demo/templates/app_demo/entry_forms_add.html
{% extends 'app_demo/base.html' %}
{% load static %}
{% block css %}
<link rel="stylesheet" href="{% static 'app_demo/style.css' %}">
{% endblock %}
{% block content %}
<h1>添加Entry</h1>
<form method="post" action="" novalidate>
{% csrf_token %}
{% for filed in form %}
<div class="form-group">
{{ filed.label }}
{{ filed }}
<span class="label label-danger">{{ filed.errors.0 }}</span>
</div>
{% endfor %}
<button type="submit" class="btn btn-default">提交</button>
</form>
{% endblock %}
通过Django组件-ModelForm
组件处理表单-编辑Entry文章
添加路由
app_demo/urls.py
path('entry/<int:e_id>/edit', views.entry_edit_view, name='entry_edit'),
修改app_demo/templates/app_demo/entry_list.html
中的“编辑”链接
<a href="{% url 'entry_edit' entry.id %}">编辑</a>
定义ModelForm表单
app_demo/forms.py
复用原有的EntryModelForm
视图函数处理表单数据
app_demo/views.py
def entry_edit_view(request, e_id):
entry = get_object_or_404(Entry, pk=e_id)
if request.method == "GET":
form = EntryModelForm(instance=entry)
return render(request, "app_demo/entry_edit.html", {"form": form})
form = EntryModelForm(request.POST, instance=entry)
if form.is_valid():
form.save()
return redirect(reverse("entry_list"))
return render(request, "app_demo/entry_edit.html", {"form": form})
form = EntryModelForm(request.POST, instance=entry)
通过instance
指定将要编辑的实例,如果不指定instance,则会数据库新建一条记录
前端通过form表单渲染和提交
app_demo/templates/app_demo/entry_edit.html
代码同 app_demo/templates/app_demo/entry_forms_add.html
{% extends 'app_demo/base.html' %}
{% load static %}
{% block css %}
<link rel="stylesheet" href="{% static 'app_demo/style.css' %}">
{% endblock %}
{% block content %}
<h1>编辑Entry</h1>
<form method="post" action="" novalidate>
{% csrf_token %}
{% for filed in form %}
<div class="form-group">
{{ filed.label }}
{{ filed }}
<span class="label label-danger">{{ filed.errors.0 }}</span>
</div>
{% endfor %}
<button type="submit" class="btn btn-default">提交</button>
</form>
{% endblock %}
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。