Django的Form主要具有一下几大功能:
- 生成HTML标签
- 验证用户数据(显示错误信息)
- HTML Form提交保留上次提交数据
- 初始化页面显示内容
第一阶段:
1.在views中创建Form类
# 创建一个类from django import formsfrom django.forms import fields class DiyForm(forms.Form): # 类中创建字段 例如 IntegerField包含了正则表达式 user = fields.CharField( max_length=18, min_length=6, required=True, error_messages={ 'max_length': '用户名过长', 'min_length': '用户名过短', 'required': '用户名不能为空', 'invalid': '输入类型错误' } ) pwd = fields.CharField( required=True, min_length=8, error_messages={ 'required': '密码不可为空', 'min_length': '密码至少为8位' } ) age = fields.IntegerField( required=True, error_messages={ 'required': '年龄不可为空', 'invalid': '年龄必须为数字' } ) email = fields.EmailField( required=True, min_length=8, error_messages={ 'required': '邮箱不可为空', 'min_length': '邮箱长度不匹配', 'invalid': '邮箱规则不符合' } )
2.views中的函数调用Form
from django.shortcuts import render,HttpResponse,redirect def f1(request): if request.method == 'GET': obj = DiyForm() # 实例化 传参可进行模板渲染 生成Html代码 return render(request, 'f1.html', { 'obj':obj}) else: obj = DiyForm(request.POST) # 判断是否全部验证成功 逐一交给类字段里面一一进行验证、像一层滤网 if obj.is_valid(): # 用户提交的数据 验证成功的信息 print('验证成功', obj.cleaned_data) return redirect('http://www.baidu.com') else: print('验证失败', obj.errors) # 封装的错误信息 return render(request, 'f1.html', { 'obj': obj})
3. html页面
DjangoForm
创建Form类时,主要涉及到 【字段】 和 【插件】,字段用于对用户请求数据的验证,插件用于自动生成HTML;
1、Django中Form类内置字段如下:
常用字段
用于保存正则表达式ChoiceField *****MultipleChoiceFieldCharFieldIntegerFieldDecimalFieldDateFieldDateTimeFieldEmailFieldGenericIPAddressFieldFileField RegexField
详细字段
Field required=True, 是否允许为空 widget=None, HTML插件 label=None, 用于生成Label标签或显示内容 initial=None, 初始值 help_text='', 帮助信息(在标签旁边显示) error_messages=None, 错误信息 { 'required': '不能为空', 'invalid': '格式错误'} show_hidden_initial=False, 是否在当前插件后面再加一个隐藏的且具有默认值的插件(可用于检验两次输入是否一直) validators=[], 自定义验证规则 localize=False, 是否支持本地化 disabled=False, 是否可以编辑 label_suffix=None Label内容后缀 CharField(Field) max_length=None, 最大长度 min_length=None, 最小长度 strip=True 是否移除用户输入空白 IntegerField(Field) max_value=None, 最大值 min_value=None, 最小值 FloatField(IntegerField) ... DecimalField(IntegerField) max_value=None, 最大值 min_value=None, 最小值 max_digits=None, 总长度 decimal_places=None, 小数位长度 BaseTemporalField(Field) input_formats=None 时间格式化 DateField(BaseTemporalField) 格式:2015-09-01TimeField(BaseTemporalField) 格式:11:12DateTimeField(BaseTemporalField)格式:2015-09-01 11:12 DurationField(Field) 时间间隔:%d %H:%M:%S.%f ... RegexField(CharField) regex, 自定制正则表达式 max_length=None, 最大长度 min_length=None, 最小长度 error_message=None, 忽略,错误信息使用 error_messages={ 'invalid': '...'} EmailField(CharField) ... FileField(Field) allow_empty_file=False 是否允许空文件 ImageField(FileField) ... 注:需要PIL模块,pip3 install Pillow 以上两个字典使用时,需要注意两点: - form表单中 enctype="multipart/form-data" - view函数中 obj = MyForm(request.POST, request.FILES) URLField(Field) ... BooleanField(Field) ... NullBooleanField(BooleanField) ... ChoiceField(Field) ... choices=(), 选项,如:choices = ((0,'上海'),(1,'北京'),) required=True, 是否必填 widget=None, 插件,默认select插件 label=None, Label内容 initial=None, 初始值 help_text='', 帮助提示 ModelChoiceField(ChoiceField) ... django.forms.models.ModelChoiceField queryset, # 查询数据库中的数据 empty_label="---------", # 默认空显示内容 to_field_name=None, # HTML中value的值对应的字段 limit_choices_to=None # ModelForm中对queryset二次筛选 ModelMultipleChoiceField(ModelChoiceField) ... django.forms.models.ModelMultipleChoiceField TypedChoiceField(ChoiceField) coerce = lambda val: val 对选中的值进行一次转换 empty_value= '' 空值的默认值 MultipleChoiceField(ChoiceField) ... TypedMultipleChoiceField(MultipleChoiceField) coerce = lambda val: val 对选中的每一个值进行一次转换 empty_value= '' 空值的默认值 ComboField(Field) fields=() 使用多个验证,如下:即验证最大长度20,又验证邮箱格式 fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(),]) MultiValueField(Field) PS: 抽象类,子类中可以实现聚合多个字典去匹配一个值,要配合MultiWidget使用 SplitDateTimeField(MultiValueField) input_date_formats=None, 格式列表:['%Y--%m--%d', '%m%d/%Y', '%m/%d/%y'] input_time_formats=None 格式列表:['%H:%M:%S', '%H:%M:%S.%f', '%H:%M'] FilePathField(ChoiceField) 文件选项,目录下文件显示在页面中 path, 文件夹路径 match=None, 正则匹配 recursive=False, 递归下面的文件夹 allow_files=True, 允许文件 allow_folders=False, 允许文件夹 required=True, widget=None, label=None, initial=None, help_text='' GenericIPAddressField protocol='both', both,ipv4,ipv6支持的IP格式 unpack_ipv4=False 解析ipv4地址,如果是::ffff:192.0.2.1时候,可解析为192.0.2.1, PS:protocol必须为both才能启用 SlugField(CharField) 数字,字母,下划线,减号(连字符) ... UUIDField(CharField) uuid类型
注:UUID是根据MAC以及当前时间等创建的不重复的随机字符串
>>> import uuid # make a UUID based on the host ID and current time >>> uuid.uuid1() # doctest: +SKIP UUID('a8098c1a-f86e-11da-bd1a-00112444be1e') # make a UUID using an MD5 hash of a namespace UUID and a name >>> uuid.uuid3(uuid.NAMESPACE_DNS, 'python.org') UUID('6fa459ea-ee8a-3ca4-894e-db77e160355e') # make a random UUID >>> uuid.uuid4() # doctest: +SKIP UUID('16fd2706-8baf-433b-82eb-8c7fada847da') # make a UUID using a SHA-1 hash of a namespace UUID and a name >>> uuid.uuid5(uuid.NAMESPACE_DNS, 'python.org') UUID('886313e1-3b8a-5372-9b90-0c9aee199e5d') # make a UUID from a string of hex digits (braces and hyphens ignored) >>> x = uuid.UUID('{00010203-0405-0607-0809-0a0b0c0d0e0f}') # convert a UUID to a string of hex digits in standard form >>> str(x) '00010203-0405-0607-0809-0a0b0c0d0e0f' # get the raw 16 bytes of the UUID >>> x.bytes b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f' # make a UUID from a 16-byte string >>> uuid.UUID(bytes=x.bytes) UUID('00010203-0405-0607-0809-0a0b0c0d0e0f')
2、Django内置插件
TextInput(Input)NumberInput(TextInput)EmailInput(TextInput)URLInput(TextInput)PasswordInput(TextInput)HiddenInput(TextInput)Textarea(Widget)DateInput(DateTimeBaseInput)DateTimeInput(DateTimeBaseInput)TimeInput(DateTimeBaseInput)CheckboxInputSelectNullBooleanSelectSelectMultipleRadioSelectCheckboxSelectMultipleFileInputClearableFileInputMultipleHiddenInputSplitDateTimeWidgetSplitHiddenDateTimeWidgetSelectDateWidget
3、常用选择插件
# 单radio,值为字符串# user = fields.CharField(# initial=2,# widget=widgets.RadioSelect(choices=((1,'上海'),(2,'北京'),))# ) # 单radio,值为字符串# user = fields.ChoiceField(# choices=((1, '上海'), (2, '北京'),),# initial=2,# widget=widgets.RadioSelect# ) # 单select,值为字符串# user = fields.CharField(# initial=2,# widget=widgets.Select(choices=((1,'上海'),(2,'北京'),))# ) # 单select,值为字符串# user = fields.ChoiceField(# choices=((1, '上海'), (2, '北京'),),# initial=2,# widget=widgets.Select# ) # 多选select,值为列表# user = fields.MultipleChoiceField(# choices=((1,'上海'),(2,'北京'),),# initial=[1,],# widget=widgets.SelectMultiple# ) # 单checkbox# user = fields.CharField(# widget=widgets.CheckboxInput()# ) # 多选checkbox,值为列表# user = fields.MultipleChoiceField(# initial=[2, ],# choices=((1, '上海'), (2, '北京'),),# widget=widgets.CheckboxSelectMultiple# )
单选或者多选时、数据源是否可以实时更新、
在使用选择标签时,需要注意choices的选项可以从数据库中获取,但是由于是静态字段 ***获取的值无法实时更新***,那么需要自定义构造方法从而达到此目的。
方法一:
from django.forms import Formfrom django.forms import widgetsfrom django.forms import fieldsfrom django.core.validators import RegexValidator class MyForm(Form): user = fields.ChoiceField( # choices=((1, '上海'), (2, '北京'),), initial=2, widget=widgets.Select ) def __init__(self, *args, **kwargs): super(MyForm,self).__init__(*args, **kwargs) # self.fields['user'].widget.choices = ((1, '上海'), (2, '北京'),) # 或 self.fields['user'].widget.choices = models.Classes.objects.all().value_list('id','caption')
方法二:
用django提供的ModelChoiceField和ModelMultipleChoiceField字段来实现
from django import formsfrom django.forms import fieldsfrom django.forms import widgetsfrom django.forms import models as form_modelfrom django.core.exceptions import ValidationErrorfrom django.core.validators import RegexValidator class FInfo(forms.Form): authors = form_model.ModelMultipleChoiceField(queryset=models.NNewType.objects.all()) # authors = form_model.ModelChoiceField(queryset=models.NNewType.objects.all())
class StuForm(Form): name=fields.CharField(required=True,error_messages={ "required":"学生名字不能为空"}, widget=widgets.TextInput(attrs={ "placeholder": "学生姓名", "class": "form-control"}) ) age=fields.IntegerField(required=True,error_messages={ "required":"年龄不能为空","invalid":"年龄必须是数字"}, widget=widgets.TextInput(attrs={ "placeholder": "年龄", "class": "form-control"}) ) sex=fields.ChoiceField(choices=(("m","男"),("f","女")),initial=1,widget=widgets.Select) email=fields.EmailField(required=True,error_messages={ "required":"邮箱不能为空","invalid":"邮箱格式不正确"}, widget=widgets.EmailInput(attrs={ "placeholder": "邮箱", "class": "form-control"}) ) cls_id=fields.ChoiceField(choices=[],widget=widgets.Select) def __init__(self,*args,**kwargs): super().__init__(*args,**kwargs) self.fields["cls_id"].choices=models.ClassList.objects.all().values_list("id","caption")
自定义校验
通过上述,Django的Form组件提供验证用户提交的数据并可以显示错误信息(或自定制),更能可以生成相应的Html代码。更是猜想到,仅仅根据Form组件的验证或许满足不了一些需求,于是建立再Form的验证功能上使其有很强的扩展性
一、基于Form组件的字段上的简单扩展
方式A
from django.forms import Formfrom django.forms import widgetsfrom django.forms import fieldsfrom django.core.validators import RegexValidator class MyForm(Form): phone = fields.CharField( validators=[RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^188[0-9]+{9}$', '数字必须以188开头')],
方式B
import refrom django.forms import Formfrom django.forms import widgetsfrom django.forms import fieldsfrom django.core.exceptions import ValidationError # 自定义验证规则def mobile_validate(value): mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$') if not mobile_re.match(value): raise ValidationError('手机号码格式错误') class PublishForm(Form): title = fields.CharField(max_length=20, min_length=5, error_messages={ 'required': '标题不能为空', 'min_length': '标题最少为5个字符', 'max_length': '标题最多为20个字符'}, widget=widgets.TextInput(attrs={ 'class': "form-control", 'placeholder': '标题5-20个字符'})) # 使用自定义验证规则 phone = fields.CharField(validators=[mobile_validate, ], error_messages={ 'required': '手机不能为空'}, widget=widgets.TextInput(attrs={ 'class': "form-control", 'placeholder': u'手机号码'})) email = fields.EmailField(required=False, error_messages={ 'required': u'邮箱不能为空','invalid': u'邮箱格式错误'}, widget=widgets.TextInput(attrs={ 'class': "form-control", 'placeholder': u'邮箱'}))
二、基于源码执行的流程上进行扩展
方式A
例如在注册一个账号时、通过Form的验证其账号符合规则时,还将要判断该账号是否存在于数据库,如存在则肯定是注册不通过的
自定义方法、单一字段逐个再次验证
from Formtest import modelsfrom django import formsfrom django.forms import fieldsfrom django.forms import widgetsfrom django.core.exceptions import ValidationError,NON_FIELD_ERRORSfrom django.core.validators import RegexValidator class AjaxForm(forms.Form): user=fields.CharField( max_length=10, required=False, validators=[RegexValidator(r'^[a-z]+$', 'Enter a valid extension.', 'invalid')], ) email=fields.EmailField() #钩子函数 def clean_user(self): """ Form中字段中定义的格式匹配完之后,执行此方法进行验证 :return: """ v = self.cleaned_data['user'] if models.UserInfo.objects.filter(user=v).count(): raise ValidationError('此用户名已经存在') return v
#钩子函数
def clean_email(self): """ email验证过之后、可以自定义验证该邮箱是否被使用 ... : return: """ pass
方式B
from django.core.exceptions import NON_FIELD_ERRORS, ValidationErrorclass AjaxForm(forms.Form): username = fields.CharField() user_id = fields.IntegerField( widget=widgets.Select(choices=[(0,'alex'),(1,'刘皓宸'),(2,'杨建'),]) ) # 自定义方法 clean_字段名,设置一个字段整体验证 # 必须返回值self.cleaned_data['username'] # 如果出错:raise ValidationError('用户名已存在') def clean_username(self): v = self.cleaned_data['username'] #数据库中如果有这用户 if UsersF.objects.filter(username=v).count(): # 整体错了 # 自己详细错误信息 raise ValidationError('用户名已存在') return v def clean_user_id(self): return self.cleaned_data['user_id'] #设置整体错误,可以用来设置多个字段整体验证 def clean(self): value_dict=self.cleaned_data v1 = value_dict.get('username') v2 = value_dict.get('user_id') if v1=='root' and v2==0: raise ValidationError('整体错误信息') return self.cleaned_datadef ajax(request): if request.method == 'GET': obj = AjaxForm() return render(request,'ajax.html',{ 'obj':obj}) else: ret = { 'status':'tom','message':None} import json obj = AjaxForm(request.POST) if obj.is_valid(): # 跳转到百度 # return redirect('http://www.baidu.com') # if .... # obj.errors['username'] = ['用户名已经存在',] # if .... # obj.errors['email'] = ['用户名已经存在',] ret['status'] = '钱' return HttpResponse(json.dumps(ret)) else: # print(type(obj.errors)) # print(obj.errors) from django.forms.utils import ErrorDict # print(obj.errors.as_ul()) # print(obj.errors.as_json()) # print(obj.errors.as_data()) ret['message'] = obj.errors # 错误信息显示在页面上 return HttpResponse(json.dumps(ret))
钩子函数 - clean_字段名 注意: 必须有返回值 只能拿自己当前字段值 raise ValidationError('xxx')
select
from django.shortcuts import renderfrom django import formsfrom django.forms import fieldsfrom django.forms import widgetsclass TestForm(forms.Form): user = fields.CharField( required=True, # 是否必填 max_length=12, # 最大长度 min_length=3, # 最小长度 error_messages={}, # 错误提示 #widget = widgets.Select(), # 定制HTML插件 label='用户名', initial='请输入用户', help_text='asdfasdf', show_hidden_initial=False, # validators=[] disabled=True, label_suffix='->' ) age = fields.IntegerField( label='年龄', max_value= 12, min_value=5, error_messages={ 'max_value':'太大了' } ) email = fields.EmailField( label='邮箱' ) img = fields.FileField() city = fields.TypedChoiceField( coerce=lambda x: int(x), choices=[(1,'上海',),(2,'北京'),(3,'沙河'),], initial=2 ) xoo = fields.FilePathField( path='app01' ) #多选checkbox c = fields.MultipleChoiceField( choices=[(1, '刚娘'), (2, '铁娘'), (3, '钢弹')], initial=[1,3], widget=widgets.CheckboxSelectMultiple ) #多选select bobby = fields.MultipleChoiceField( choices=[(1, '刚娘'), (2, '铁娘'), (3, '钢弹')], initial=[1, 2], widget=widgets.SelectMultiple ) #单选select t = fields.CharField( widget = widgets.Select(choices=[(1,'上海',),(2,'北京'),(3,'沙河'),]), initial=2 ) #**********重要***** u = fields.CharField( widget= widgets.Select() ) def __init__(self,*args,**kwargs): #实时更新,拷贝所有的静态字段,复制给self.fields super(TestForm,self).__init__(*args,**kwargs) self.fields['u'].widget.choices=UsersF.objects.values_list('id','username')def test(request): if request.method == 'GET': obj = TestForm() return render(request,'test.html',{ 'obj':obj}) elif request.method=='POST': obj = TestForm(request.POST,request.FILES) if obj.is_valid(): print('成功',obj.cleaned_data) return render(request, 'test.html', { 'obj': obj}) else: pass
示例
from django.db import modelsclass ClassList(models.Model): """ 班级表 """ caption = models.CharField(max_length=32) headmaster = models.ForeignKey(to="UserInfo")class Student(models.Model): """ 学生表 """ name = models.CharField(max_length=32) age = models.IntegerField() cls = models.ForeignKey(to="ClassList",related_name="uuu")class UserType(models.Model): """ 用户类型表,个数经常变动 """ title = models.CharField(max_length=32)class UserInfo(models.Model): """ 用户表:讲师和班主任 """ username = models.CharField(max_length=32) password = models.CharField(max_length=64) email = models.CharField(max_length=32) ut = models.ForeignKey(to="UserType") teacher_to_cls = models.ManyToManyField(to='ClassList',related_name='a') def __str__(self): return self.username# #################################################
rom app01 import viewsurlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^index/', views.index), url(r'^login/', views.login), url(r'^teachers/', views.teachers), url(r'^add_teacher/', views.add_teacher), url(r'^edit_teacher/(\d+)/', views.edit_teacher), url(r'^class_list/', views.class_list), url(r'^class_add/', views.class_add), url(r'^class_edit/(\d+)/', views.class_edit), url(r'^teacher_list/', views.teacher_list), url(r'^teacher_add/', views.teacher_add), url(r'^teacher_edit/(\d+)/', views.teacher_edit), url(r'^test/', views.test),]
from django.shortcuts import render,redirect,HttpResponsefrom django.conf import settingsfrom django.forms import Formfrom django.forms import fieldsfrom django.forms import widgetsfrom django.core.validators import RegexValidatorfrom django.core.exceptions import ValidationErrorfrom app01 import models## def index(request):## all_teacher_list=models.Teacher.objects.all()## return render(request,"index.html",locals())## # def index(request):# # is_login=request.COOKIES.get("is_login",None)# # if is_login:# # username=request.COOKIES.get("username")# # return render(request, "index.html",locals())# # else:# # return redirect("/login/")##### def delTeacher(request,tid):## models.Teacher.objects.filter(tid=tid).delete()## return redirect("/index/")#class LoginForm(Form): username = fields.CharField( required=True, min_length=3, max_length=18, error_messages={ 'required': '用户不能为空', 'min_length': '用户长度不能小于3', 'max_length': '用户长度不能大于18', } ) password = fields.CharField( required=True, min_length=3, max_length=18, error_messages={ 'required': '密码不能为空', 'min_length': '密码长度不能小于3', 'max_length': '密码长度不能大于18', 'invalid': '密码格式错误', }, validators=[RegexValidator('\d+','只能是数字') ] ) def clean_username(self): # ... user = self.cleaned_data['username'] is_exsit = models.UserInfo.objects.filter(username=user).count() if not is_exsit: raise ValidationError('用户名不存在') return user def clean_password(self): user = self.cleaned_data['username'] return userdef login(request): if request.method == "GET": form = LoginForm() return render(request,'login.html',{ 'form':form}) elif request.method =="POST": form = LoginForm(data=request.POST) if form.is_valid(): # 验证成功 user = models.UserInfo.objects.filter(**form.cleaned_data).first() if not user: # 用户名或密码错误 # form.add_error('password','用户名或密码错误') form.add_error('password',ValidationError('用户名或密码错误')) return render(request, 'login.html', { 'form': form}) else: request.session[settings.SJF] = { 'id':user.id, 'username':user.username} return redirect('/index/') else: # 验证失败 return render(request, 'login.html',{ 'form':form}) else: return HttpResponse('滚')def auth(func): def inner(request,*args,**kwargs): user_info = request.session.get(settings.SJF) if not user_info: return redirect('/login/') return func(request,*args,**kwargs) return innerdef index(request): username = request.session[settings.SJF]['username'] return render(request,'index.html',{ 'username':username})def teachers(request): # models.UserInfo.objects.filter(ut__title='讲师') teacher_list = models.UserInfo.objects.filter(ut_id=1) return render(request,'teachers.html',{ 'teacher_list':teacher_list})class TeacherForm(Form): username = fields.CharField( required=True, error_messages={ 'required':'用户名不能为空'}, widget=widgets.TextInput(attrs={ 'placeholder':'用户名','class':'form-control'}) ) # 不能为空 password = fields.CharField(required=True,error_messages={ 'required':'密码不能为空'}, widget=widgets.TextInput(attrs={ 'placeholder':'密码','class':'form-control'})) # 不能为空 email = fields.EmailField(required=True,error_messages={ 'required':'邮箱不能为空','invalid':'邮箱格式错误'},widget=widgets.EmailInput(attrs={ 'placeholder':'邮箱','class':'form-control'})) # 不能为空,且邮箱格式def add_teacher(request): if request.method == 'GET': form = TeacherForm() return render(request,'add_teacher.html',{ 'form':form}) else: """ 1. 用户请求数据验证 2. 自动生成错误信息 3. 打包用户提交正确信息 4. 错误:保留上次输入内容 5. 定制页面上显示的HTML标签 Django Form组件 1. 创建规则(类,字段) class Foo: username = xxx password = xxx email = xxx 2. 数据和规则进行匹配 """ form = TeacherForm(data=request.POST) # 数据和规则放置一起 if form.is_valid(): # 开始校验,并获取校验结果 # print('执行成功',form.cleaned_data) # 所有匹配成功,字典 # {'username': 'asd', 'password': 'sdf', 'email': 'sadf@live.com','ut_id':1} form.cleaned_data['ut_id'] = 1 models.UserInfo.objects.create(**form.cleaned_data) return redirect('/teachers/') return render(request, 'add_teacher.html',{ 'form':form})def edit_teacher(request,nid): obj = models.UserInfo.objects.filter(id=nid,ut_id=1).first() if not obj: return redirect('/teachers/') if request.method == "GET": # 显示input,并且将数据库中的默认值填写到input框中 form = TeacherForm(initial={ 'username':obj.username,'password':obj.password,'email':obj.email}) return render(request,'edit_teacher.html',{ 'form':form}) else: form = TeacherForm(data=request.POST) if form.is_valid(): # 校验成功 models.UserInfo.objects.filter(id=nid).update(**form.cleaned_data) return redirect('/teachers/') return render(request,'edit_teacher.html',{ 'form':form})class TestForm(Form): caption = fields.CharField() # xxx = fields.ChoiceField(choices=[(1,'讲师'),(2,'班主任')]) # xxx = fields.ChoiceField(choices=models.UserInfo.objects.values_list('id','username')) # xxx = fields.ChoiceField(choices=models.UserType.objects.values_list('id','title')) xxx = fields.MultipleChoiceField(choices=models.UserInfo.objects.values_list('id','username'))def test(request): print('view.test') return HttpResponse('...')def class_list(request): cls_list = models.ClassList.objects.all() return render(request,'class_list.html',{ 'cls_list':cls_list})class ClassForm(Form): caption = fields.CharField(error_messages={ 'required':'班级名称不能为空'}) headmaster_id = fields.ChoiceField(choices=[]) def __init__(self,*args,**kwargs): super().__init__(*args,**kwargs) self.fields['headmaster_id'].choices = models.UserInfo.objects.filter(ut_id=2).values_list('id','username')def class_add(request): if request.method == 'GET': form = ClassForm() return render(request,'class_add.html',{ 'form':form}) else: form = ClassForm(data=request.POST) if not form.is_valid(): return render(request, 'class_add.html', { 'form': form}) models.ClassList.objects.create(**form.cleaned_data) return redirect('/class_list/')def class_edit(request,nid): obj = models.ClassList.objects.filter(id=nid).first() if not obj: return redirect('/class_list/') if request.method == "GET": form = ClassForm(initial={ 'caption': obj.caption,'headmaster_id':obj.headmaster_id}) return render(request, 'class_edit.html', { 'form': form}) else: form = ClassForm(data=request.POST) if form.is_valid(): models.ClassList.objects.filter(id=nid).update(**form.cleaned_data) return redirect('/class_list/') return render(request, 'class_edit.html', { 'form': form})class TeacherNewForm(Form): username = fields.CharField( required=True, error_messages={ 'required': '用户名不能为空'}, widget=widgets.TextInput(attrs={ 'placeholder': '用户名', 'class': 'form-control'}) ) # 不能为空 password = fields.CharField(required=True, error_messages={ 'required': '密码不能为空'}, widget=widgets.TextInput(attrs={ 'placeholder': '密码', 'class': 'form-control'})) # 不能为空 email = fields.EmailField(required=True, error_messages={ 'required': '邮箱不能为空', 'invalid': '邮箱格式错误'}, widget=widgets.EmailInput( attrs={ 'placeholder': '邮箱', 'class': 'form-control'})) # 不能为空,且邮箱格式 cls_list = fields.MultipleChoiceField(choices=[]) def __init__(self,*args,**kwargs): super().__init__(*args,**kwargs) self.fields['cls_list'].choices = models.ClassList.objects.values_list('id','caption')def teacher_list(request): teachers = models.UserInfo.objects.filter(ut_id=1).all() return render(request,'teacher_list.html',{ 'teachers':teachers})def teacher_add(request): if request.method == "GET": form = TeacherNewForm() return render(request,'teacher_add.html',{ 'form':form}) else: form = TeacherNewForm(request.POST) if form.is_valid(): """ 1. 创建老师表数据 username password email ut_id=1 2. 创建老师班级关系表数据 新创建的老师 5 cls_list: [1,2,3] """ cls_list = form.cleaned_data.pop('cls_list') form.cleaned_data['ut_id']= 1 # 获取新创建的老师对象 user_obj = models.UserInfo.objects.create(**form.cleaned_data) # 创建老师和班级关系表数据 user_obj.teacher_to_cls.add(*cls_list) # 第三张表中添加数据 return redirect('/teacher_list/')def teacher_edit(request,nid): obj = models.UserInfo.objects.filter(ut_id=1,id=nid).first() if not obj: return redirect('/teacher_list/') """ 获取当前用户信息: obj.username obj.password obj.email obj.teacher_to_cls.all() [班级对象,班级对象,] """ if request.method == "GET": form = TeacherNewForm(initial={ 'username':obj.username,'password':obj.password,'email':obj.email,'cls_list':[row.id for row in obj.teacher_to_cls.all()]}) return render(request,'teacher_edit.html',{ 'form':form}) else: form = TeacherNewForm(request.POST) if form.is_valid(): cls_list = form.cleaned_data.pop('cls_list') models.UserInfo.objects.filter(id=nid).update(**form.cleaned_data) obj.teacher_to_cls.set(cls_list) # 更新第三张表 return redirect('/teacher_list/') return render(request, 'teacher_edit.html', { 'form': form})
详见github schoolmanaage