django笔记

文章目录

    • 查询表记录
    • 路由关系
    • 标签和过滤器
    • 静态文件导入,以及模板的导入和继承
    • Ajax请求
    • API查询
    • 制作分页器
    • 表单校验以及全局钩子和局部钩子
    • 页面渲染
    • cookie,session
    • 中间件
    • django多个app防止导入混乱

查询表记录

查询API
all():                  查询所有结果
filter(**kwargs):       它包含了与所给筛选条件相匹配的对象
get(**kwargs):          返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误
exclude(**kwargs):      它包含了与所给筛选条件不匹配的对象
order_by(*field):       对查询结果排序(‘-id’可以实现倒序)
reverse():              对查询结果反向排序
count():                返回数据库中匹配查询(QuerySet)的对象数量
first():                返回第一条记录
last():                 返回最后一条记录
exists():               如果QuerySet包含数据,就返回True,否则返回False
values(*field):         返回一个ValueQuerySet》》一个特殊的QuerySet,运行后得到的并不是一系列model的实例化对象,而是一个可迭代的字典序列
values_list(*field):    它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列
distinct():             从返回结果中剔除重复记录

主流web框架总结:
a socket
b 路由关系
c 模板字符串替换(模板语言)

django   a用别人的  b自己写的   c自己写的
flask    a用别人的  b自己写的   c用别人的(jinja2)
tornado  a自己写的  b自己写的   c自己写的

另一个维度:
django
其他

创建Django

#注意:别忘了前面加解释器

1 模块安装
2 django-admin startproject  mysite
3 manage.py 管理我的django项目
4 启动django--python3
manage.py runserver 127.0.0.1:8002
		-manage.py runserver 8002
		-manage.py runserver
  (2)pycharm启动:1  跟上面一样
					2 点绿色的箭头
	不是点右键运行
5 停止 ctrl+c

6 目录介绍
	settings--django全局配置文件
	urls---路由关系

创建app命令:
manage.py startapp app01
目录:
	migrations:数据库迁移的文件
	admin:后台管理相关
	apps:app配置相关
	models:模型,数据库相关,写一些类
继承auth的话,需要导入一下模块
from django.contrib.auth.models import AbstractUser

class user(AbstractUser):	#定义自己需要的类,继承AbstractUser
#写自己的功能
	test:测试相关
	views:视图函数

settings:
DEBUG
INSTALLED_APPS—》放app的名字
MIDDLEWARE–》中间件
TEMPLATES—》指定我模板文件放的路径
DATABASES—》指定连接的数据库

静态文件配置:(名字一定不能错)
STATICFILES_DIRS=[
os.path.join(BASE_DIR, ‘static’),
]

三件套:
render 模板渲染
HttpResponse 返回字符串
redirect 重定向

orm:对象关系映射
python代码------》sql
前端:
$(“#app”)------>document.getElementById(‘app’)

优点:
1 sql掌握一般,也可开发程序
2 开发效率高
3 易用,学习曲线短

缺点:
1 sql大神,执行效率高,可能orm 执行效率低
2 有的sql写不出来

orm能干的事:
1 创建表,修改表,删除表
2 插入数据
3 修改数据
4 删除数据
不能干:不能创建数据库

类名-----》表

对象------》一条数据

属性-----》字段

使用mysql步骤:

1、创建数据库(orm不能创建数据库) 	
2、在settings里配置 
 'default': {
				'ENGINE': 'django.db.backends.mysql',	#注意改后缀名
				'NAME': 'mytest',	#数据库名称
				'HOST': '127.0.0.1',	#ip地址
				'PORT': 3306,	#数据库端口
				'USER': 'root',	#指定用户
				'PASSWORD': 'xxxxxxx'	 #指定密码
3、在app的init.py文件里写上:
	import pymysql
	# django 默认用mysqldb连接mysql数据库,但是mysqldb这个模块不支持python3.0以后的版本,
	# 所以用pymysql来替换mysqldb
	pymysql.install_as_MySQLdb()	
4、在models里定义类,类必须继承 models.Model 	
5、写属性,对应着数据库的字段 	
6、执行 python manage.py    makemigrations(相当于做一个记录) 
7、执行 python manage.py migrate (会把记录执行到数据库)
#注意:创建出来的表名是app的名字_类名

2.0 path
1 from django.urls import path
2 不支持正则,精准匹配
3 有5个转换器(int,str,slug,path,uuid)
4 自定义转换器:

4.1 写一个类:
	class Test:
		regex = '[0-9]{4}'
		def to_python(self, value):
			# 写一堆处理
			value=value+'aaa'
			return value
		def to_url(self, value):
			return '%04d' % value
4.2 from django.urls import register_converter
4.3 register_converter(Test,'ttt'4.4 path('index/', views.index,name='index'),

MVC和MTV

M          T                 V

models	   template         views

M          V                 C(路由+views)
models    模板              控制器

视图层:request对象:(method POST GET FILES path get_full_path() )
# form表单,不写method ,默认是get请求
# 1 什么情况下用get:请求数据,请求页面,
# 2 用post请求:向服务器提交数据
# request.GET 字典
# request.POST 字典
# 请求的类型
# print(request.method)
# 路径
# http://127.0.0.1:8000/index/ppp/dddd/?name=xxx
# 协议:ip地址和端口/路径?参数(数据)
# print(request.path)
# print(request.get_full_path())

JsonResponse(向前端页面发json格式字符串)

# dic={'name':'xxx','age':18}
    # li=[1,2,3,4]
    # # return HttpResponse(json.dumps(li))
    # from django.http import JsonResponse
    # return JsonResponse(li,safe=False)

CBV(class base view)和FBV(function base view)
cbv:

from django.views import View
	class Test(View):
		def dispatch(self, request, *args, **kwargs):
		# 加点东西
		print('111')
		obj=super().dispatch(request, *args, **kwargs)
		# 加点东西
		print('2222')
		return obj	#不return会报错
		
		def get(self,request):
		obj= render(request,'index.html')
		print(type(obj))
		return obj
		def post(self,request):
		return HttpResponse('ok')
		
		re_path(r'index/', views.Test.as_view()),#在路由里调用

简单文件上传

1 <form action="" method="post" enctype="multipart/form-data">
		用户名:<input type="text" name="name">
		密码:<input type="text" name="password">
		文件:<input type="file" name="myfile">
		<input type="submit">

		</form>
		#enctype="multipart/form-data"	#提交数据必须指定的格式
		#	#指定类型和名称

	2   # ff是一个文件对象,django封装的
        ff=request.FILES.get('myfile')
        # 文件对象的名字
        file_name=ff.name
        from django.core.files.uploadedfile import InMemoryUploadedFile
        print(type(ff))
        with open(file_name,'wb') as f:
            for line in ff.chunks():
                f.write(line)

路由关系

基础知识,无名分组:url(r’^admin/', admin.site.urls),
# 第一个参数,可以写一个正则表达式
# 从上往下匹配,一旦匹配成功,就不往下走了
# 如果分几个个组,相应的视图函数,就应该接收几个
# 在setting里设置:APPEND_SLASH=False,请求时,浏览器不会自动补全斜杠,带上斜杠就匹配失败
# 伪静态,方便搜索引擎收录
有名分组:

	1 url(r'^test/(?P[0-9]{4})/(?P[0-9]{2})', views.test)
	2 def test(request,month,year):
		print(year)
		print(month)
		return HttpResponse('ok')
		#名字必须一致,否则报错,位置可以颠倒,如果分了两个组,必须用两个参数接
	3 有名分组和无名分组不要混用
	4 有名分组可以用**kwargs接收,无名分组可以用*args接收
	5 分组捕获的参数,都是str类型
	6 可以设置默认值

路由分发:

1 先导入from django.conf.urls import include
	2 url(r'^app01/', include('app01.urls')),有两种方式:。。。。
	3 在相应的app里创建urls  py文件,建议,不要改名字
	4 urlpatterns 不能变名字 ,后面的写法就一样了 url(r'^test',views.test3 ),
	5 重复上面步骤,分发多个

2.几和1.几的区别
1 2.几的re_path 就是我原来的url
2 2.几多了一个path,不支持正则

反向解析

	1 路由中,命一个名,url(r'^index/', views.index,name='n1'),
	2 在视图函数里:
		from django.shortcuts import reverse
		#这样就能拿到我反向解析出来的url
		url=reverse('n1')
	3 在模板里用:
		{% url 'n1'%}
	4 带位置参数反向解析  url(r'^index/([0-9]{4})/([0-9]{2})', views.index,name='n1'),
		视图:url=reverse('n1',args=(2012,12,))

		模板:{% url 'n1' 2012 12 %}
	5 带关键字参数反向解析  url(r'^index/(?P[0-9]{4})/(?P[0-9]{2})', views.index,name='n1'),
		视图:url=reverse('n1',args=(2012,12,)   ---可以
			  url=reverse('n1',kwargs={'year':2014,'month':12})-----也可以

		模板:
			{% url 'n1' 2012 12 %}----可以
			{% url 'n1' month=12 year=2012 %}----可以
		注意:按位置传,顺序是固定的
作用:修改路由中url的时候,其它地方不需要改动

名称空间:(知道它,但是建议不同app的url里name不能重名,app的名字_name)

	1   url(r'^app01/', include('app01.urls',namespace='app01')),
			urlpatterns = [
				url(r'^test',views.test3 ,name='test'),
			]
		url(r'^app02/', include('app02.urls',namespace='app02')),
			urlpatterns = [
					url(r'^test02',views.test3 ,name='test'),
			]
	2 在视图函数里:
		url=reverse('app02:test')
		print(url)
	3 在模板里:
		<a href="{% url 'app02:test' %}">点我跳到首页</a>

标签和过滤器

filter
{{}}
1 变量
句点符,深度查询(可以点到方法,不要加括号,只能是无参的方法)
2 过滤器

<p>date过滤器 {{ now|date:'Y-m-d H:i:s' }}</p>
<p>date过滤器 {{ now|date }}</p>
#如果一个变量是false或者为空,使用给定的默认值。否则,使用变量的值。例如:
<p>default过滤器  {{ ss2|default:'字符串没有值' }}</p>
<p>default过滤器  {{ ll3|default:'列表没有值' }}</p>
#返回值的长度。它对字符串和列表都起作用
<p>length过滤器  {{ ll2|length }}</p>
#将值格式化为一个 “人类可读的” 文件尺寸 (例如 '13 KB', '4.1 MB', '102 bytes', 等等)。例如:
<p>filesizeformat过滤器  {{ file|filesizeformat }}</p>
<p>filesizeformat过滤器  {{ 1024|filesizeformat }}</p>
#切片操作
<p>slice过滤器  {{ 'ycfisbig'|slice:'1:9' }}</p>
#如果字符串字符多于指定的字符数量,那么会被截断。截断的字符串将以可翻译的省略号序列(“...”)结尾
<p>truncatechars过滤器  {{ 'xxxisbigdddddddeee'|truncatechars:9 }}</p>
<p>truncatewords过滤器:  {{ 'xxx is big and yyy is small'|truncatewords:3 }}</p>
<p>safe过滤器:  {{ ss3|safe }}</p>
	xss攻击:跨站脚本攻击
	{#可以在视图函数里处理#}
	from django.utils.safestring import mark_safe
	ss3=mark_safe(ss3)
<p>safe过滤器:  {{ ss3|safe }}</p>
#俩参数可以传字符串和数字,具体详见源码
<p>add过滤器:  {{ 12|add:"3" }}</p>
<p>add过滤器:  {{ 'eee'|add:"3rrr" }}</p>
		

tag

{% %}
	for :forloop 
		{%for i in ll%}
		#必须再for循环里使用
		{{forloop}}
		#
		{% empty%}}
		{% endfor%}
	if if语句支持 and 、or、==><!=<=>=、in、not in、is、is not判断。
		{%if 条件%}
		{% endif%}
		
	{% with aa=dic.name%}
	{{aa}}
	{%endwith%}

自定义过滤器

1 先去setting里面把app名字配置上
2 再app目录下创建一个templatetags模块
3 写py文件(my_test.py)
4 from django import template
5 register=template.Library()
6 写函数 addstr(用register.filter()装饰)
7 模板:
8 {% load my_test %}
9 {{'xxx'|addstr:'isbig' }}  #最多只能传两个参数

自定义标签:

1 先去setting里面把app名字配置上
2 再app目录下创建一个templatetags模块
3 写py文件(my_test.py)
4 from django import template
5 register=template.Library()
6 写函数 [email protected]_tag(name='yy')装饰)
	@register.simple_tag(name='yy')
	def my_sum(x,y,z,i):

		return x+y+z+i
7 模板:
8 {% load my_test %}
9 {% yy 12 34 56 78 %}  #以空格做分割,传参数

静态文件导入,以及模板的导入和继承

静态文件引入的三种方式:

 	一:
		<link rel="stylesheet" href="/static/dd/ssmycss.css">
	二:
		{% load static %}
		<link rel="stylesheet" href="{% static 'dd/ss/mycss.css' %}">
		{#    返回值:/static/dd/ss/mycss.css#}
	三:
		<link rel="stylesheet" href="{% get_static_prefix %}dd/ss/mycss.css">

模板导入和继承
模板导入:

1 把公共部分,放到html里,比如叫 left.html
2 想在哪里用 {% include 'left.html' %}
母版继承:
1  写一个母版 base.html
2 要更改的地方写上以下内容
{% block base %}
	母版的盒子里也可以写东西
{% endblock %}
3 调用:
	3.1 写在第一行 {%extends 'base.html' %}
	3.2 		{% block base %}
	
				自己的东西
				
				{% endblock my_head%}
	3.3 还想用母版里的内容({{block.super}} 放在哪,原来母版里的东西,就会渲染在哪)
			{% block base %}
				{{block.super}}
				自己的东西						
			{% endblock my_head%}
	3.4 如过不继承盒子,它会用原来的内容,如果继承了,没写自己的东西,它会空白
	3.5 盒子在继承时,跟顺序无关

自定义 inclusion_tag

1 先去setting里面把app名字配置上
2 再app目录下创建一个templatetags模块
3 写py文件(my_test.py)	#可以自定义名字
4 from django import template
5 register=template.Library()
6 @register.inclusion_tag('test.html')
	def my_inclusion(n):
		data=[]
		for i in range(n):
			data.append('第%s行'%i)
		return {'data':data}
7 写test.html页面
			<ul>
			  {% for choice in data %}
				<li>{{ choice }}</li>
			  {% endfor %}
			</ul>
8 {% load my_test %}
9 {% my_inclusion 10 %}   它会返回html的页面

Ajax请求

1、 基本应用:

 $.ajax({
        url:'/ajax_next/',		#指定路径
        type:'get',				#指定get或者post请求
        data:{'n1':n1,'n2':n2},
        success:function (data) {
            alert(data)			#处理data
            $("#sum").val(data)
        }
    })

2、提交json数据

	#name=xxx&age=12
	#往后台传递json格式数据
	#JSON.stringify({'name':'ycf'})
	#转完之后‘{“name”:“ycf”}’
 $.ajax({
    url:'/ajax_next/',
    type:'get',
	contentType:'application/json',		#默认是urlencoded
    data:JSON.stringify({'name': name, 'pwd': pwd}),
    success:function (data) {			#success是异步
        alert(data)						#处理data
        $("#sum").val(data)
    }
})
需要自己从body取出来,后续处理

3、上传文件:

    $(".btn").click(function () {
    var formdata=new FormData();
    console.log(typeof formdata);
    formdata.append('name',$('[name="name"]').val())
    formdata.append('pwd',$('[name="pwd"]').val())
    formdata.append('myfile',$("#myfile")[0].files[0])
    console.log(formdata)
    $.ajax({
        url: '/ajax_next/',
        type: 'post',
        contentType: false,  //告诉jQuery不要去处理发送的数据
        processData:false, // 告诉jQuery不要去设置Content-Type请求头
        data: formdata,
        success: function (data) {
            alert(data)
        }
    })
})

API查询

基于双下划线的模糊查询

Book.ojects.filter(price__in=[100,200,300])		#判断是否在某个值里
Book.ojects.filter(price__gt=100)				#大于
Book.ojects.filter(price__lt=100)				#小于
Book.ojects.filter(price__gte=100)				#大于等于
Book.ojects.filter(price__lte=100)				#小于等于
Book.ojects.filter(price__range=[100,200])		#相当于between and
Book.ojects.filter(price__contains="python")	#包含
Book.ojects.filter(price__icontains="pyhon")	#不区分大小写
Book.ojects.filter(price__startswith="py")		#以py开头
Book.ojects.filter(pub_date_year=2021)			#匹配年,可以匹配月份,天数
#django聚合
from django.db.models import Avg,Count,Max,Min,Sum	#需要导入


#django F和Q
from djngo.d.models import F,Q						#/导入F、Q
F()的实例可以在查询中引用字段
Q()来表示与或非	&表示与	|表示或	~表示非


#不用访问页面,直接写一个py文件,运行就能查看结果
“untitled2.settings”根据自己的配置文件修改名字
import os
if __name__=='__main__':
	os.environ.setdefault("DJANGO_SETTINGS_MODULE","untitled2.settings")
	import django
	django.setup()

制作分页器

from django.shortcuts import render, HttpResponse

# Create your views here.
from app01.models import *	#导入自己定义的类
from django.core.paginator import Paginator, EmptyPage	#导入分页码需要的模块


def page_test(request):
    # book_list=[]												#创建一个空列表
    # for i in range(100):										#循环一百次
    #     # Book.objects.create(name='book%s'%i,price=10+i)		#这种方式每次都要打开数据库存一条数据,耗费资源
    #     book=Book(name='book%s'%i,price=10+i)					#每循环一次将数据存入book
    #     book_list.append(book)								#添加到列表里
    # Book.objects.bulk_create(book_list,10)					#统一加入到数据库,10代表一次写入10条
    

	# 获取当前页码
    book_list = Book.objects.all()		#查询所有数据
    paginator = Paginator(book_list, 3)	#3代表每页展示多少条数据
    print(paginator.count)				#传进来的object_list总共的数量
    print(paginator.num_pages)			#总共的页数
    print(paginator.page_range)			#页码的列表。比如[1,2,3]
    try:
        current_page = int(request.GET.get('page', 1))
        # 生成page对象,传页码,会生成对应页码数据
        page = paginator.page(current_page)
    except Exception:
        current_page = 1
        page = paginator.page(1)
        
    # for i in page.object_list:
    #     print(i)
    # for i in page:
    #     # 当前页码的每条数据
    #     print(i)
    # 是否有下一页
    # print(page.has_next())
    # # 是否有上一页
    # print(page.has_previous())
    # # 下一页页码
    # print(page.next_page_number())
    # # 上一页页码
    # print(page.previous_page_number())
    
	#object_list :在当前这页上的对象列表。
	#number :当前的页码。
	#paginator :获取 Paginator 对象。
    
    # 显示前5 后5 总共11页
    if paginator.num_pages > 11:	#判断总页码数是否大于11
        if current_page - 5 < 1:	#判断当前页码数减5是否小于一
            page_range = range(1, 12)	#指定范围,顾头不顾尾,共十一页
        elif current_page + 5 > paginator.num_pages:	判断当前页码数加5是否大于总页码数
            page_range = range(paginator.num_pages - 10, paginator.num_pages + 1)	#指定范围,顾头不顾尾,共十一页
        else:
            page_range = range(current_page - 5, current_page + 6)	#除了上面两种情况,则正常显示前五页后五页
    else:
        page_range = paginator.page_range	#页码数不大于十一页,有多少页就显示多少页

    return render(request, 'page_test.html', locals())	#locals() 函数会以字典类型返回当前位置的全部局部变量。

表单校验以及全局钩子和局部钩子

forms组件简单介绍
	1 字段校验
	2 渲染表单
	3 显示错信息
	4 局部钩子
	5 全局钩子

实例


from django import forms	#导入表单
from django.forms import widgets	#widgets可以指定输入框格式和定义属性

from django.core.exceptions import  ValidationError	#补货异常需要导入ValidationError
class RegForm(forms.Form):	#定义类继承forms.Form
    name = forms.CharField(required=True, max_length=10, min_length=2, label='用户名',
                           error_messages=
                           {'required': '该字段必填', 'max_length': '超出指定长度', 'min_length': '长度不够'},
                           widget=widgets.TextInput(attrs={'class':'form-control error','aa':'xxx'})
                           )
                           #required=True	该字段默认就是True
                           max_length=10	#指定该字段的最大长度限制
                           min_length=2		#指定该字段的最小长度限制
                           label='用户名'	#渲染时在页面会显示
                           error_messages={}	#指定不符合条件时给出的提示
                           widget=widgets.TextInput(attrs={}	#指定input是哪个框,可以自己选,attrs可以自己定义属性,自己通过属性名修改样式
    pwd = forms.CharField(max_length=10, min_length=2, label='密码',widget=widgets.PasswordInput(attrs={'class':'form-control error','aa':'xxx'}))
    re_pwd = forms.CharField(max_length=10, min_length=2, label='确认密码',widget=widgets.PasswordInput(attrs={'class':'form-control error','aa':'xxx'}))
    # xx = forms.CharField(max_length=10, min_length=2, label='确认密码',widget=widgets.CheckboxInput())
    email = forms.EmailField(label='邮箱', error_messages={'required': '该字段必填', 'invalid': '不符合邮箱格式'},widget=widgets.EmailInput(attrs={'class':'form-control error','aa':'xxx'}))
    
    # 局部钩子(多了一个我自己写校验规则的方式)
    def clean_name(self):	#要修改的字段必须是clean_(自己上面定义过得名称)
        name=self.cleaned_data.get('name')	#cleaned_data是用来存储已经校验通过的数据
        user=UserInfo.objects.filter(name=name).first()	#通过上面拿出来的数据和自己数据库中的数据做对比
        if user:
            raise ValidationError('用户已经存在')	#比对成功则显示用户已经存在
        else:
            if name.startswith('sb'):
                raise ValidationError('不能以sb开头')	#也可以自己限制不让用户输入的格式
            return name
            
    # 全局钩子
    def clean(self):	#全局钩子是上面所有都校验通过之后才能到达的
        pwd=self.cleaned_data.get('pwd')	#因为上面没有校验密码的error_message,所以可以在这里进行判断
        re_pwd=self.cleaned_data.get('re_pwd')
        if pwd and re_pwd:
            if pwd==re_pwd:
                return self.cleaned_data
            else:
                raise ValidationError('两次密码不一致')



# def forms_test(request):
#     # from类里没有的字段,不会做校验,而且,一旦校验通过,cleaned_data 里面也没有这个字段
#     # from类里有的字段,如果不传,一定校验不通过
#     # form_obj=RegForm({'namea':'leee','password':'xxx','email':'[email protected]','xxx':'xxx'})
#     # # 返回一个布尔类型,true代表,里面所有字段,都校验通过
#     # print(form_obj.is_valid())
#     # if form_obj.is_valid():
#     #     # 校验通过的字段,放在里面
#     #     print(form_obj.cleaned_data)
#     # else:
#     #     print(form_obj.errors.get('name')[0])
#     #     print(type(form_obj.errors))
#     #     from django.forms.utils import  ErrorDict
#     #     print(form_obj.cleaned_data)
#
#
#     return render(request,'forms_test.html')

def forms_test(request):	#定义函数
    form_obj = RegForm()	#指定一个为空的数据

    if request.method == 'POST':	#来的是post请求则继续往下
        form_obj = RegForm(request.POST)	#将post请求的数据写入form_obj
        if form_obj.is_valid():		#判断是否校验通过
            UserInfo.objects.create(**form_obj.cleaned_data)	#将数据打散,创建该信息
            # return HttpResponse('ok')

        else:
            print(form_obj.errors.as_data())	
            errors=form_obj.errors.get('__all__','')	#将错误信息返回,可以指定默认为空
            # print(form_obj['name'].errors)
            # return HttpResponse('失败')

    return render(request, 'forms_test.html', locals())

页面渲染

注意:form表单还是需要自己创建

<div class="container-fluid">
    <div class="row">
        <div class="col-md-6 col-md-offset-3">

            <form action="" method="post">	#正常写入表单以及数据
                <p>用户名:<input type="text" name="name" class="form-control" aa="ddd"></p>
                <p>密码:<input type="password" name="pwd"class="form-control"></p>
                <p>确认密码:<input type="password" name="re_pwd"class="form-control"></p>
                <p>邮箱<input type="text" name="email" class="form-control"></p>
                <input type="submit">
            </form>
            
            <hr>
            <h1>渲染页面方式一</h1>		#以视图里的字段坐渲染	
            <form action="" method="post" novalidate>
                <p>{{ form_obj.name.label }}{{ form_obj.name }} <span
                        class="pull-right">{{ form_obj.name.errors.0 }}</span></p>
                <p>密码:{{ form_obj.pwd }}<span class="pull-right">{{ form_obj.pwd.errors.0 }}</span></p>
                <p>确认密码:{{ form_obj.re_pwd }}<span class="pull-right">{{ form_obj.re_pwd.errors.0 }}{{ errors }}</span></p>
                <p>邮箱{{ form_obj.email }}<span class="pull-right">{{ form_obj.email.errors.0 }}</span></p>
                <input type="submit">
            </form>
            
            <hr>
            <h1>渲染页面方式二</h1>		#for循环每个字段,推荐使用,可以在每个字段加入标签,方便改动
            <form action="" method="post" novalidate>
                {% for foo in form_obj %}
                    <div>{{ foo.label }}{{ foo }}<span class="pull-right">{{ foo.errors }}</span></div>
                {% endfor %}
                <input type="submit">
            </form>

            <hr>
            <h1>渲染页面方式三</h1>		#不推荐使用,虽然用起来方便,但是没法修改样式
            <form action="" method="post">
                {{ form_obj.as_p }}
            </form>
        </div>
    </div>
</div>

cookie,session

简单设置

cookie sessioon
	#设置cookie
	obj.set_cookie(key,value)
	return obj
	#取cookie
	key=request.COOKIES.get('key')	
	#删除
	obj.delete_cookie(’key‘)
	retrun obj
	
	#设置session
	request.session[key]=value
		1 
		2
		3
	
	cbv加装饰器
def login_auth(func):
    def inner(request, *args, **kwargs):
        url = request.get_full_path()
        # /shopping/?nana=ppp
        is_login = request.COOKIES.get('is_login')
        # xxx=request.get_signed_cookie('xxx',salt='123')
        # print(xxx)
        if is_login:
            ret = func(request,*args, **kwargs)
        else:
            return redirect('/login/?next=%s' % url)
        # /login/?next=/shopping/?nana=ppp
        return ret

    return inner


def login(request):
    if request.method == 'POST':
        url = request.GET.get('next')
        name = request.POST.get('name')
        pwd = request.POST.get('pwd')
        if name == 'ycf' and pwd == '123':
            obj = redirect(url)
            obj.set_cookie('is_login', True,path='/shopping/')
            import datetime
            now = datetime.datetime.now().strftime('%Y-%m-%d %X')
            obj.set_cookie('last_time', now)
            obj.set_cookie('name', 'ycf')
            obj.set_cookie('pwd', '123')
            obj.set_signed_cookie('xxx','xxxxxx',salt='123')
            return obj
        else:
            obj = HttpResponse('登陆失败')
            return obj

    return render(request, 'login.html')

def logout(request):

    obj=HttpResponse('注销成功')
    obj.delete_cookie('is_login')
    return obj

@login_auth
def shopping(request):
    return render(request, 'shopping.html', locals())


@login_auth
def order(request):
    return render(request, 'order.html', locals())

from django.utils.decorators import method_decorator
from django.views import View

# @method_decorator(login_auth,name='post')
# @method_decorator(login_auth,name='get')
class MyOrder(View):
    @method_decorator(login_auth)
    def dispatch(self, request, *args, **kwargs):
        ret=super().dispatch(request, *args, **kwargs)
        return ret
    # 在cbv上加装饰器,需要用method_decorator修饰一下

    def get(self,request):
        return HttpResponse('get')
    def post(self,request):
        return HttpResponse('post')
'''
1 导入from django.utils.decorators import method_decorator
2 加载get,post,dispatch方法上:@method_decorator(login_auth)
3 加在类上:@method_decorator(login_auth,name='get')
'''

def session_test(request):

    request.session['username']='ycf'
    request.session['is_login']=True
    '''
    1 生成一个随机字符串
    2 把随机字符串以cookie的形式写回给浏览器
    3 会在数据库里存{'随机字符串':{'username':'ycf','is_login':True}}
    '''

    return HttpResponse('ok')


def get_session(request):
    name=request.session['username']
    is_login=request.session['is_login']
    print(name)
    print(is_login)

    # request.session['k1']
    # request.session.get('k1', None)
    # request.session['k1'] = 123
    # request.session.setdefault('username', 123)  # 存在则不设置
    # del request.session['k1']
    # print(request.session.session_key)
    # 将所有Session失效日期小于当前日期的数据删除
    # request.session.clear_expired()
    # print(request.session.exists("uhsvmv7wc41pneeee6f4w0fxvqy6qzh5m29"))
    # 会删除数据库的session
    # request.session.delete()
    # 删除当前的会话数据并删除会话的Cookie。
    # 通常用它
    request.session.flush()

    return HttpResponse('ok')

def test(request):

    return HttpResponse('ok')

中间件

中间件:
中间件顾名思义,是介于request与response处理之间的一道处理过程,相对比较轻量级,并且在全局上改变django的输入与输出。因为改变的是全局,所以需要谨慎实用,用不好会影响到性能1

重点方法:
	请求:process_request  一旦有返回值,直接就回去了
	相应:process_response 如果没有返回值,就会报错
	process_view
	process_exception
Csrf:跨站请求伪造
	比如:招商银行转账接口:transfer/?to='xxx'&count='100'
	黑客网站:有个按钮:http://market.cmbchina.com/transfer/?to='xxx'&count='100'

XSS:跨站脚本攻击
		
		
CBV局部使用,禁用csrf
	from django.views import View
	from django.views.decorators.csrf import csrf_exempt,csrf_protect
	from django.utils.decorators import method_decorator	
	#加在类上,必须指定方法为dispatch
	#@method_decorator(csrf_exempt,name='dispatch')
	class Test(View):
		#加在dispatch方法上
		# @method_decorator(csrf_exempt)
		def dispatch(self, request, *args, **kwargs):
			obj=super().dispatch(request, *args, **kwargs)
			return obj

		def get(self,request):
			return render(request,'index1.html')
		def post(self,request):
			print(request.POST)
			return HttpResponse('ok')

django多个app防止导入混乱

首先在你自己新增的app里创建urls.py文件,添加如下内容
from app01 import views		#导入自己的视图
from newdjango.urls import path	#导入主路由的地址

urlpatterns = [
    path('index/', views.index),	
]

在views.py里写自己定义的函数
def index(request):
    return render(request,'index.html')

在主路由里配置一下内容
from django.urls import path,include	#导入include模块
urlpatterns = [
    path('admin/', admin.site.urls),
    path('app01/',include('app01.urls')),	#定义访问路径,include(指定app的路由)
]

web访问的时候app01/index/		#主路由定义的地址/app路由定义的地址

你可能感兴趣的:(Python,Django,django,python,笔记)