urls.py
# 任务管理
path('task/list/', task.task_list),
path('task/add/', task.task_add),
models.py
class Admin(models.Model):
username = models.CharField(verbose_name='用户名', max_length=32)
password = models.CharField(verbose_name='密码', max_length=64)
def __str__(self):
return self.username
class Task(models.Model):
""" 任务 """
leval_choices = (
(1, '紧急'),
(2, '重要'),
(3, '临时'),
)
leval = models.SmallIntegerField(choices=leval_choices, default=1, verbose_name='级别')
title = models.CharField(verbose_name='标题', max_length=64)
detail = models.TextField(verbose_name='详细信息')
user = models.ForeignKey(verbose_name='负责人', to='Admin', on_delete=models.CASCADE)
views.py
from django.shortcuts import render, HttpResponse, redirect
from django.http import JsonResponse
import json
# 免CSRF认证
from django.views.decorators.csrf import csrf_exempt
from django import forms
from sainfo import models
# 使用 forms.ModelForm 生成前端的 表单
class TaskModelForm(forms.ModelForm):
class Meta:
model = models.Task
# 所有字段
fields = "__all__"
widgets = {
# 'detail': forms.TextInput,
'detail': forms.Textarea,
}
# 该方法是通过修改内部代码,对样式进行修改,样式的值可根据需求随意修改
# 重新定义 init 方法
def __init__(self, *args, **kwargs):
# 重新定义 它 父类的 init 方法
super().__init__(*args, **kwargs)
# 循环ModelForm中的所有字段,给每个字段设置插件 field.widget.attrs
for name, field in self.fields.items():
print(name, field)
# 判断,给某个字段不加插件
# if name == 'password':
# continue
# 字段的插件
field.widget.attrs = {
"class": "form-control",
# "placeholder": field.label
}
def task_list(request):
"""任务列表"""
form = TaskModelForm()
return render(request, 'task_list.html', {'form': form})
# 免csrf认证
@csrf_exempt
def task_add(request):
if request.method == 'GET':
print(request.GET)
if request.method == 'POST':
print(request.POST)
# 1.前端提效数据需要进行校验(ModelForm进行校验)
# 创建对象
form = TaskModelForm(data=request.POST)
if form.is_valid(): # 校验数据
# 校验成功,保存到数据库
form.save()
# 返回数据到前端, 因为是Ajax提交,不能使用 return redirect(.....)
# HttpResponse 返回前端数据字典,要使用 json.dumps()
data_dict = {'status': '正常'}
return HttpResponse(json.dumps(data_dict))
else:
# 验证失败 ,错误信息都在 创建的 form 对象里
print(type(form.errors)) # <class 'django.forms.utils.ErrorDict'>
print(form.errors)
data_dict = {'status': '失败', 'error': form.errors}
return HttpResponse(json.dumps(data_dict))
task_list.html
{% extends 'layout.html' %}
{% block content %}
<div class="container">
<div class="panel panel-default">
<div class="panel-heading">表单</div>
<div class="panel-body">
<form id="formAdd" novalidate>
{# class="clearfix" 清除内部的浮动#}
<div class="clearfix">
{# form 是 views传过来的对象,也是ModelForm自动生成的html内容#}
{% for field in form %}
{# 栅格 #}
<div class="col-xs-6">
{# position: relative 显示相对定位 #}
<div class="form-group" style="position: relative; margin-bottom: 20px">
{# filed.label 就是 字段的 verbose_name#}
{# field 是循环后得到的每一个字段的 input框#}
<label>{{ field.label }}:</label>
{{ field }}
{# position: absolute 显示绝对定位 漂浮在上面 #}
{# class="error-msg" 创建类,ajax 类选择器会使用 #}
<span class="error-msg" style="color:red; position: absolute"></span>
</div>
</div>
{% endfor %}
</div>
<div class="col-xs-12">
<button type="reset" class="btn btn-primary btn-sm">
<span class="glyphicon glyphicon-remove-circle" aria-hidden="true"></span>
重置
</button>
{# 用Ajax提交表单,不能使用 type="submit" #}
<button id='btnAdd' type="button" class="btn btn-primary btn-sm" onclick="clickform()">
<span class="glyphicon glyphicon-ok-circle" aria-hidden="true"></span>
提交
</button>
</div>
</form>
</div>
</div>
</div>
{% endblock %}
{% block js %}
<script>
function clickform() {
// ".error-msg" 类选择器,每次执行时先把 span 标签清空
$(".error-msg").empty();
$.ajax({
url: '/task/add/',
type: 'post',
// 接收前端字典数据
dataType: 'JSON',
// serialize() 对选中的form表单内容进行序列化,返回给后端
// 不用分别对每个input框使用 val() 取值
data: $('#formAdd').serialize(),
// res 接收的后端回传数据, 这里就是后端 json.dumps(data_dict)
success: function (res) {
if (res.status === '正常') {
alert('数据添加成功');
} else {
console.log(res.error);
// {title: Array(1), detail: Array(1), user: Array(1)}
// each 遍历字典 在span标签输出错误信息
$.each(res.error, function (name, value) {
// value 的值是数组
console.log(name+'......'+value);
// 字符串拼接
// ModelForm 在生成 input 框时会自动增加 id_,格式是: id_属性名
// 比如这里的input框会自动生成: id="id_title", id="id_detail", id="id_user"
// '#id_'+ name, 拼接字符串,并选中标签。 name是遍历的字典key.
// next() 选中当前标签的下一个标签,这里就是input标签的下一个是span标签
// text(value[0]), value是数组,取第0个元素,text()写入内容
$('#id_'+ name).next().text(value[0]); // #id选择器
})
}
}
})
}
</script>
{% endblock %}