举个基于类的views的例子
在views里
from django.views import View
class AddPublisher(View):
def get(self,request):
# get请求hr@qutke.com
return response
def post(self,request):
# post请求
return response
在url里的路径
url(r'^add_publisher/', views.AddPublisher.as_view()),
1). 程序启动的时候,就执行as_view() 定义view函数并返回
2). 请求到来的时候,执行父类里面的view函数:
(1). 实例化当前的类 ——》 self
(2). self.request = request
(3). 执行self.dispatch的方法:
3.1. 判断请求方式是否别允许:
3.1.1. 允许 通过反射拿到对用请求方式的方法 —— 》 handler
3.1.2. 不允许 self.http_method_not_allowed ——》 handler
3.2. 执行handler 得到 HttpResponse对象 返回
定义一个timer装饰器
FBV : 直接加在函数上
CBV : from django.utils.decorators import method_decorator
@method_decorator(timer)
def get(self, request):
@method_decorator(timer)
def dispatch(self, request, *args, **kwargs):
ret=super().dispatch(request,*args,**kwargs) #调用父类方法
return ret
(1)指定给谁加上
@method_decorator(timer,name='post')
@method_decorator(timer,name='get')
class AddPublisher(View):
(2)要是这种的话,就不用写dispatch方法了,他会加在父类的方法上
@method_decorator(timer,name='dispatch')
class AddPublisher(View):
没什么区别,主要区别在于装饰器里的args,func上
1) 不使用method_decorator:
Args (<app01.views.AddPublisher object at 0x03B465B0>, <WSGIRequest: GET ‘/add_publisher/‘>)
Func :func函数,取值,对应得request是第二个值(就是取值不太方便)
2) 使用method_decorator:
Args 是 (<WSGIRequest: GET ‘/add_publisher/‘>,)
Func :bondfunc 绑定函数,取值的话第一个值对应得是request对象
1)属性
request.method #请求方式 POST GET :类型是字符串
request.GET #是url地址上的参数,不是get带的参数
request.POST #form表单用户提交POST请求的数据
#request.POST.get(‘name’) #得到数据(返回值,get()是字典形式)*
request.FILES # 上传的文件
request.path_info # 路径 不包含IP和端口 参数
print(request.path_info,type(request.path_info)) 结果:/index/ <class 'str'>
request.body # 请求体 请求数据 get没有请求体
结果:get b’ ‘ 是空的,post ’ b’ czc…name=’’’里面有内容
Request.META #请求头的信息
Request.COOKIES: #一个标准的python字典
Request.session: #一个既会读又课写的类似于字典的形象,表示当前会话
以上的必须记住
Request.scheme 协议 http https 结果是http 类型是字符串
Request.encoding:表示提交数据的编码方式,如果为None,则default_charset=’utf-8’
2)方法
Request.get_full_path() #路径 不包含ip和端口 包含参数
Request.is_ajax() #判断是否是ajax请求
Request.host() #获取主机的ip和端口
1) form 表单里写上编码方式
enctype="multipart/form-data"
2) 要是POST请求,在模板里要写上 {% csrf_token%}
3) request.FILES 打印结果是字典
request.FILES.get(‘s19’) 获取值, 文件在内存里
4) chunks:意思是一片一片的传
这是一个上传下载文件的代码:
在views里
def upload(request):
if request.method=='POST':
print(request.POST)
f1 = request.FILES.get('s19')
print(f1,type(f1))
with open(f1.name,'wb')as f: #把文件写进去,字节形式
for chunk in f1.chunks():
f.write(chunk)
return render(request,'upload.html')
在模板里
<form action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
文件 <input type="file" name="s19">
<button>上传</button>
</form>
HttpResponse('字符串') ——》 返回的字符串
render(request,'模板的文件名',{k1:v1}) ——》 返回一个完整的HTML页面
redirect(要跳转的地址) —— 》重定向 Location :地址
jsonresponse
Jsonresponse 传输字典类型的,要想传输其他类型,加上safe=False
from django.http.response import JsonResponse
JsonResponse(data) # Content-Type: application/json
JsonResponse(data,safe=False) # 传输非字典类型
举个例子
import json
from django.http.response import JsonResponse
def json_data(request):
date={'name':'alex','age':30}
# return HttpResponse(date) #得到的是字典的键
ret = HttpResponse(json.dumps(date))
ret['Content-Type']='application/json'
return ret #{'name':'alex','age':30}
# Content-Type: text/html; charset=utf-8
# return JsonResponse(date) #{'name':'alex','age':30}
# Content-Type: application/json
return JsonResponse(li,safe=False)
2.分组 ( )
url(r'^blog/([0-9]{4})/([0-9]{2})/$', views.blog),
分组的结果会当做位置参数 ——》 传递给视图函数
def blog(request,name,aa):
return HttpResponse('ok')
3.命名分组 (?P
url(r'^blog/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.blog),
?分组的结果会当做关键字参数 ——》 传递给视图函数
def blog(request,year,month):
print(year,month)
return HttpResponse('ok')
4.include 路由分发
先匹配一级目录,在匹配二级目录 (多个app的时候)
from django.conf.urls import url,include
from app01 import views
urlpatterns = [
url(r'^app01/', include('app01.urls')),
url(r'^app02/', include('app02.urls')),
]
传递额外的参数给视图函数
注:要是命名函数的名字和参数的键同名,那命名函数名字的值就是参数的值
url(r'^blug/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/',views.blug,{'foo':'v1'})
def blug(request,year,month,**kwargs):
print(year,month)
print(kwargs)
return HttpResponse('ok')
5. URL命名和反向解析
静态地址
1)命名
url(r'^blog/$', views.blogs, name='xxxx'),
url(r'^home/',views.home)
使用:
?
在模板
? {% url ‘xxxx‘ %} ——》 ‘/blog/‘ 一个完整的URL
或是在py文件
? from django.urls import reverse
? reverse(‘xxxx‘) ——》 ‘/blog/
2)命名分组
url(r'^blog/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.blog,name='blog' ),
使用:
?
在模板
? {% url ‘blog‘ ‘2019’ ‘12’ %} ——》 ‘/blog/2019/12/‘ 一个完整的URL 位置传参
? {% url ‘blog‘ month=‘09‘ year=‘2016‘ %} ‘/blog/2016/09/‘ 关键字传参
? 在py文件
? from django.urls import reverse
? reverse(‘blog‘,args=(‘2018‘,‘02‘)) ——》 ‘/blog/2018/02‘
reverse(‘blog‘, kwargs={‘year‘: ‘2020‘, ‘month‘: ‘03‘}) ——》 /blog/2020/03
namespace 在多个app下有相同的方法,用‘namespace:name‘便于区分
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^app01/', include('app01.urls',namespace='app01')),
url(r'^app02/', include('app02.urls',namespace='app02')),
]
使用:
在模板
{% url 'namespace:name' 参数 %}
在py文件
reverse( 'namespace:name' ,arrgs=(),kwargs={} )
LANGUAGE_CODE = ‘zh-Hans‘ 改成中文
1. 创建超级用户
python manage.py createsuperuser
用户名和密码 密码 数字+字母+至少8位
2. 注册model
在app下的admin.py中写
from app01 import models
admin.site.register(models.Person)
3. 访问 http://127.0.0.1:8000/admin/
对象关系映射(Object Relational Mapping,简称ORM)模式是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术。
ORM的操作:
类 —— 》 表
对象 —— 》 数据(记录)
属性 —— 》 字段
models.User.objects.all() # 所有数据 对象列表
models.User.objects.get(username='alex') # 获取一个满足条件的对象 没有数据 或者 多条数据就报错
models.User.objects.filter(username='alex1') # 获取满足条件的所有对象 对象列表1) 对应关系
class Student(models.Model)
models.CharField (max_length=32) # varchar(32)
models.AutoField (primary_key=True) #自增字段 pk主键
models.ForeignKey (‘Publisher’,on_delete=models.CASCADE) #publisher是所管连的表的类名(可以是字符串的形式)
models.CASCADE 是级联删除
default=’男’
on_delete=models.SET_DEFAULT 是设置默认值
SET_NULL是设置为空
SET(value)
on_delete:所关联的表删除后,对这个表所做的操作
django1.11版本之前的不用填写 默认是on_delete=models.CASCADE
django2.0版本之后就是必填项
常用的字段
?????????AutoField :自增字段 自增的整形字段,必填参数primary_key=True,则成为数据库的主键。无该字段时,django自动创建。
一个model不能有两个AutoField字段。
?????????AutoFieldIntegerField: 一个整数类型。数值的范围是?-2147483648 ~ 2147483647。
?????????AutoFieldCharField: 字符类型
?????????AutoFieldDateField ; 日期类型
参数:
auto_now:每次修改时修改为当前日期时间。
auto_now_add:新创建对象时自动添加当前日期时间。每次修改时,时间不变
auto_now和auto_now_add和default参数是互斥的,不能同时设置。
?????????AutoFieldDatetimeField : 日期时间字
????????AutoFieldBooleanField : - 布尔值类型
????????AutoFieldNullBooleanField 可以为空
????????AutoFieldTextField- 文本类型
????????AutoFieldFloatField:浮点型
????????AutoFieldDecimalField 10进制小数
1). null = Ture 数据库中可以为空
2). blank = Ture 表单中可以为空
3). db_column 修改数据库中字段的列名
4). default 默认值
5) unique=True 唯一
6) verbose_name=’名字’ ?Admin中显示的字段名称中文提示
7) choices Admin中显示选择框的内容可供选择的值 gender=models.BooleanField(‘性别‘,default=False,choices=((0,‘男‘),(1,‘女‘)))
8) help_text=‘请输入正确年龄‘ ?Admin中该字段的提示信息
class MyCharField(models.Field):
"""
自定义的char类型的字段类
"""
def __init__(self, max_length, *args, **kwargs):
self.max_length = max_length
super(MyCharField, self).__init__(max_length=max_length, *args, **kwargs)
def db_type(self, connection):
"""
限定生成数据库表的字段类型为char,长度为max_length指定的值
"""
return 'char(%s)' % self.max_length
使用:用自定义的类名 phone = MyCharField(max_length=11,)
Class Mate类是固定写法,是给上边的类做的标配
class Person(models.Model):
pid = models.AutoField(primary_key=True)
name = models.CharField(max_length=32, db_column='username', unique=True, verbose_name='姓名') # varchar(32)
class Meta:
# 数据库中生成的表名称 默认 app名称 + 下划线 + 类名
db_table = "person"
# 排序
ordering = ('pk',)
# 联合索引
index_together = [
("name", "age"),
]
# 联合唯一索引
unique_together = (("name", "age"),)
下图是该名字,改变后,名字变了,内容不变
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "orm_practice.settings")
import django
django.setup()
from app01 import models
返回的是对象列表 (8)
all 获取表中所有的数据 ——》 对象列表 QuerySet
filter # 获取表中满足条件的所有数据 ——》 对象列表 QuerySet
exclude 获取表中不满足条件的所有数据 ——》 对象列表 QuerySet
order_by 对已经排好序的结果进行倒序 ——》 对象列表 QuerySet
排序 默认升序 字段加- 降序 多个字段 ——》 对象列表 QuerySet
models.Person.objects.all().order_by('-age', 'pk'),先按第一个字段排,要是有两个一样的,按第二个排
reverse 翻转
ret = models.Person.objects.all().order_by('pk').reverse()
values 获取数据的字段名和对应的值 ——》 对象列表 QuerySet [{} ,{}]字典
# 不填写参数 获取所有字段名字和值 obj=models.Person.objects.values()
# 填写参数 获取指定字段名字和值 obj=models.Person.objects.values('name',’age’)
values_list
获取数据的字段对应的值 ——》 对象列表 QuerySet [() ,()] 元祖
# 不填写参数 获取所有字段值
# 填写参数 获取指定字段值 有顺序
distinct 去重 所有字段都一样才去重
返回的是对象 (3)
get # 获取一条数据 ——》 对象 获取不到或者多条就报错
first 取第一个元素 没有元素 None
last 取最后一个元素 没有元素 None
返回布尔值 (1)
exists 判断是否存在 models.Person.objects.filter(name='alex').exists()
返回数字 (1)
count 计数
ret = models.Person.objects.filter(pk=1)
ret = models.Person.objects.filter(pk__gt=1) # greater than 大于
ret = models.Person.objects.filter(pk__lt=3) # less than 小于
ret = models.Person.objects.filter(pk__gte=1) # greater than equal 大于等于
ret = models.Person.objects.filter(pk__lte=3) # less than equal 小于等于
ret = models.Person.objects.filter(pk__range=[1, 3]) # 范围 左右都包含
ret = models.Person.objects.filter(pk__in=[1, 5]) # in 只要1和5
ret = models.Person.objects.filter(name__contains='alex') # like 完全包含
ret = models.Person.objects.filter(name__icontains='ale') # like 忽略大小写 ignore
ret = models.Person.objects.filter(name__startswith='a') # 以a开头
ret = models.Person.objects.filter(name__istartswith='a') # 以a开头忽略大小写
ret = models.Person.objects.filter(name__endswith='a') # 以a开头
ret = models.Person.objects.filter(name__iendswith='g') # 以a开头忽略大小写
ret = models.Person.objects.filter(phone__isnull=True) # phone字段为空
ret = models.Person.objects.filter(phone__isnull=False) # phone字段不为空
ret = models.Person.objects.filter(birth__year=2019)
ret = models.Person.objects.filter(birth__contains='2019-04-09') 包含,相当于like
# ret = models.Person.objects.filter(birth__month=4)
1)基于对象的查询
正向查询
book_obj = models.Book.objects.get(pk=1)
# print(book_obj.publisher) # 书籍所关联的对象
# print(book_obj.publisher.name) # 书籍所关联的对象的名字
# print(book_obj.publisher_id) # 书籍所关联的对象的ID
反向查询
pub_obj = models.Publisher.objects.get(pk=1)
# 外键中 不指定related_name pub_obj.表名小写_set 关系管理对象
# print(pub_obj.book_set,type(pub_obj.book_set)) # 表名小写_set 关系管理对象
# print(pub_obj.book_set.all())
# 外键中 指定related_name='books' pub_obj.books 关系管理对象
# print(pub_obj.books,type(pub_obj.books)) # 表名小写_set 关系管理对象
**2)基于字段的查询 外键名__name=’ ’ 跨表查询**
查询人民出版社出版的所有书籍
ret = models.Book.objects.filter(publisher__name='人民出版社')
查询丰乳肥臀的出版社
不指定 related_name 跨表时使用 表名小写__字段
# ret = models.Publisher.objects.filter(book__title='丰乳肥臀')
# 指定 related_name='books' 跨表时使用books__字段
# ret = models.Publisher.objects.filter(books__title='丰乳肥臀')
# 指定 related_name='books' related_query_name='book' 跨表时使用book__字段
ret = models.Publisher.objects.filter(book__title='丰乳肥臀')
# print(ret)
print(pub_obj.books.all())
基于对象的查询
author_obj.books ——》 关系管理对象
author_obj.books.all() ——》 关系管理对象
不指定related_name
book_obj.author_set ——》 关系管理对象
book_obj.author_set.all() ——》 作者写过所有的书籍对象
指定related_name=’authors‘
book_obj.authors——》 关系管理对象
book_obj.authors.all() ——》 作者写过所有的书籍对象
管理对象的方法
all 获取所有的对象
set 设置关系 多对多 [ id,id ] [对象,对象] 一对多 [对象]
add 添加关系 多对多 id,id 对象,对象 一对多 对象
remove 删除关系 一对多:必须设置外键可为空,才有remove clear方法
clear 清空所有的关系
create 创建一个对象并且添加关系
`book_obj.authors.create(name='xxxx') `
pub_obj.books.set(models.Book.objects.filter(pk__in=[3])) # 设置关系 【对象 】
pub_obj.books.add(*models.Book.objects.filter(pk__in=[4])) # 添加关系 对象
pub_obj.books.remove(*models.Book.objects.filter(pk__in=[3])) # 删除关系 对象 外键 null=True
pub_obj.books.clear() # 删除关系 对象 外键 null=True
分组 注释: annotate
所获取的是对象列表[{ },{ }]
例:
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "orm_practice.settings")
import django
django.setup()
from app01 import models
from django.db.models import Max, Min, Count, Avg, Sum
方式一:
ret = models.Publisher.objects.annotate(min=Min('book__price')).values()
方式二
ret = models.Book.objects.values('publisher__name').annotate(min=Min('price')) #对象列表{}
for i in ret:
print(i)
from django.db.models import F, Q
F查询 比较两个字段
ret=models.Book.objects.filter(sale__gt=F('kucun')) update(sale=F(‘sale’)*2)
Q 查询 |或 ;& 与 ;~ 非
Filter(Q(pk_gt=5)) == Q((‘ss’,kk))
定义:cookie就是保存在浏览器本地的一组组键值对
特性:
为什么要有cookie?
HTTP协议是无状态的,每次请求都是没关系的,没办法保存,状态,使用cookie保存状态
django的操作:
设置 本质: 响应头 set-cookie
ret = redirect(‘/home/‘) #响应对象
ret.set_cookie(‘is_login‘, ‘1‘) # 普通的cookie max_age=5设置时间 path domain
#ret.set_signed_cookie(key=‘is_login‘,value= ‘1‘, salt=‘day62‘) # 加密的cookie
参数:
max_age=5设置时间,
path=‘/‘, Cookie生效的路径,/ 表示根路径,特殊的:根路径的cookie可以被任何url的页面访问domain=None, Cookie生效的域名
获取 本质:请求头cookie
request.COOKIES[key] {} # 普通的cookie删除
ret = redirect(‘/login/‘)
ret.delete_cookie(‘is_login‘)
session 当做字典使用
定义: 保存在服务器上一组组键值对,必须依赖于cookie。
为什么要使用session?(特性)
django中操作session
设置
request.session[key] = value获取
request.session[key]删除
del request.session[‘k1‘]
request.session.delete() # 删除所有的session数据 不删除cookie
request.session.flush() # 删除所有的session数据 删除cookie
request.session.exists("session_key") #检查会话session的key在数据库中是否存在
其他:
request.session.set_expiry(10) #设置超时时间,但是数据库的session不会删
通过request.session.clear_expired() # 清除已过期的数据
配置: 了解
from django.conf import global_settings
#数据库Session
SESSION_ENGINE = 'django.contrib.sessions.backends.db' # 引擎(默认)
#缓存Session
SESSION_ENGINE = 'django.contrib.sessions.backends.cache' # 引擎
#文件Session
SESSION_ENGINE = 'django.contrib.sessions.backends.file'
SESSION_COOKIE_AGE = 1209600 设置失效时间的
SESSION_COOKIE_PATH = "/" # Session的cookie保存的路径(默认)
SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名(默认)
SESSION_COOKIE_SECURE = False # 是否Https传输cookie(默认)
SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http传输(默认)
本质上就是python中的类
使用:
在app01下新建一个middlewares文件夹,在里面新建一个py文件
from django.utils.deprecation import MiddlewareMixin
在setting里添加配置
1)官方的说法:中间件是在全局范围内一个用来处理Django的请求和响应的框架级别的钩子
2) 五种方法:(执行时间、执行顺序、参数、返回值)
process_request(self,request)
执行时间:
?视图函数执行之前(请求到来后,路由匹配前)
执行顺序:
?按照注册的顺序 顺序执行
参数:
?request - 和视图中的request对象是同一个
返回值:
?None: 正常流程
?HttpResponse对象: 后面的中间件的process_request方法、视图都不执行,直接执行当前中间件的process_response方法,再返回给浏览器
process_response(self, request, response)
执行时间:
?视图函数执行之后
执行顺序:
?按照注册的顺序 倒序执行
参数:
?request - 和视图中的request对象是同一个
?response - 视图函数返回的响应对象
返回值:
HttpResponse对象: 必须返回
process_view(self, request, view_func, view_args, view_kwargs)
执行时间:
?在process_request方法后,路由匹配之后,视图函数执行之前
执行顺序:
?按照注册的顺序 顺序执行
参数:
?request - 和视图中的request对象是同一个
?view_func - 视图函数
?view_args - 给视图使用的位置参数
?view_kwargs - 给视图使用的关键字参数
返回值:
?None: 正常流程
?HttpResponse对象: 后面的中间件的process_view方法、视图都不执行,直接执行最后一个中间件的process_response方法,再返回给浏览器
process_exception(self, request, exception)
执行时间(触发的条件):
? 视图函数执行之后,视图有异常时才执行
执行顺序:
? 按照注册的顺序 倒序执行
参数:
? request - 和视图中的request对象是同一个
? exception - 错误的对象
返回值:
? None: 正常流程 ,交给下一个中间件处理异常,都返回的是None,交给django处理异常(大黄页)
? HttpResponse对象: 后面的中间件的process_exception方法不执行,直接执行最后一个中间件的process_response方法,再返回给浏览器
process_template_response(self,request,response)
执行时间(触发条件):
? 视图函数执行之后,要求视图函数返回的对象是TemplateResponse对象
执行顺序:
? 按照注册的顺序 倒序执行
参数:
? request - 和视图中的request对象是同一个
? response - 视图函数返回的响应对象
返回值:
? HttpResponse对象: 必须返回
csrf_exempt # 当前的视图不需要CSRF校验
csrf_protect # 当前的视图需要CSRF校验
from django.views.decorators.csrf import csrf_exempt, csrf_protect
from django.views.decorators.csrf import ensure_csrf_cookie
@ csrf_exempt
def login(request) 普通函数直接加
CBV中 csrf_exempt只能加在dispatch上或是类上
@method_decorator(csrf_exempt,name='dispatch')
JSON 简单的语法格式和清晰的层次结构明显要比 XML 容易阅读,并且在数据交换方面,由于 JSON 所使用的字符要比 XML 少得多,可以大大得节约传输数据所占用得带宽。
(Asynchronous Javascript And XML)翻译成中文就是“异步的Javascript和XML”,
AJAX 不是新的编程语言,而是一种使用现有标准的新方法
定义: 是一个js的技术,发送请求的一种途径。
特点:
发请求的途径:
简单实例 固定格式
$.ajax({
url:'/calc/',
type:'post',
data:{
i1:$('[name="i1"]').val(),
i2:$('[name="i2"]').val(),
},
success:function (res) {
$('[name="i3"]').val(res)
}
})
参数
$.ajax({
url: '/ajax_test/', # 请求的地址
type: 'post', # 请求的方式
data: { # 请求的数据
name: 'alex',
age: 73,
hobby: JSON.stringify(['装逼', '作死', '卖烧饼']) #将对象转成字符串
},
success: function (res) { # 成功后执行的函数
location.href=地址 重定向 #返回时不要redirect了
},
error: function (res) { # 失败后执行的函数
console.log(res)
},
})
ret=json.loads(ret)
print(ret,type(ret)) #<class ‘list‘>
ajax上传文件
<script src="/static/ajax_setup.js"></script>
数据交换的格式
Python
? 数据类型: 数字 字符串 列表 字典 布尔值 None
? 转化:
? 序列化 Python的类型 ——》 json的字符串
? json.dumps(Python的类型)
? json.dump(Python的类型, f )
? 反序列化 json的字符串 ——》 Python的类型
? json.loads( json的字符串)
? json.load(f )
js
? 数据类型: 数字 字符串 列表 字典 布尔值 null
? 转化:
? 序列化 js的类型 ——》 json的字符串
? JSON.stringify( js的类型 )
? 反序列化 json的字符串 ——》 JS的类型
? JSON.parse( json的字符串 )
JsonResponse({}) # contentType :application/json
JsonResponse([],safe=False)
from django import forms
class RegForm(forms.Form):
user = forms.CharField()
pwd = forms.CharField()
# gender=forms.CharField(widget=forms.Select(choices=((1,'男'),(2,'女')))) #单选下拉框
# gender=forms.CharField(widget=forms.SelectMultiple(choices=((1,'男'),(2,'女')))) #多选
# gender=forms.ChoiceField(choices=((1,'男'),(2,'女')),
widget=forms.widgets.RadioSelect() #单选radio
) #单选下拉框
gender=forms.MultipleChoiceField(choices=((1,'男'),(2,'女'))) #多选
使用: 在views
form_obj=ReForm() #实例化对象
form_obj = RegForm(request.POST) #把post提交过来的数据直接传进去
return render(request,'reg2.html',{'form_obj':form_obj })
模板 :
{{ form_obj.as_p }} ——》 生成p标签 label 和 input标签
{{ form_obj} input框
{{ form_obj.user }} ——》 字段对应的input标签
{{ form_obj.user.id_for_label }} ——》 input标签的ID
{{ form_obj.user.label }} ——》 字段对应的input标签的中文
{{ form_obj.user.errors }} ——》 当前字段的所有错误信息
{{ form_obj.user.errors.0 }} ——》 当前字段的第一个错误信息
{{ form_obj.non_field_errors.0 }} __all__的错误的显示
form组件的主要功能如下:
form字段
CharField 文本
ChoiceField 选择框
MultipleChoiceField 多选框
字段参数
在form标签里写上novalidate ,就不提示错了(取消浏览器的提示错误)
widget=forms.PasswordInput #密码是密文 label=’中文’
required=True, 是否允许为空
widget=None, HTML插件
label=None, 用于生成Label标签或显示内容
initial=None, 初始值 (设置默认值)
error_messages=None, 错误信息 {'required': '不能为空', 'invalid': '格式错误'}
validators=[], 自定义验证规则
disabled=False, 是否可以编辑
is_valide()是否验证成功
关于choice的注意事项:
在使用选择标签时,需要注意choices的选项可以从数据库中获取,但是由于是静态字段 获取的值无法实时更新,那么需要自定义构造方法从而达到此目的。
方法一:在类里面定义一个__init取继承父类
方法二:
from django.forms import models as form_model
hobby=form_model.ModelMultipleChoiceField(queryset=models.Hobby.objects.all())
校验
1). 内置校验
min_length=8,
max_length
required=True
2) 自定义校验
Validators=[check]
字段的参数
validators=[check,RegexValidator()],
写函数
from django.core.exceptions import ValidationError内置的校验器
from django.core.validators import RegexValidator
phone = forms.CharField(
validators=[RegexValidator(r‘^1[3-9]\d{9}$‘, ‘手机号格式不正确‘)]
局部钩子和全局钩子
from django.core.exceptions import ValidationError
def clean_user(self):
# 局部钩子
value = self.cleaned_data.get('user') # alex
# 通过校验规则 返回正确的值 (你可以修改)
return "{}dsb".format(value)
# 不通过校验规则 抛出异常
raise ValidationError('错误提示')
def clean(self):
# 全局钩子
# 通过校验规则 返回正确的值(所有的值 self.cleaned_data ) (你可以修改)
# 不通过校验规则 抛出异常
pwd = self.cleaned_data.get('pwd')
re_pwd = self.cleaned_data.get('re_pwd')
if pwd == re_pwd:
return self.cleaned_data
raise ValidationError('两次密码不一致')
‘oncontextmenu‘:"return false"是不让你右键点击
from django import forms
from django.core.exceptions import ValidationError
class RegForm(forms.ModelForm):
password = forms.CharField(min_length=6, widget=forms.PasswordInput(attrs={'placeholder': '您的密码'}))
re_password = forms.CharField(min_length=6, widget=forms.PasswordInput(attrs={'placeholder': '确认您的密码'}))
class Meta:
model = models.UserProfile
fields = '__all__' # ['字段名']
exclude = ['is_active']
widgets = {
'username': forms.TextInput(attrs={'placeholder': '您的用户名'}),
'password': forms.PasswordInput(attrs={'placeholder': 'xxxxx'}),
'name': forms.TextInput(attrs={'placeholder': '您的真实姓名'}),
'mobile': forms.TextInput(attrs={'placeholder': '您的手机号'}),
}
error_messages = {
'username': {'invalid': '请输入正确的邮箱地址'}
}
def clean(self):
# 获取到两次密码
password = self.cleaned_data.get('password')
re_password = self.cleaned_data.get('re_password')
if password == re_password:
# 加密后返回
md5 = hashlib.md5()
md5.update(password.encode('utf-8'))
password = md5.hexdigest()
self.cleaned_data['password'] = password
# 返回所有数据
return self.cleaned_data
# 抛出异常
self.add_error('re_password', '两次密码不一致!!')
raise ValidationError('两次密码不一致')
字段的展示:
1. 普通字段
{{ 对象.字段名 }}
2. choice参数
对象.字段名 ——》 数据库的值
对象.get_字段名_display() ——》显示 中文
{{ 对象.get_字段名_display }} 放在前端不加括号
外键字段 对象(__str__)
3. 自定义方法 models里
def show_classes(self):
return ' | '.join([str(i) for i in self.class_list.all()])
{{ 对象.show_classes }}
safe
不需要转义 和safe一样
在后端用mark_safe 在前端用safe
from django.utils.safestring import mark_safe
mark_safe(<span style="background-color: {};color: white;padding: 4px">{}</span>)
编辑时, instance=obj : 把原始数据放到这里,给页面展示
Request.POST:获取提交的值
https://gitee.com/
1.配置:
Git config –global user.email ‘qi@live.com’
Git config –global user.name ‘qi’
Git init :先创建个空库
git status: 查看状态
git add . :添加
git add 文件
get --version : 查看版本
git commit –m’添加注册和登录功能’ :提交到本地
Git log :查看版本信息
git reset :是回滚到commit之前,(还可以重新修改,在提交)
git reset –hard ‘版本号’ :回到最原始的位置
Git reflog :查看版本号 在会滚回来还是git reset –hard ‘版本号’
Git clone 远程仓库地址
给远程仓库起别名:Git remote add origin 远程仓库地址
Git stash :保存
Git stash list : 查看“某个地方”存储的所有记录
Git stash clear : 清空某个地方
Git stash drop :编号 ,删除指定编号的记录
git push origin master:最后提交到服务器码云
git pull origin master :拉代码,从远程拉到本地
==>
Git fetch origin master : 去仓库 获取
+
git merge origin/master-和网上下的master分支合并
git show <commit-hashId> 便可以显示某次提交的修改内容
同样?git show <commit-hashId> filename 可以显示某次提交的某个内容的修改信息。
如何把分支A 上某个commit应用到分支b上:git cherry-pick <commit id>
2.rebase变基
使git记录简洁(除了第1条后边的全整合在一起),多个记录 ——》1个记录
用法:git rebase 分支
1)Rebase第一种:
第一步:Git rebase -i HEAD~3
第二步:把第二,三行pick 变成s, s代表把当前版本合并到上一个版本,最终v3,v4都合并到v2中了
第三步:
HEAD~3:合并前3条
注:合并记录时不要把已提交(push)到仓库的代码合并,容易起冲突
2)rebase第二种:
3)Rebase第三种:
git pull origin master (有分叉)
==》
Git fetch origin dev
+
Git rebase origin master/dev
3.记录图形展示
Git log --graph
git log --graph --pretty=format:"%h %s"
4.merge 和 rebase命令的区别
Merge一次性展示所有冲突,rebase每次展示一次commit提交的冲突
Merge保留完整的历史记录,rebase会重写历史记录
5. git rebase 产生冲突
方法一:git add 文件名
Git rebase --continue
方法二:
git branch 查看
git branch dev 新建dev分支
git branch -d dev 删除dev分支
git checkout dev 切换到dev分支
git merge dev 从dev合并到当前分支(有冲突 手动解决),在commit一下
Git clone http:xxx :克隆
git checkout -b dev :创建并切换到分支
注:先切换分支在合并,切换到merge,再把dev合并到merge
单人开发
新建一个dev分支 开发新功能
开发完成 合并到master分支
有bug 新建debug分组
到debug分支上修改bug
修改完成 合并到master分支 并且删除debug分支
多人协作开发
远程仓库中每人有自己的分支
在本地开发 开发完成后提交到自己的分支
提交pull requests 合并到dev分支上
Github (仓库,小公司,网站):花钱放到别人的仓库
Gitlab (工具,大公司,开源软件)是一个用于仓库管理系统的开源项目,使用Git作为代码管理工 具:自己公司搭建一个属于自己的仓库,自己买服务器,自己有管理员,页避免代码泄露
gitignore的作用:
配置 git 需要忽略的文件或文件夹,在 .gitignore 文件配置的文件或文件夹不会随着 git 提交到你的仓库
原文:https://www.cnblogs.com/xm-179987734/p/12336207.html