目录:Django其他篇

01:Django基础篇

02:Django进阶篇

03:Django数据库操作--->Model

04: Form 验证用户数据 & 生成html

05:ModelForm 数据验证 & 生成html & 数据库操作

06: Django Admin

07: Django 学习补充

目录:

1.1 ModelForm作用及基本使用返回顶部

  1、form 作用

      1功能1  验证

      2功能2  生成html标签(默认功能:保留上次提交的值)

      3、功能3:  数据操作

      4、功能4: HTML Form提交保留上次提交数据

      5、功能5: 初始化页面显示内容

  2、form使用原则

      1、 新url方式操作(一定要用form方式生成html,避免提交刷新页面,丢失当前页面中填的值)

      2、 发Ajax请求时可以不用form生成html标签,仅用form做验证,因为ajax请求本身不刷新页面,不必担心填

           的值会丢失,当然使用form生成html也是可以的

1.2 Meta中定义字段验证规则返回顶部

    注意: 导入模块名(fields、widgets)和字段名重复,所以导入时要起个别名。

from django import forms
from django.forms import fields as Ffields
from django.forms import widgets as Fwidgets
class UserInfoModelForm(forms.ModelForm): is_rmb = Ffields.CharField(widget=Fwidgets.CheckboxInput()) class Meta:
model = models.UserInfo
fields = '__all__'
# fields = ['username','email']
# exclude = ['username']
labels = {
'username': '用户名',
'email': '邮箱',
}
help_texts = {
'username': '...'
}
widgets = {
'username': Fwidgets.Textarea(attrs={'class': 'c1'})
}
error_messages = {
'__all__':{ # 整体错误信息 },
'email': {
'required': '邮箱不能为空',
'invalid': '邮箱格式错误..',
}
}
field_classes = { # 定义字段的类是什么
# 'email': Ffields.URLField # 这里只能填类,加上括号就是对象了。
} # localized_fields=('ctime',) # 哪些字段做本地化

Meta中可以定义的字段类型

1.3 ModelForm应用:编辑默认选中 及 提交自动保存返回顶部

  1、所有文件

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'^user_edit/(?P<nid>\d+)/', views.user_edit),
]

urls.py 路由系统

from django.db import models

class UserType(models.Model):
caption = models.CharField(max_length=32)
def __str__(self):
return self.caption class UserInfo(models.Model):
username = models.CharField(max_length=32)
email = models.EmailField()
user_type = models.ForeignKey(to='UserType', to_field='id')

models.py 定义表

from django.shortcuts import render,HttpResponse
from app01 import models
from app01.forms import UserInfoModelForm #1、创建UserInfo表中数据
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()
return render(request,'index.html',{'obj':obj}) #2、展示UserInfo表中数据
def user_list(request):
li = models.UserInfo.objects.all().select_related('user_type')
return render(request,'user_list.html',{'li':li}) #3、编辑默认选中 & 提交自动保存
def user_edit(request,nid):
if request.method == 'GET':
user_obj = models.UserInfo.objects.filter(id=nid).first()
mf = UserInfoModelForm(instance=user_obj) #只用传入instance点击编辑时就会默认选中
return render(request,'user_edit.html',{'mf':mf,'nid':nid})
elif request.method == 'POST': #ModelForm修改
user_obj = models.UserInfo.objects.filter(id=nid).first() # 如果这里没有传入 instance=user_obj就会变成ModelForm添加
mf = UserInfoModelForm(request.POST,instance=user_obj) #修改后数据要传递进去
if mf.is_valid():
mf.save()
else:
print(mf.errors.as_json())
return render(request,'user_edit.html',{'mf':mf,'nid':nid}) #################### 自动生成UserType 和 UserInfo 表中的数据 ############## usertype_list = [
{'caption':'python_group'},
{'caption':'linux_group'},
] userinfo_list = [
{'username':'zhangsan','email':'zhangsan@qq.com','user_type_id':1,},
{'username':'lisi','email':'lisi@qq.com','user_type_id':1,},
{'username':'wangwu','email':'wangwu@qq.com','user_type_id':1,},
] '''
for u_type in usertype_list:
models.UserType.objects.create(**u_type) for userinfo in userinfo_list:
models.UserInfo.objects.create(**userinfo)
'''

views.py 视图函数

from django.shortcuts import render,HttpResponse
from django import forms # 在ModelForm中有插件名widgets,所以这里引入插件时要取别名,否则报错
from django.forms import fields as Ffields
from django.forms import widgets as Fwidgets
from app01 import models class UserInfoModelForm(forms.ModelForm):
extraField = Ffields.CharField( widget=Fwidgets.CheckboxInput() ) #ModelForm中可以自定制额外字段
class Meta:
model = models.UserInfo #model指定关联那个类
fields = '__all__' labels = {
'username':'用户名',
'email':'邮箱',
} help_texts = {
'username':'username字段提示信息'
} widgets = {
'username':Fwidgets.Textarea(attrs={'class':'c1',})
} error_messages = {
'__all__':{}, #定义整体的错误信息
'email':{
'required':'邮箱不能为空',
'invalid':'邮箱格式错误',
}
} field_classes = {
# 'email':Ffields.URLField #改变字段格式为url
} localized_fields=('birth_date',)

forms.py 数据验证规则

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/index/" method="POST">
{% csrf_token %}
<p>{{ obj.username.label }}: {{ obj.username }} {{ obj.errors.username.0 }}</p>
<p>{{ obj.email.label }}: {{ obj.email }} {{ obj.errors.email.0 }}</p>
<p>{{ obj.user_type.label }}: {{ obj.user_type }} {{ obj.errors.user_type.0 }}</p>
<p>{{ obj.extraField.label }}: {{ obj.extraField }} {{ obj.errors.extraField.0 }}</p> <input type="submit" value="提交">
</form>
</body>
</html>

index.html生成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="/user_edit/{{ row.id }}/">编辑</a></li>
{% endfor %}
</ul>
</body>
</html>

user_list.html 展示数据

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form method="POST" action="/user_edit/{{ nid }}/">
{% csrf_token %}
{{ mf.as_p }}
<input type="submit" value="提交">
</form>
</body>
</html>

user_edit.html 编辑数据

   2、说明

      1. http://127.0.0.1:8000/index/  页面用来新建用户(在views.py中也有批量创建的for循环)

      2. http://127.0.0.1:8000/user_list/ 页面用来展示已创建用户,当点击编辑是会携带对应用户的id,已gett请求提交给user_edit

      3. http://127.0.0.1:8000/user_edit/1/ 这个路径携带有需要修改的用户id,实现编辑默认选中 及 提交自动保存

1.4 MordelForm中生成html & 数据验证 常用方法返回顶部

  1、生成HTML常用语法

      1、 obj.user.label                     标签显示内容(如:用户名)
            obj.user.label_tag

      2、 obj.user                            自动生成一个input标签,这种表自动保留上一次提交的数据功能

      3、 obj.errors.user.0              获取字段错误信息(提取到user字段)
            obj.errors                          所有字段错误信息的html字符串
            obj.user.errors                 错误信息(返回html标签)<ul class="errorlist"><li>用户名不能为空</li></ul>

      4、 obj.email.help_text          获取提示帮助信息(必须输入邮箱格式)

  4、ModelForm对象数据验证

    1. 用于验证

        model_form_obj = XXOOModelForm(request.POST)           # 将POST中提交的所有数据传给处理类(类中做校验)
        model_form_obj.is_valid()                                                # 类中对输入信息校验结果,符合返回True,否则返回False
        model_form_obj.clean()                                                   # 用户POST中所有正确信息,格式就是字典
        model_form_obj.cleaned_data

        model_form_obj.errors.as_json()                                     # 错误信息转换成json格式
        model_form_obj.errors                                                       # 所有错误信息的html字符串(ul li格式)

    2. 用于创建保存

        # 默认保存多对多
        obj = form.save(commit=True)

        # 不做任何操作,内部定义 save_m2m(用于保存多对多)
        obj = form.save(commit=False)
        obj.save()                                                 # 保存单表信息
        obj.save_m2m()                                       # 保存关联多对多信息

    4、新建数据 、修改数据、默认选中

        UserInfoModelForm(request.POST,instance=user_obj)           # 修改新旧数据都需要提交

        UserInfoModelForm(request.POST)                                        # 新建只需提交request.POST数据

        UserInfoModelForm(instance=user_obj)                                 # 只用传入instance点击编辑时就会默认选中 

    5. 验证执行过程
        is_valid -> full_clean -> 钩子 -> 整体错误

def clean_字段名(self):
# 可以抛出异常
# from django.core.exceptions import ValidationError
return "新值"

定义字段钩子

1.5 ModelForm验证规则中的内置钩子返回顶部

  1. from验证经历的顺序(搜索:Form and field validation

       验证执行过程:  is_valid -> full_clean -> 钩子 -> 整体错误

      1、拿到字段:用户发送一堆数据,根据form循环,拿到第一个字段

      2、正则匹配:先进行fields默认正则表达式判断,然后进行自定的正则表达式判断(如果有)

      3、字段钩子函数:然后执行字段的钩子函数,接着进行第二个字段,然后是第二个字段钩子函数...

      4、clean钩子函数:字段钩子函数执行完了再执行clean钩子函数进行整体验证

      5、_post_clean:     最后执行_post_clean钩子做其他验证

  2、 form验证的错误信息存放位置

      1、字段钩子错误信息放到对应的字段中 (obj.error中对应的字段字典)

      2、整体错误信息会放到 {"__all__":[],}中等价于{'NON_FIELD_ERRORS':[],} (如:执行clean)

  3、forms.py文件中使用这三种钩子

from django import forms
from django.forms import fields as Ffields
from django.forms import widgets as Fwidgets
from app01 import models
from django.core.exceptions import ValidationError class UserInfoModelForm(forms.ModelForm):
extraField = Ffields.CharField( widget=Fwidgets.CheckboxInput() ) #ModelForm中可以自定制额外字段
class Meta:
model = models.User #model指定关联那个类
fields = '__all__' labels = {
'name':'用户名',
'pwd':'密码',
} #1 clean_字段名 是字段钩子(每个字段都有对应的这个钩子):如判断:“用户名已存在”
def clean_user(self):
# self.cleand_data['user']是用户提交的数据'
c = models.User.objects.filter(name=self.cleand_data['user']).count()
if not c:
return self.cleand_data['user'] #必须要有返回值
else:
raise ValidationError('用户名已存在',code='xxx') #2 clean钩子对整体验证:如判断“用户名或密码错误”
def clean(self):
c = models.User.objects.filter(
name=self.cleand_data['user'],
pwd=self.cleand_data['pwd']).count()
if c:
return self.cleand_data #正确的值必须return回去
else:
raise ValidationError('用户名或密码错误') #3 在这里可以做 其他验证
def _post_clean(self):
pass

forms.py文件中使用这三种钩子

1.6 使用type动态生成ModelForm类进行数据验证、生成html返回顶部

from django.db import models

class User(models.Model):
username = models.CharField(max_length=32)
def __str__(self):
return self.username def default_form_validation(self):
''' 每个class_admin都可以重写这个方法来对整体验证'''

models.py创建表

from django.shortcuts import render
from app01 import models
from app01.forms import create_model_form def login(request):
model_form_class = create_model_form(request,models.User) form_obj = model_form_class() if request.method == 'POST':
obj = models.User.objects.get(id=1)
form_obj = model_form_class(instance=obj)
form_obj = model_form_class(request.POST,instance=obj)
if form_obj.is_valid():
form_obj.save()
else:
print('errors',form_obj.errors)
return render(request, 'loin.html',{'form_obj':form_obj})

views.py视图函数

from django.forms import ModelForm,ValidationError
from app01 import models def create_model_form(request,admin_class):
def __new__(cls,*args,**kwargs): # 重写ModelForm的__new__方法
'''
作用1--> 添加字段样式: class="form-control"
作用2--> 添加字段钩子: clean_字段名
'''
for field_name, field_obj in cls.base_fields.items():
# field_name : 字段名称,比如 "username"
# field_obj : 定义字段样式的类
field_obj.widget.attrs['class'] = "form-control" # 给所有字段添加样式:class="form-control" if hasattr(admin_class, "clean_%s" % field_name): # clean_字段名 是字段钩子(每个字段都有对应的这个钩子)
field_clean_func = getattr(admin_class, "clean_%s" % field_name)
setattr(cls, "clean_%s" % field_name, field_clean_func)
return ModelForm.__new__(cls) # 调用一下ModelForm的__new__方法否则不往下走 def default_clean(self): # 重写ModelForm的 default_clean 方法
'''添加默认钩子'''
error_list = [] # 在这个cleaned方法中定义一个允许用户自己定义的方法做验证
response = admin_class.default_form_validation(self)
if response:
error_list.append(response) if error_list:
raise ValidationError(error_list) class Meta: # ModelForm中使用Meta类进行条件过滤
model = models.User # model指定关联那个类
fields = "__all__" # 对那些字段过滤 labels = {
'username': '用户名',
} attrs = {'Meta':Meta} _model_form_class = type("DynamicModelForm",(ModelForm,),attrs) #创建类并设置Meta属性
setattr(_model_form_class,"__new__",__new__) #动态将__new__函数添加到类中
setattr(_model_form_class,'clean',default_clean) #动态将_default_clean__函数添加到类中 return _model_form_class

froms.py动态生成ModelForm类

1.7 ModelForm实例:不使用ModelForm生成html、并用ajax提交显示错误信息返回顶部

  相关知识点:

      1、不使用ModelForm生成html
      2、使用ajax提交数据,所以无法使用obj.errors.xxx 在前端显示错误信息
      3、使用json序列化ModelForm验证的错误信息
      4、使用ajax将错误信息放到对应位置

from django.shortcuts import render,HttpResponse
from django.utils import timezone
from django.core.exceptions import ValidationError import hashlib
import json from app01.models import User
from app01.forms import RegisterFrm class JsonCustomEncoder(json.JSONEncoder):
def default(self, field):
if isinstance(field, ValidationError):
return {'code':field.code,'messages':field.messages}
else:
return json.JSONEncoder.default(self, field) def register(request):
if request.method == 'POST':
if request.method == 'POST':
ret = {'status': False, 'error': None, 'data': None}
obj = RegisterFrm(request.POST)
if obj.is_valid():
cd = obj.cleaned_data
new_user = obj.save(commit=False) # 将密码md5加密后再存到数据库中
password2 = cd.get("password2")
m = hashlib.md5()
m.update(password2.encode())
new_user.password = m.hexdigest()
new_user.save()
ret['status']=True
return HttpResponse(json.dumps(ret))
else:
ret['error'] = obj.errors.as_data() # as_json() 返回的是字符串
request = json.dumps(ret, cls=JsonCustomEncoder)
return HttpResponse(request)
obj = RegisterFrm()
return render(request,'register.html',{'obj':obj}) # 登陆 : 这里没有做登录界面只有验证密码的函数
def login(request):
if request.method == 'POST':
login_name = request.POST.get("login_name")
password = request.POST.get("password")
if login_name and password:
# 将密码转md5
m = hashlib.md5()
m.update(password.encode())
password_md5 = m.hexdigest()
# 获取用户对象
user = User.objects.filter(login_name=login_name, password=password_md5).first()
if user:
print('用户密码正确')

views.py

from django.db import models

class User(models.Model):
login_name = models.CharField(max_length=32,unique=True,verbose_name="用户名",error_messages={'unique':"用户名已占用"})
password = models.CharField(max_length=32)
email = models.EmailField(unique=True,error_messages={'unique':'邮箱已注册'})
def __str__(self):
return self.login_name

models.py

from django import forms
from django.forms import fields
from app01.models import User class RegisterFrm(forms.ModelForm):
login_name = forms.CharField(
required=True,
error_messages={
'required': '用户名不能为空',
})
email = forms.EmailField(
error_messages={
'required': '邮箱不能为空',
'invalid':'邮箱格式错误'
})
password = forms.CharField(
widget=forms.PasswordInput,
label="密码",
error_messages={
'required': '密码不能为空',
})
password2 = forms.CharField(
widget=forms.PasswordInput,
label="确认密码",
error_messages={
'required': '确认密码不能为空',
}) class Meta:
model = User
fields = ("login_name", "password", "email") def clean_login_name(self):
"""login_name里不允许有空格"""
cd = self.cleaned_data
login_name = cd.get("login_name").strip()
if " " in login_name:
raise forms.ValidationError("用户名不能有空格")
return login_name def clean_password2(self):
"""两次密码是否一致"""
cd = self.cleaned_data
if cd['password'] != cd['password2']:
raise forms.ValidationError('确认密码不一致')
return cd['password2']

forms.py

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div class="reg_frm fl">
<h1>注册{{ obj.errors }}</h1>
<form id="register_frm">
<table>
<tr>
<th>用户名</th>
<td><input type="text" id="login_name" name="login_name"></td>
<td class="tips">{{ obj.login_name.errors.0 }}</td>
</tr>
<tr>
<th>邮箱</th>
<td><input type="email" id="email" name="email"></td>
<td class="tips">{{ obj.email.errors.0 }}</td>
</tr>
<tr>
<th>密码</th>
<td><input id="password" type="password" name="password" autocomplete="off" minlength="3"></td>
<td class="tips">{{ obj.password.errors.0 }}</td>
</tr>
<tr>
<th>确认密码</th>
<td><input id="password2" type="password" name="password2" autocomplete="off" minlength="3"></td>
<td class="tips"></td>
</tr>
</table>
<p><input type="button" value="ajax提交" onclick="ajaxSubmit();"></p>
</form>
</div>
<script src="/static/jquery-1.12.4.min.js"></script>
<script>
function ajaxSubmit() {
$.ajax({
url:'/register/',
data:$('#register_frm').serialize(),
type:'POST',
dataType:'json',
success:function(arg){ //服务端返回的是字符串格式
if(arg.status==true){
console.log('成功创建用户后的操作')
}else {
var check_list = {
'login_name':'用户名',
'email':'邮箱',
'password':'密码',
'password2':'确认密码'
};
for(var key in check_list){
$('#'+key).parent().parent().find('.tips').text('');
var err_val = "arg.error." + key +"[0].messages";
try{
var err = eval(err_val);
$('#'+key).parent().parent().find('.tips').text(err)
}catch (err){
console.log(err.message);
}
}
}
}
})
}
</script>
</body>
</html>

register.html

05:ModelForm 数据验证 & 生成html & 数据库操作的更多相关文章

  1. 手把手封装数据层之DataUtil数据库操作的封装

    上一篇我们写完了数据库连接的封装 没有看的请移步上一篇关于数据库连接的内容 这次我们讲数据库操作的封装.数据库的操作就是增删改查:心再大一点就可以直接分为查询和其他. 因为查询是有返回对象的,而其他都 ...

  2. Android数据读取之Sqlite数据库操作

    咱们书接上文,继续来说说Android数据读取,这回,我们要讲的是Sqlite数据库的相关操作.以一个实例开始吧: 首先,上图,看看做成后的效果: 大概描述:类似于浏览器的收藏夹,网站名称,网站地址, ...

  3. android菜鸟学习笔记20----Android数据存储(四))Android数据库操作

    Android内置了一个名为SQLite的关系型数据库,这是一款轻量型的数据库,操作十分简便.SQLite与别的数据库不同的是,它没有数据类型.可以保存任何类型的数据到你所想要保存的任何表的任何列中. ...

  4. Effective C++ .05 一些不自动生成copy assigment操作的情况

    主要讲了 1. 一般情况下编译器会为类创建默认的构造函数,拷贝构造函数和copy assignment函数 2. 执行默认的拷贝构造/copy assignment函数时,如果成员有自己的拷贝构造/c ...

  5. 03: Django Model数据库操作

    目录:Django其他篇 01:Django基础篇 02:Django进阶篇 03:Django数据库操作--->Model 04: Form 验证用户数据 & 生成html 05:Mo ...

  6. python 学习笔记十六 django深入学习一 路由系统,模板,admin,数据库操作

    django 请求流程图 django 路由系统 在django中我们可以通过定义urls,让不同的url路由到不同的处理函数 from . import views urlpatterns = [ ...

  7. 结合java的反射和泛型性质简化JDBC和相应的同步等服务器数据库操作代码

    github地址:https://github.com/hzphzp/HeartTrace_Server 我们的服务器端数据库并没有用sqllite, 而是直接用mysql,并且用JDBC直接进行操作 ...

  8. PHP 生成 MySql 数据库字典

    项目说明 通过配置 MySql 数据库信息,使用 PHP 生成数据表字典可以输出在当前页面,可以生成文件保存在指定位置,也可以下载格式支持网页HTML格式.CSV格式(Excel 读取).ZIP压缩格 ...

  9. JSP中的数据库操作,MySQL基础操作(一)

    一.JDBC JDBC(java data base concectivity),是一种用于执行SQL语句的java API,可以为多种关系库提供统一访问. 通常使用JDBC完成以下操作: 1)同数据 ...

随机推荐

  1. 在ubuntu下安装使用latex

    参考:https://www.cnblogs.com/longdouhzt/archive/2012/09/27/2706358.html https://jingyan.baidu.com/albu ...

  2. Invalid HTTP_HOST header: 'xxx.xx.xxx.xxx:8000'. You may need to add 'xxx.xx' to ALLOWED_HOSTS

    Invalid HTTP_HOST header: 'xxx.xx.xxx.xxx:8000'. You may need to add 'xxx.xx' to ALLOWED_HOSTS - buk ...

  3. Linux下缓冲区溢出攻击的原理及对策

    前言 从逻辑上讲进程的堆栈是由多个堆栈帧构成的,其中每个堆栈帧都对应一个函数调用.当函数调用发生时,新的堆栈 帧被压入堆栈:当函数返回时,相应的堆栈帧从堆栈中弹出.尽管堆栈帧结构的引入为在高级语言中实 ...

  4. Jmeter(十五)_上传与下载

    今天重点说一下Jmeter的上传与下载 1:Jmeter上传文件 首先确认你的文件名称,参数名称,MIME类型,这些可以从接口文档里面获取,或者直接在页面抓包然后从请求头里面查看.注意,此处我的文件路 ...

  5. 虚拟机linux centoros系统安装

    (一) 系统下载地址:https://www.centos.org/download/ (二) 下载安装:vmware.并安装. (三) 虚拟机的安装: 1.创建新的虚拟机 2.选择自定义,下一步 3 ...

  6. HTTP 协议详解(转载)

    原文: http://kb.cnblogs.com/page/130970/#httpmeessagestructe HTTP协议详解 当今web程序的开发技术真是百家争鸣,ASP.NET, PHP, ...

  7. 7.MQTT网页客户端连接MQTT服务器的问题WebSocket connection to 'ws://XXX:1883/' failed: Connection closed before receiving a handshake response

    问题描述:MQTT.js提供了连接MQTT的一套javascipt的方法,可供前端连接到MQTT服务器,也可以作为脚本测试.以脚本形式,用nodejs运行,是没有问题的,能够正常连接并且发送报文.但是 ...

  8. 30 段 JavaScript 代码

    1. 前端人员经常遇到的问题就是如何区分IE及非IE浏览器,JavaScript代码是: if(!+[1,]) { //IE11不支持 alert('这是IE浏览器'); }else{ alert(' ...

  9. 为什么GPU可以用于科学计算【转载】

    转自:https://blog.csdn.net/xihuanyuye/article/details/81178352 https://www.zhihu.com/question/35063258 ...

  10. Ubuntu 16.04下deb文件的安装

    pkg 是Debian Package的简写,是为Debian 专门开发的套件管理系统,方便软件的安装.更新及移除.所有源自Debian的Linux发行版都使用dpkg,例如Ubuntu.Knoppi ...