Day23内容回顾--缺失,遗憾成狗。
一:Model(2个功能)
-数据库操作;
-验证,只有一个clean方法可以作为钩子。
二:Form(专门来做验证的)--------根据form里面写的类,类里面有字段,这个字段是内置的正则表达式。
例如:-class LoginForm(Form): email=fields.EmailField()
-is_valid(触发验证功能) ->每一个字段进行正则(用的是字段内置的正则)+clean_字段 -> clean(__all__) -> _post_clean。
form的钩子,先进行每一个字段正则表达式验证,然后每一个字段的方法,然后进行clean,clean完了以后是post clean
email的错误信息放在email [大列表里面了], 整体的错误信息放在了 __all__ 里面了。
-cleaned_data
-error
建议分开使用上面的两个模块:Model+Form,这样可以降低耦合。但是代码有重复。
Day24: 环境搭建,参考http://www.cnblogs.com/momo8238/p/7508677.html
一,基于form来做。
创建2张表备用,2张表之间用ForeignKey进行关联:
models.py
from django.db import models # Create your models here. class UserType(models.Model): caption=models.CharField(max_length=32) class UserInfo(models.Model): username = models.CharField(max_length=32) email=models.EmailField() user_type=models.ForeignKey(to='UserType',to_field='id')
创建
python manage.py makemigrations python manage.py migrate
2. 如果我想在index.html页面上对UserInfo表进行操作,那么应该把UserInfo 表中的所有信息从后台传送过来。把所有的字段重新创建一遍。
用Form方法的话,需要自己写field字段。 用ModelForm的话,字段是自己从类里面提取过来的。
views.py
# Create your views here. 用Form方式实现 from django.shortcuts import render from django import forms from django.forms import fields from app01 import models class UserInfoForm(forms.Form): username = fields.CharField(max_length=32) email=fields.EmailField() user_type=fields.ChoiceField( choices=models.UserType.objects.values_list('id','caption') #forms下面是用field字段来进行验证的。forms下面没有foreignKey字段,只有choicefield,然后通过choices把另外一张表里面的内容都关联过来。在页面上把用户类型作为一个列表展示出来 ) def index(request): obj=UserInfoForm() return render(request,'index.html',{'obj':obj})
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> {% csrf_token %} {{obj.as_p}} </body> </html>
运行效果:
3. 让user_type每一次都做更新操作,需要重构函数
说明见下图:
具体说明可以参考day23
def __init__(self,*args,**kwargs): super(UserInfoForm,self).__init__(*args,**kwargs) self.fields['user_type'].choices=models.UserType.objects.values_list('id','caption')
4. 完善index.html函数,用form表单提交
{% csrf_token %} 密文显示
{{csrf_token }} 在前端页面生成字符串
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="/index/" method="POST"> {% csrf_token %} {{obj.as_p}} <input type="submit" value="提交"/> </form> </body> </html>
页面效果:
5. 一点提交,数据就传到了后台。
obj.is_valid() #是否通过验证
obj.cleaned_data() #所有的正确信息
obj.errors() #所有的错误信息
models.UserInfo.objects.create(**obj.cleaned_data) #如果数据正确,则创建。是字典格式。
models.UserInfo.objects.filter(id=1).update(**obj.cleaned_data) #找到主键后自动更新
程序粘贴:
views.py
# Create your views here. 用Form方式实现 from django.shortcuts import render from django import forms from django.forms import fields from app01 import models class UserInfoForm(forms.Form): username = fields.CharField(max_length=32) email=fields.EmailField() #user_type=fields.ForeignKey(to='UserType',to_field='id') fields中没有foreignkey user_type=fields.ChoiceField( choices=models.UserType.objects.values_list('id','caption') #在页面上把用户类型作为一个列表展示出来 ) def __init__(self,*args,**kwargs): super(UserInfoForm,self).__init__(*args,**kwargs) self.fields['user_type'].choices=models.UserType.objects.values_list('id','caption') def index(request): if request.method=='GET': obj=UserInfoForm() return render(request,'index.html',{'obj':obj}) elif request.method=='POST': obj=UserInfoForm(request.POST) obj.is_valid() obj.cleaned_data() obj.errors() #models.UserInfo.objects.create(**obj.cleaned_data) #models.UserInfo.objects.filter(id=1).update(**obj.cleaned_data) return render(request, 'index.html', {'obj': obj})
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="/index/" method="POST"> {% csrf_token %} {{obj.as_p}} <input type="submit" value="提交"/> </form> </body> </html>
models.py
from django.db import models # Create your models here. class UserType(models.Model): caption=models.CharField(max_length=32) class UserInfo(models.Model): username = models.CharField(verbose_name='用户名',max_length=32) email=models.EmailField() user_type=models.ForeignKey(to='UserType',to_field='id')
urls.py
from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^index/', views.index), ]
二,基于ModelForm来做。
1. class UserInfoModelForm(forms.ModelForm): 它也能帮我们自动生成HTML标签。
views.py
# 基于ModelForm方式来实现 from django.shortcuts import render from app01 import models from django import forms from django.forms import fields class UserInfoModelForm(forms.ModelForm): class Meta: model=models.UserInfo #指去哪个类里面去获取字段。 fields='__all__' #代指的是所有的field字段 #fields=['username'] #还可以是一个列表,可以选择要展示哪几列,只展示username这一列 #exclude=['username'] #把username列排除在外了。 def index(request): if request.method=='GET': obj=UserInfoModelForm() return render(request,'index.html',{'obj':obj}) elif request.method=='POST': obj=UserInfoModelForm(request.POST) return render(request, 'index.html', {'obj': obj})
效果:
2.用Form时,字段是自己定义的。所以如果想显示中文的话,用label标签就可以了。
views.py
# 基于Form方式来实现 from django.shortcuts import render from django import forms from django.forms import fields from app01 import models class UserInfoForm(forms.Form): username = fields.CharField(max_length=32,label='用户名') email=fields.EmailField() #user_type=fields.ForeignKey(to='UserType',to_field='id') fields中没有foreignkey user_type=fields.ChoiceField( choices=models.UserType.objects.values_list('id','caption') #在页面上把用户类型作为一个列表展示出来 ) def __init__(self,*args,**kwargs): super(UserInfoForm,self).__init__(*args,**kwargs) self.fields['user_type'].choices=models.UserType.objects.values_list('id','caption') def index(request): if request.method=='GET': obj=UserInfoForm() return render(request,'index.html',{'obj':obj}) elif request.method=='POST': obj=UserInfoForm(request.POST) obj.is_valid() obj.cleaned_data() obj.errors() #models.UserInfo.objects.create(**obj.cleaned_data) #models.UserInfo.objects.filter(id=1).update(**obj.cleaned_data) return render(request, 'index.html', {'obj': obj})
效果如下:
用ModelForm时,前端页面中的字段是从相关联的类里面直接提取过来的,两者之间有耦合。自己不用再写了。
如果想要显示中文字段名的话,需要verbose_name='用户'
效果:
3.
model=models.UserInfo #指去哪个类里面去获取字段,以后也可以做增删改查。
fields='__all__' #代指的是所有的field字段
fields=['username'] #还可以是一个列表,可以选择要展示哪几列,只展示username这一列
exclude=['username'] #把username列排除在外了。
效果展示1:
效果展示2:
4. 往UserType里面写一条数据备用:
用form方法的时候,验证功能的函数其实是写在BaseForm里的:UserInfoForm-->继承了Form--->继承了BaseForm(is_valid......)
点击提交的时候,modelform也可以做验证。UserInfoModelForm-->继承了ModelForm--->继承了BaseModelForm--->继承了BaseForm(is_valid......)
UserInfoModelForm下面也应该有obj.is_valid(), obj.cleaned_data, obj.errors 等方法。
ModelForm 做验证的时候与Form方法是一样的。
效果1:
效果2:
三,程序粘贴:
1. 基于form方法的views.py
# 基于Form方式来实现 from django.shortcuts import render from django import forms from django.forms import fields from app01 import models class UserInfoForm(forms.Form): username = fields.CharField(max_length=32,label='用户名') email=fields.EmailField() #user_type=fields.ForeignKey(to='UserType',to_field='id') fields中没有foreignkey user_type=fields.ChoiceField( choices=models.UserType.objects.values_list('id','caption') #在页面上把用户类型作为一个列表展示出来 ) def __init__(self,*args,**kwargs): super(UserInfoForm,self).__init__(*args,**kwargs) self.fields['user_type'].choices=models.UserType.objects.values_list('id','caption') def index(request): if request.method=='GET': obj=UserInfoForm() return render(request,'index.html',{'obj':obj}) elif request.method=='POST': obj=UserInfoForm(request.POST) obj.is_valid() obj.cleaned_data() obj.errors() #models.UserInfo.objects.create(**obj.cleaned_data) #models.UserInfo.objects.filter(id=1).update(**obj.cleaned_data) return render(request, 'index.html', {'obj': obj})
2. 基于modelform方法的views.py
# 基于ModelForm方式来实现 from django.shortcuts import render,HttpResponse from app01 import models from django import forms from django.forms import fields def orm(request): #models.UserType.objects.create(caption='Alex') return HttpResponse('orm') class UserInfoModelForm(forms.ModelForm): class Meta: model=models.UserInfo #指去哪个类里面去获取字段,以后也可以做增删改查。 fields='__all__' #代指的是所有的field字段 #fields=['username'] #还可以是一个列表,可以选择要展示哪几列,只展示username这一列 #exclude=['username'] #把username列排除在外了。 class UserInfoForm(forms.Form): username = fields.CharField(max_length=32) email=fields.EmailField() #user_type=fields.ForeignKey(to='UserType',to_field='id') user_type=fields.ChoiceField( choices=models.UserType.objects.values_list('id','caption') ) def __init__(self,*args,**kwargs): super(UserInfoForm,self).__init__(*args,**kwargs) self.fields['user_type'].choices=models.UserType.objects.values_list('id','caption') def index(request): if request.method=='GET': obj=UserInfoModelForm() return render(request,'index.html',{'obj':obj}) elif request.method=='POST': obj=UserInfoModelForm(request.POST) print(obj.is_valid()) print(obj.cleaned_data) print(obj.errors) return render(request, 'index.html', {'obj': obj})
3.index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="/index/" method="POST"> {% csrf_token %} {{obj.as_p}} <input type="submit" value="提交"/> </form> </body> </html>
4.models.py
from django.db import models # Create your models here. class UserType(models.Model): caption=models.CharField(max_length=32) class UserInfo(models.Model): username = models.CharField(verbose_name='用户',max_length=32) email=models.EmailField() user_type=models.ForeignKey(to='UserType',to_field='id')
5.urls.py
from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^index/', views.index), url(r'^orm/', views.orm), ]
4.1 labels=None, # 提示信息
如果不想在Models原表中写verbose_name的话,可以在定义类的时候在ModelForm中写提示信息。
原来的效果:
现在也可以在modelform中写提示信息:labels是个字典格式,可以写多个。
4.2 help_texts=None, # 帮助提示信息
4.3 widgets=None, # 自定义插件以及样式。
4.4 错误信息 error_messages=None, # 自定义错误信息(整体错误信息from django.core.exceptions import NON_FIELD_ERRORS)
前端:
后台收集的错误信息:
错误信息的显示:
整体的错误信息也可以在这里用同样的方法定义,用的是__all__:{ }。 每一项的错误信息应该放到一个字典中。
4.5 field_classes=None # 自定义字段类 (也可以自定义字段)
我想把邮箱格式的正则表达式改为url的格式进行验证。
# 基于ModelForm方式来实现 from django.shortcuts import render,HttpResponse from app01 import models from django import forms from django.forms import fields as Ffields from django.forms import widgets as Fwidgets def orm(request): #models.UserType.objects.create(caption='Alex') return HttpResponse('orm') class UserInfoModelForm(forms.ModelForm): class Meta: model=models.UserInfo #指去哪个类里面去获取字段,以后也可以做增删改查。 fields='__all__' #代指的是所有的field字段 #fields=['username'] #还可以是一个列表,可以选择要展示哪几列,只展示username这一列 #exclude=['username'] #把username列排除在外了。 #labels={'username':'请填入用户名'} #help_texts={'username':'请把你的名字写对'} #widgets={'username':Fwidgets.Textarea(attrs={'class':'c1'})} error_messages={ '__all__':{}, 'email':{ 'required':'邮箱不能为空', 'invalid':'邮箱格式错误', } } field_classes={ 'email':Ffields.URLField #这里只能填类,不能加括号,加上括号就变成对象了。 } class UserInfoForm(forms.Form): username = Ffields.CharField(max_length=32) email=Ffields.EmailField() #user_type=fields.ForeignKey(to='UserType',to_field='id') user_type=Ffields.ChoiceField( choices=models.UserType.objects.values_list('id','caption') ) def __init__(self,*args,**kwargs): super(UserInfoForm,self).__init__(*args,**kwargs) self.fields['user_type'].choices=models.UserType.objects.values_list('id','caption') def index(request): if request.method=='GET': obj=UserInfoModelForm() return render(request,'index.html',{'obj':obj}) elif request.method=='POST': obj=UserInfoModelForm(request.POST) print(obj.is_valid()) print(obj.cleaned_data) print(obj.errors.as_json()) return render(request, 'index.html', {'obj': obj})
效果:
4.6 把时间本地化的时候,需要在setting里面进行一下当前时区的设置。
localized_fields
=
(
'birth_date'
,)
# 本地化,如:根据不同时区显示数据
如:
数据库中
2016
-
12
-
27
04
:
10
:
57
setting中的配置
TIME_ZONE
=
'Asia/Shanghai'
USE_TZ
=
True
则显示:
2016
-
12
-
27
12
:
10
:
57
4.7 切记 class Meta里面最容易犯的错误就是加逗号。千万不要加逗号
ModelForm的所有字段 a. class Meta: model, # 对应Model的哪个类,哪张表。 fields=None, # 字段 exclude=None, # 排除字段 labels=None, # 提示信息 help_texts=None, # 帮助提示信息 widgets=None, # 自定义插件 error_messages=None, # 自定义错误信息(整体错误信息from django.core.exceptions import NON_FIELD_ERRORS) field_classes=None # 自定义字段类 (也可以自定义字段) localized_fields=('birth_date',) # 本地化,如:根据不同时区显示数据 如: 数据库中 2016-12-27 04:10:57 setting中的配置 TIME_ZONE = 'Asia/Shanghai' USE_TZ = True 则显示: 2016-12-27 12:10:57 b. 验证执行过程 is_valid -> full_clean -> 钩子 -> 整体错误 c. 字典字段验证 def clean_字段名(self): # 可以抛出异常 # from django.core.exceptions import ValidationError return "新值" d. 用于验证 model_form_obj = XXOOModelForm() model_form_obj.is_valid() model_form_obj.errors.as_json() model_form_obj.clean() model_form_obj.cleaned_data e. 用于创建 model_form_obj = XXOOModelForm(request.POST) #### 页面显示,并提交 ##### # 默认保存多对多 obj = form.save(commit=True) # 不做任何操作,内部定义 save_m2m(用于保存多对多) obj = form.save(commit=False) obj.save() # 保存单表信息 obj.save_m2m() # 保存关联多对多信息 f. 用于更新和初始化 obj = model.tb.objects.get(id=1) model_form_obj = XXOOModelForm(request.POST,instance=obj) ... PS: 单纯初始化 model_form_obj = XXOOModelForm(initial={...})
五 第一个省事的地方是不用写字段了。第二个省事的地方是验证通过以后,用save方式就可以直接添加到数据库中了。
程序:
效果:
六,再新建一张表,做多对多的示例。
6.1 models.py
from django.db import models class UserType(models.Model): caption=models.CharField(max_length=32) class UserGroup(models.Model): name=models.CharField(max_length=32) class UserInfo(models.Model): #username = models.CharField(verbose_name='用户',max_length=32) username = models.CharField(max_length=32) email=models.EmailField() user_type=models.ForeignKey(to='UserType',to_field='id') u2g=models.ManyToManyField(UserGroup)
在usergroup表中新建几条数据
def orm(request): models.UserGroup.objects.create(name='CEO') models.UserGroup.objects.create(name='CFO') models.UserGroup.objects.create(name='COO') return HttpResponse('orm')
如下:
页面效果:发现多对多也显示出来了。
6.2 页面上新建然后保存数据
点击提交,就保存到数据库表中了。
多对多表中数据也增加了。
这个save的功能太强大了。
6.3 views.py
# 基于ModelForm方式来实现 from django.shortcuts import render,HttpResponse from app01 import models from django import forms from django.forms import fields as Ffields from django.forms import widgets as Fwidgets def orm(request): #models.UserGroup.objects.create(name='CEO') #models.UserGroup.objects.create(name='CFO') #models.UserGroup.objects.create(name='COO') return HttpResponse('orm') class UserInfoModelForm(forms.ModelForm): class Meta: model=models.UserInfo #指去哪个类里面去获取字段,以后也可以做增删改查。 fields='__all__' #代指的是所有的field字段 #fields=['username'] #还可以是一个列表,可以选择要展示哪几列,只展示username这一列 #exclude=['username'] #把username列排除在外了。 #labels={'username':'请填入用户名'} #help_texts={'username':'请把你的名字写对'} #widgets={'username':Fwidgets.Textarea(attrs={'class':'c1'})} error_messages={ '__all__':{}, 'email':{ 'required':'邮箱不能为空', 'invalid':'邮箱格式错误', } } #field_classes={'email':Ffields.URLField} class UserInfoForm(forms.Form): username = Ffields.CharField(max_length=32) email=Ffields.EmailField() #user_type=fields.ForeignKey(to='UserType',to_field='id') user_type=Ffields.ChoiceField( choices=models.UserType.objects.values_list('id','caption') ) def __init__(self,*args,**kwargs): super(UserInfoForm,self).__init__(*args,**kwargs) self.fields['user_type'].choices=models.UserType.objects.values_list('id','caption') def index(request): if request.method=='GET': obj=UserInfoModelForm() return render(request,'index.html',{'obj':obj}) elif request.method=='POST': obj=UserInfoModelForm(request.POST) if obj.is_valid(): obj.save() #print(obj.is_valid()) #print(obj.cleaned_data) #print(obj.errors.as_json()) return render(request, 'index.html', {'obj': obj})
七,obj.save()的拆分
查看源码可知,save包含两部分:
instance.save(当前这个model对象,意思就是可以把当前表save一下)
obj.save_m2m( ) save ManyToMany,其实就是把两步save拆开了。
7.1 测试 instance.save
测试效果:
7.2 小结:ModelForm可以帮我们生成HTML标签,也可以帮忙做验证,验证完了以后还可以直接保存在数据库中。
八,基于modelform实现添加数据的功能
models.UserInfo.objects.all().select_related('user_type','u2g') #跨表
8.1 添加user_list函数
# 基于ModelForm方式来实现 from django.shortcuts import render,HttpResponse from app01 import models from django import forms from django.forms import fields as Ffields from django.forms import widgets as Fwidgets def orm(request): #models.UserGroup.objects.create(name='CEO') #models.UserGroup.objects.create(name='CFO') #models.UserGroup.objects.create(name='COO') return HttpResponse('orm') class UserInfoModelForm(forms.ModelForm): class Meta: model=models.UserInfo #指去哪个类里面去获取字段,以后也可以做增删改查。 fields='__all__' #代指的是所有的field字段 #fields=['username'] #还可以是一个列表,可以选择要展示哪几列,只展示username这一列 #exclude=['username'] #把username列排除在外了。 #labels={'username':'请填入用户名'} #help_texts={'username':'请把你的名字写对'} #widgets={'username':Fwidgets.Textarea(attrs={'class':'c1'})} error_messages={ '__all__':{}, 'email':{ 'required':'邮箱不能为空', 'invalid':'邮箱格式错误', } } #field_classes={'email':Ffields.URLField} class UserInfoForm(forms.Form): username = Ffields.CharField(max_length=32) email=Ffields.EmailField() #user_type=fields.ForeignKey(to='UserType',to_field='id') user_type=Ffields.ChoiceField( choices=models.UserType.objects.values_list('id','caption') ) def __init__(self,*args,**kwargs): super(UserInfoForm,self).__init__(*args,**kwargs) self.fields['user_type'].choices=models.UserType.objects.values_list('id','caption') def index(request): if request.method=='GET': obj=UserInfoModelForm() return render(request,'index.html',{'obj':obj}) elif request.method=='POST': obj=UserInfoModelForm(request.POST) if obj.is_valid(): #obj.save()#这个save实现的时候,其实内部包含了2个步骤。可以拆开。 instance=obj.save(False) #什么也没干 instance.save() #只会保存当前这个类,而不会保存manytomany obj.save_m2m() #保存manytomany #print(obj.is_valid()) #print(obj.cleaned_data) #print(obj.errors.as_json()) return render(request, 'index.html', {'obj': obj}) def user_list(request): li=models.UserInfo.objects.all().select_related('user_type') #先把userinfo中的数据取出来 return render(request,'user_list.html',{'li':li})
user_list.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <ul> {% for row in li %} <li>{{row.username}}-{{row.user_type.caption}}</li> {% endfor %} </ul> </body> </html>
页面效果:
8.2 最终想要达到的效果:
程序粘贴:
models.py
from django.db import models class UserType(models.Model): caption=models.CharField(max_length=32) class UserGroup(models.Model): name=models.CharField(max_length=32) class UserInfo(models.Model): #username = models.CharField(verbose_name='用户',max_length=32) username = models.CharField(max_length=32) email=models.EmailField() user_type=models.ForeignKey(to='UserType',to_field='id') u2g=models.ManyToManyField(UserGroup)
views.py
# 基于ModelForm方式来实现 from django.shortcuts import render,HttpResponse from app01 import models from django import forms from django.forms import fields as Ffields from django.forms import widgets as Fwidgets def orm(request): #models.UserGroup.objects.create(name='CEO') #models.UserGroup.objects.create(name='CFO') #models.UserGroup.objects.create(name='COO') return HttpResponse('orm') class UserInfoModelForm(forms.ModelForm): class Meta: model=models.UserInfo #指去哪个类里面去获取字段,以后也可以做增删改查。 fields='__all__' #代指的是所有的field字段 #fields=['username'] #还可以是一个列表,可以选择要展示哪几列,只展示username这一列 #exclude=['username'] #把username列排除在外了。 #labels={'username':'请填入用户名'} #help_texts={'username':'请把你的名字写对'} #widgets={'username':Fwidgets.Textarea(attrs={'class':'c1'})} error_messages={ '__all__':{}, 'email':{ 'required':'邮箱不能为空', 'invalid':'邮箱格式错误', } } #field_classes={'email':Ffields.URLField} class UserInfoForm(forms.Form): username = Ffields.CharField(max_length=32) email=Ffields.EmailField() #user_type=fields.ForeignKey(to='UserType',to_field='id') user_type=Ffields.ChoiceField( choices=models.UserType.objects.values_list('id','caption') ) def __init__(self,*args,**kwargs): super(UserInfoForm,self).__init__(*args,**kwargs) self.fields['user_type'].choices=models.UserType.objects.values_list('id','caption') def index(request): if request.method=='GET': obj=UserInfoModelForm() return render(request,'index.html',{'obj':obj}) elif request.method=='POST': obj=UserInfoModelForm(request.POST) if obj.is_valid(): #obj.save()#这个save实现的时候,其实内部包含了2个步骤。可以拆开。 instance=obj.save(False) #什么也没干 instance.save() #只会保存当前这个类,而不会保存manytomany obj.save_m2m() #保存manytomany #print(obj.is_valid()) #print(obj.cleaned_data) #print(obj.errors.as_json()) return render(request, 'index.html', {'obj': obj}) def user_list(request): li=models.UserInfo.objects.all().select_related('user_type') #先把userinfo中的数据取出来 return render(request,'user_list.html',{'li':li}) def user_edit(request,nid): #获取当前id对应的用户信息 #显示用户已经存在的数据 if request.method=='GET': user_obj=models.UserInfo.objects.filter(id=nid).first() #获取对象 mf=UserInfoModelForm(instance=user_obj) #帮咱们生成标签 return render(request, 'user_edit.html',{'mf':mf,'nid':nid}) elif request.method=='POST': user_obj = models.UserInfo.objects.filter(id=nid).first() #获取对象 mf = UserInfoModelForm(request.POST,instance=user_obj) #instance传进来表示更新,不加的话表示新建了一条数据。 if mf.is_valid(): mf.save() else: print(mf.errors.as_json()) return render(request, 'user_edit.html', {'mf': mf, 'nid': nid})
user_edit.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form method="POST" action="/edit-{{nid}}/"> {% csrf_token %} {{mf.as_p}} <input type="submit" value="提交"/> </form> </body> </html>
user_list.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <ul> {% for row in li %} <li>{{row.username}}-{{row.user_type.caption}}-<a href="/edit-{{row.id}}/">编辑</a></li> {% endfor %} </ul> </body> </html>
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="/index/" method="POST"> {% csrf_token %} {{obj.as_p}} <input type="submit" value="提交"/> </form> </body> </html>
urls.py
from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^index/', views.index), url(r'^user_list/', views.user_list), url(r'^edit-(d+)/', views.user_edit), url(r'^orm/', views.orm), ]
8.3 补充
ModelForm:通过配置生成标签,用is_valid 进行验证,通过save进行保存。
ModelForm也可以自己定义钩子,与Form的用法一样。
在UserInfoModelForm中也可以定义新的字段。比如 username+password 可以从数据库中获取,但是像一个月内免登陆就不需要提交到数据库。像这个字段我们就可以在UserInfoModelForm中单独定义。
views.py
# 基于ModelForm方式来实现 from django.shortcuts import render,HttpResponse from app01 import models from django import forms from django.forms import fields as Ffields from django.forms import widgets as Fwidgets def orm(request): #models.UserGroup.objects.create(name='CEO') #models.UserGroup.objects.create(name='CFO') #models.UserGroup.objects.create(name='COO') return HttpResponse('orm') class UserInfoModelForm(forms.ModelForm): #自定义额外的字段,比如是否要保存一个月内免登陆。 is_remember=Ffields.CharField( widget=Fwidgets.CheckboxInput() ) class Meta: model=models.UserInfo #指去哪个类里面去获取字段,以后也可以做增删改查。 fields='__all__' #代指的是所有的field字段 #fields=['username'] #还可以是一个列表,可以选择要展示哪几列,只展示username这一列 #exclude=['username'] #把username列排除在外了。 #labels={'username':'请填入用户名'} #help_texts={'username':'请把你的名字写对'} #widgets={'username':Fwidgets.Textarea(attrs={'class':'c1'})} error_messages={ '__all__':{}, 'email':{ 'required':'邮箱不能为空', 'invalid':'邮箱格式错误', } } #field_classes={'email':Ffields.URLField} def clean_username(self): old=self.cleaned_data['username'] return old class UserInfoForm(forms.Form): username = Ffields.CharField(max_length=32) email=Ffields.EmailField() #user_type=fields.ForeignKey(to='UserType',to_field='id') user_type=Ffields.ChoiceField( choices=models.UserType.objects.values_list('id','caption') ) def __init__(self,*args,**kwargs): super(UserInfoForm,self).__init__(*args,**kwargs) self.fields['user_type'].choices=models.UserType.objects.values_list('id','caption') def index(request): if request.method=='GET': obj=UserInfoModelForm() return render(request,'index.html',{'obj':obj}) elif request.method=='POST': obj=UserInfoModelForm(request.POST) if obj.is_valid(): #obj.save()#这个save实现的时候,其实内部包含了2个步骤。可以拆开。 instance=obj.save(False) #什么也没干 instance.save() #只会保存当前这个类,而不会保存manytomany obj.save_m2m() #保存manytomany #print(obj.is_valid()) #print(obj.cleaned_data) #print(obj.errors.as_json()) return render(request, 'index.html', {'obj': obj}) def user_list(request): li=models.UserInfo.objects.all().select_related('user_type') #先把userinfo中的数据取出来 return render(request,'user_list.html',{'li':li}) def user_edit(request,nid): #获取当前id对应的用户信息 #显示用户已经存在的数据 if request.method=='GET': user_obj=models.UserInfo.objects.filter(id=nid).first() #获取对象 mf=UserInfoModelForm(instance=user_obj) #帮咱们生成标签 return render(request, 'user_edit.html',{'mf':mf,'nid':nid}) elif request.method=='POST': user_obj = models.UserInfo.objects.filter(id=nid).first() #获取对象 mf = UserInfoModelForm(request.POST,instance=user_obj) #instance传进来表示更新,不加的话表示新建了一条数据。 if mf.is_valid(): mf.save() else: print(mf.errors.as_json()) return render(request, 'user_edit.html', {'mf': mf, 'nid': nid})
效果:
九,总结
一,ModelForm => 可以做验证,可以做数据库操作。 Model+Form => 验证+数据库操作 -class LoginModelForm(XXXX): 利用model.A中的字段 1.生成html标签: class Meta:... 2.mf=xxxModelForm(instance=ModelObj) 3.额外的标签, 4.各种验证 is_valid()->各种钩子... 跟form的钩子一模一样,先进行每一个字段正则表达式验证,然后每一个字段的方法,然后进行clean,clean完了以后是post clean 5.mf.save() ############或者下面的############### instance=mf.save(False) instance.save() mf.save_m2m()