首页 > 其他 > 详细

django 视图

时间:2020-03-05 17:36:26      阅读:80      评论:0      收藏:0      [点我收藏+]

视图

CBV FBV

  1. CBV : class based view 基于类的视图
    FBV: funcation based view 基于函数的视图
    使用:在views里,好处是不需要加if判断了

举个基于类的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()),
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
1). 加在方法上

@method_decorator(timer)
def get(self, request):

2) 加在dispatch方法上(所有的请求方式都能加上)

@method_decorator(timer)
def dispatch(self, request, *args, **kwargs):
    ret=super().dispatch(request,*args,**kwargs)  #调用父类方法
    return ret

3)加在类上, 必须有name参数

(1)指定给谁加上

  @method_decorator(timer,name='post')
  @method_decorator(timer,name='get')
  class AddPublisher(View):

(2)要是这种的话,就不用写dispatch方法了,他会加在父类的方法上

@method_decorator(timer,name='dispatch')
class AddPublisher(View):
使用类装饰器和直接使用@timer有什么区别?

没什么区别,主要区别在于装饰器里的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对象

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>

response

HttpResponse('字符串')    ——》 返回的字符串
render(request,'模板的文件名',{k1:v1})    ——》  返回一个完整的HTML页面
redirect(要跳转的地址)    —— 》重定向       Location :地址
jsonresponse
httpresponse 和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)

分组

  1. Django settings.py配置文件中默认没有 APPEND_SLASH 这个参数,但 Django 默认这个参数为 APPEND_SLASH = True。 其作用就是自动在网址结尾加‘/‘。

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={} )

admin的使用

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/

ORM模型

对象关系映射(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版本之后就是必填项

1.ORM字段 对象关系映射

常用的字段
?????????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进制小数

2.参数

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中该字段的提示信息

3.自定义一个char类型字段:

 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,)

4. 表的参数

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"),)

下图是该名字,改变后,名字变了,内容不变
技术分享图片
技术分享图片

5. ORM的查询(13条) 必知必会13条

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

聚合 aggregate

分组 注释: 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)

F和Q查询

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


cookie能做什么:

  1. 登录 (保存状态)
  2. 保存用户的浏览习惯
  3. 投票

为什么要有cookie?

HTTP协议是无状态的,每次请求都是没关系的,没办法保存,状态,使用cookie保存状态

django的操作:

  1. 设置 本质: 响应头 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生效的域名

  2. 获取 本质:请求头cookie

    request.COOKIES[key] {} # 普通的cookie
    或者
    request.COOKIES.get(key)
    #request.get_signed_cookie(‘is_login‘,salt=‘day62‘,default=‘‘) # 加密的cookie
  3. 删除

    ret = redirect(‘/login/‘)
    ret.delete_cookie(‘is_login‘)

session

session 当做字典使用

定义: 保存在服务器上一组组键值对,必须依赖于cookie。

为什么要使用session?(特性)

  1. cookie保存在浏览器本地,不安全
  2. cookie的大小受到限制

django中操作session

  1. 设置

    request.session[key] = value
    或者
    request.session.setdefault(key,value)
  2. 获取

    request.session[key]
    或者
    request.session.get(key)
  3. 删除

    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)
  • process_view(self, request, view_func, view_args, view_kwargs)
  • process_exception(self, request, exception)
  • process_template_response(self,request,response)
  • process_response(self, request, response)

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相关的装饰器

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')

csrf中间件步骤

  1. 请求到来时执行process_request方法:
    从cookie中获取csrftoken的值 —— 》 赋值给 request.META[‘CSRF_COOKIE‘]
  2. 执行process_view方法:
    1. 查看视图是否加了csrf_exempt装饰器:
      1. 有 不需要csrf 校验 返回none
      2. 没有 需要csrf 校验
    2. 请求方式的判断:
      1. 如果是 ‘GET‘, ‘HEAD‘, ‘OPTIONS‘, ‘TRACE‘ 不需要csrf 校验 返回none
      2. 其他方式需要csrf 校验
    3. 进行CSRF校验:
      1. 从request.META获取到csrftoken的值
      2. 尝试从表单中获取csrfmiddlewaretoken的值:
        1. 能获取到
          csrfmiddlewaretoken的值和cookie中的csrftoken值做对比
          1. 对比成功 通过csrf校验
          2. 对比不成功 不通过csrf校验 拒绝请求
        2. 获取不到 尝试从请求头中获取x-csrftoken的值
          x-csrftoken的值和cookie中的csrftoken值做对比
          1. 对比成功 通过csrf校验
          2. 对比不成功 不通过csrf校验 拒绝请求
json 和XML对比

JSON 简单的语法格式和清晰的层次结构明显要比 XML 容易阅读,并且在数据交换方面,由于 JSON 所使用的字符要比 XML 少得多,可以大大得节约传输数据所占用得带宽。

ajax

(Asynchronous Javascript And XML)翻译成中文就是“异步的Javascript和XML”,
AJAX 不是新的编程语言,而是一种使用现有标准的新方法

定义: 是一个js的技术,发送请求的一种途径。
特点:

  1. 异步 2. 局部刷新 3. 传输的数据量小(xml json)

发请求的途径:

  • 地址栏上输入地址 GET
  • a标签 GET
  • form表单 GET/POST

简单实例 固定格式

$.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上传文件
技术分享图片
技术分享图片

ajax通过django的csrf校验
  1. 确保csrftoken的cookie
    1. 一个加 {% csrf_tokne%}
    2. 给视图函数加装饰器
  2. 提供参数
    1. 给data添加数据
      data: {
      csrfmiddlewaretoken:隐藏标签或是cookie
      csrfmiddlewaretoken: $(‘[name="csrfmiddlewaretoken"]‘).val(),
      i1: $(‘[name="i1"]‘).val(),
      i2: $(‘[name="i2"]‘).val(),
      },
      ? 2. 加x-csrftoken的请求头
      headers: {
      ‘x-csrftoken‘: 隐藏标签或是cookie
      ‘x-csrftoken‘: $(‘[name="csrfmiddlewaretoken"]‘).val(),
      },
      3.文件导入
    <script src="/static/ajax_setup.js"></script> 

    总结:json

                     数据交换的格式
                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)

form组件 是一个类

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组件的主要功能如下:

  • 生成页面可用的HTML标签
  • 对用户提交的数据进行校验
  • 保留上次输入内容

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()],
  1. 写函数

    from django.core.exceptions import ValidationError
    def check(value):
    # 自定义校验规则
    # 通过校验 不用返回
    # 没有通过校验 抛出异常 raise ValidationError(‘有非法字符‘)
  2. 内置的校验器

    from django.core.validators import RegexValidator
    phone = forms.CharField(
    validators=[RegexValidator(r‘^1[3-9]\d{9}$‘, ‘手机号格式不正确‘)]

is_valid()的流程:
  1. 执行self.errors的方法 ——》 self.full_clean()
  2. full_clean方法():
    1. 定义一个存放错误信息的字典 self._errors = ErrorDict()
    2. 定义一个存放正确(经过校验)值 的字典 self.cleaned_data = {}
    3. 执行self._clean_fields():
    4. 依次循环所有的字段
    5. 执行内部的校验 和 自定义校验器的校验 value = field.clean(value)
    6. 将正确的值放在self.cleaned_data self.cleaned_data[name] = value
    7. 有局部钩子就执行
      1. 通过校验 self.cleaned_data[name] 重新赋值
      2. 不通过校验 self.cleaned_data[name] 当前字段的键值对被清除 self._errors中存放当前字段的错误信息
    8. 执行self._clean_form() ——》 self.clean()
      1. 如果有重新定义就执行
        1. 通过校验 返回所有的值 self.cleaned_data 重新赋值
        2. 不通过校验 把错误信息添加到 all 中

局部钩子和全局钩子

     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('两次密码不一致')

modelform组件

‘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:获取提交的值
技术分享图片

Git

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第二种:

  • 第一步:git branch dev touch dev1.py git add git commit
  • 第二步:git checkout master touch master1.py git add git commit
  • 第三步:git checkout dev git rebase master(在dev上合并master)
  • 第四步:git checkout master git merge dev(切换到master,再合并dev)
    Git log --graph --pretty=format:”%h %s” 结果就是一条简单的直线

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 提交到你的仓库

django 视图

原文:https://www.cnblogs.com/xm-179987734/p/12336207.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!