Django


目录
  • Django
    • 1、web应用的概念
      • 1.1、web应用是什么?
      • 1.2、软件开发模式
      • 1.3、web应用程序的优点
      • 1.4、web应用的缺点
      • 1.5、web框架
      • 1.6、Python中的三大主流框架
    • 2、MVC和MTV模型
      • 2.1、MVC
      • 2.2、MTV
    • 3、Django下载与安装
      • 3.1、Django的版本问题
      • 3.2、安装Django
      • 3.3、验证是否成功
      • 3.4、创建Django项目
        • 3.4.1、命令行创建
        • 3.4.2、pycharm创建
        • 3.4.3命令行和pycharm创建项目的区别
        • 3.4.4、启动Django项目
        • 3.4.5、创建应用
    • 4、主要文件介绍
    • 5、Django三板斧
      • 5.2、rener
      • 5.3、redirect
    • 6、静态文件的配置
    • 7、request请求
    • 8、form表单
    • 9、pycharm链接MySQL
    • 10、Django链接MySQL
    • 11、Django操作ORM
      • 11.1、创建表
      • 11.2、ORM对字段的增删改查
      • 11.3、ORM对数据的增删改查
      • 11.4、ORM创建表关系
    • 12、Django请求周期流程图
    • 13、路由层
      • 13.1、无名有名分区
      • 13.2、反向解析
      • 13.3、路由分发
      • 13.4、名称空间
    • 14、JsonResponse类的使用(JSON格式的数据)
    • form表单上传文件
    • 16、CBV和FBV
    • 17、模板层
      • 17.1、模板语法之传值
      • 17.2、模板语法之过滤
      • 17.2、模板语法之标签
      • 17.3、模板语法之继承
      • 17.4、模板语法之导入
    • 18、测试环境的搭建
    • 19、ORM查询方式
      • 19.1、基于双下滑线查询
      • 19.2、一对多外键字段的增删改
      • 19.3、多对多的增删改
      • 19.4、多表查询-基于对象的跨表查询(子查询)
      • 19.5、基于双下划线跨表查询(连表查询)
      • 19.6、F与Q
  • Django操作数据库的SQL语句查看

Django

1、web应用的概念

http的默认端口号	:80
https的默认端口号	:443

1.1、web应用是什么?

就是通过浏览器访问的应用都是web应用

1.2、软件开发模式


C/S:client:客户端		server:服务端
B/S:browser:浏览器		server:服务端
    # 本质:B/S架构也是C/S架构

服务端需要具备的特征:
	24小时对外提供服务

1.3、web应用程序的优点

1、只需要一个浏览器
2、充当多个应用的客户端,可以减少硬盘空间的占用
3、客户端不需要主动更新,服务端更新即可
4、支持跨平台使用

1.4、web应用的缺点

1、一旦服务端出现问题,客户端立刻受到影响
2、兼容性问题。同样的代码在不同的浏览器渲染出来的效果可能不一样

1.5、web框架

框架:就是在固定的位置书写固定的代码(主体)

1.6、Python中的三大主流框架

1、Django框架
	大而全,类似于航空母舰
2、flask框架
	小而精,轻量级框架,依赖于第三方模块
3、tornado框架
	异步高性能框架

2、MVC和MTV模型

2.1、MVC

MVC:
	M:model(跟数据打交道)		模型
    V:View(html页面)			视图
    C:controller(逻辑相关)		控制器
    	S:sevice(服务层)--->>公共的功能
        	C层逻辑特别多的时候,就会分出S层
            
# python之外的

2.2、MTV

MTV
	M:model(模型层:跟数据相关) --- model(跟数据打交道)
    T:template(模板:html页面) --- View(html页面)
    V:view(主要写逻辑的) --- controller(逻辑相关)

# Python中的说法
# MVC与MTV中的层次一一对应

3、Django下载与安装

3.1、Django的版本问题

Django1.x:老项目再用
Django2.x:现在的新项目再用
Django3.x:刚出来的新版本

3.2、安装Django

# 命令行
pip install django
pip3 install django  # 安装最新版本
pip3 install django==1.11.11  # 指定版本

# pycharm
scttings
	Python interpreter
    	搜索点击安装即可

3.3、验证是否成功

在cmd中,输入:django-admin,如果有输出信息,就代表安装成功

django-admin

3.4、创建Django项目

3.4.1、命令行创建

# 提前切换到项目要保存的文件夹内

创建项目
django-admin startproject 项目名

3.4.2、pycharm创建

File
	new project
    	Django
        	选择Python解释器
            

3.4.3命令行和pycharm创建项目的区别

pycharm创建:
	自动生成templates文件夹
    
    settings.py文件:
    	TEMPLATES = [{
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')]}       
    
命令行创建:
	没有templates文件夹
    
    settings.py文件:
    	TEMPLATES = [{
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': []   # 需要手动添加路径

3.4.4、启动Django项目

"""前提:先切换到manage.py 所在的文件夹下"""
命令行启动:
	python manage.ot runserver  # 默认本机ip+端口
    python manage.ot runserver 127.0.0.1:8000  # 启动其他ip + 端口
    python manage.ot runserver 8000  # 默认本机ip可以更改端口

pycharm启动
	找到对应的项目点击绿色箭头就可以启动


3.4.5、创建应用

# 创建应用:
python manage.py startapp app名

eg:
	用户模块		应用
    订单模块
    收货地址管理
    ...
    
命令行创建:
	python manage.py startapp app名
    """
    app名:见名知意
    """
	# 一个Django项目至少要有一个应用
pycharm创建:
	tools
    	run manage.py task
        	startapp app名
            

# 创建应用完成之后,第一件事就到配置文件中配置文件
	INSTALLED_APPS = [
        'app名'
    ]

4、主要文件介绍

mysitel					# 项目名
	- app01				# 应用名
    	--migrations	# 迁移数据库的时候,会把迁移记录保存到这里
        	__init__.py
        --admin.py		# Django自带的后台管理系统
        --apps.py
        --models.py  	# 模型成,跟数据相关的
        -- tests.py  	# 测试脚本
        --views.py  	# view层,核心逻辑、
    -mysitel  			# 项目同名文件夹
    	--__init__.py
        --settings.py  	# 配置文件
        --urls.py  		# 路由层,路径与视图函数的对应关系
        --wsgi.py  		# wsgiref服务器,WSGI协议,uwsgi服务器
    -templates  		# html文件
    db.sqlite3  		# Django自带的小型数据库
    -manage.py  		# 启动文件(入口文件)

5、Django三板斧

# Django自动重启的现象:热更新

locals()  # 获取局部名称空间的变量名(内存地址),必须在局部名称空间
globals()  # 获取全局名称空间的变量名

5.1、HttpResponse

HttpResponse	返回字符串类型数据

-----------------------------------------------------------------
from app01 import views
# urls.py
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^index/',views.index)  # 函数名不能加括号
]

-----------------------------------------------------------------
# views.py
from django.shortcuts import render, HtttpResponse, redirect


def index(request):
	return HttpResponse('Hello Django!')

5.2、rener

render		返回request对象,html页面,还可以传值

-----------------------------------------------------------------
from app01 import views
# urls.py
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^index/',views.index)  # 函数名不能加括号
]

-----------------------------------------------------------------
# views.py
from django.shortcuts import render, HttpResponse,redirect
from time


def index(request):
	ctime = time.strftime('%Y-%m-%d %X')
	return render(request,'index.html',{'ctime':ctime})  # 将ctime返回到前端页面
	
-----------------------------------------------------------------

# index.html

{{ ctime }}

5.3、redirect

redirect	重定向
可以将用户访问重定向到其他网址
或者自身其他的url
-----------------------------------------------------------------
from app01 import views
# urls.py
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^index/',views.index)  # 函数名不能加括号
]

-----------------------------------------------------------------
# views.py
from django.shortcuts import render, HttpResponse,redirect


def index(request):
	ctime = time.strftime('%Y-%m-%d %X')
	return redirect('/home/')

-----------------------------------------------------------------


6、静态文件的配置

什么是静态文件?
	静态文件是网站页面所使用到的提前已经写好的文件,如css,js,第三方组件 bootstrap,sweetalert,fontawesome等
	
静态文件的储存路径一般是 static 文件夹。
创建项目的时候默认是没有该文件夹的,需要手动创建
在项目的根路径下创建即可。

在static 文件夹可以根据不同的功能进行不同的划分
static
	- JS
	- CSS
	- IMG
	- ...

http://127.0.0.1:8000/static/css/...不能访问是因为没有开通接口,需要在配置文件中添加。
STATICFILES_DIRS = [
    os.path.join(BASSE_DIR, 'static')  # 将静态文件路劲添加到环境变量,相当于开通接口
]


配置文件中的STATIC_URL = '/static/'  # 相当于令牌


# 动态引入
{% load static %}


7、request请求

request.method
	获取当前请求方式,是大写的字符串

request.GET				:获取GET请求的数据:
request.GET.get()			:根据括号内的参数指定获取数据
request.GET.getlist			:获取全部数据,以列表的形式展现

request.POST				:获取POST请求的数据:
request.POST.get()			:根据括号内的参数指定获取数据
request.POST.getlist()			:获取全部数据,以列表的形式展现

8、form表单

form action=" " # 提交地址  
	method=''  # 提交方式
"""
action=''
	1、什么都不写:提交到当前页面
	2、全写:可以提交到任何地址
	3、只有后缀:/index/ 会自动提交到这里,ip 端口默认
"""





# 面试题
get 和 post区别
get:get可以携带非常小的参数,对数据大小有限制,没有请求体
post:有请求体,对数据大小没限制,传输比get安全


HTTP四大特征
	基于请求响应
	基于TCP/UDP协议之上
	无状态
	无/短连接

MySQL可能会出现的安全问题:
	SQL注入
前端当中可能会出现的安全问题
	XSS攻击:用户在输入框输入某些代码,后端使用

Django可能会出现的安全问题
	csrf请求

9、pycharm链接MySQL

pycharm >>> databases >>> Date Source >>> MySQL >>> 按照提示输入即可

10、Django链接MySQL

需要更改配置文件
更改配置文件
DATEBASE = {
    'default':{
        'ENGINE':'djang0.db.backends.mysql',
   'NAME':''  # 库名字
   'PORT':3306  # 端口
    'USER':'root'  # 用户名
    'PASSWORD':''  # 密码
    'CHARSET':'utf8'  # 字符集
    'HOST':'127.0.0.1'  # ip
    }
}


# Django默认的操作MySQL的模块是MySQLdb

"""
在python3.6版本以下,需要在任意__init__加入下面两句话
	pip install pymysql
	
	import pymysql
	pymysql.install_as_MySQLdb()
"""

# mysqlclient 模块:安装之后不用各种乱七八糟的,但不容易安转



11、Django操作ORM

1、什么是ORM
	关系映射对象

2、特点
	在操作数据库的时候不需要写原生SQL语句
	"""相对而言执行效率变低了"""

3、ORM书写位置
	models.py

4、代码指向
	类名 >>> 表名
	对象 >>> 记录
	属性 >>> 字段(对应的数据)

11.1、创建表

"""
如果创建表的主键字段名为 id 那么可以默认不写,也是唯一且自增的
如果创建主键的字段为 uid pid 等都需要书写出来
	uid = models.AutoField(primary_Key=True)
"""
# 创建表
from django.db import models


class User(models.Model):
	# id int primary key auto_increment
	id = AutoField(primary_Key=True)
	# username varchar(32)
	username = CharField(max_length=32)
	passworf = CharField(max_length=32)


操作数据的代码书写完毕之后需要执行数据库迁移命令
	python manage.py makemigrations
	python manage.py migtate


# django_migrations表
	内部数据可以随意删除,之后执行数据库迁移命令即可

11.2、ORM对字段的增删改查

from django.db import models


class User(models.Model):
	# id int primary key auto_increment
	id = AutoField(primary_Key=True)
	# username varchar(32)
	username = CharField(max_length=32)
	passworf = CharField(max_length=32)

	# 增加,直接书写然后数据库迁移命令
	age = IntegerField()
	之后出提示输入字段默认值
	终端提示,输入:1  # 直接添加数据
	# 增加2,在创建的时候直接输入
	方式1:
		age = IntegerField(null=True)  # 即该字段可以为空
	方式2:
		age = IntegerField(default='默认值')  # 直接输入默认值
	
	# 删除,直接注释或者删除代码,数据库迁移
	# age = IntegerField()  即删除字段
	    """
    在操作models.py的时候一定要细心
    	千万不要注释一些字段
    	执行迁移命令之前最好检查一下自己写的代码
    """

	# 修改,直接修改代码,数据库迁移
	age1 = IntegerField()

注:任何与数据库相关的命令全都要执行数据库迁移命令

11.3、ORM对数据的增删改查

filter():过滤。and关系
first():取出第一个数据

1、增加数据
from app名字 impore models

方式1
# insert into user(username,password) values('username','password');
res = models.User.object.create(username='username',passwoed='password')
方式2
user_obj = models..User(username='username',password='passwore')  # 只是产生一个User类的对象
user_obj.save()  # 这个才是真正的增加保存时局




2、删除数据
# delete from user where id=1;
models.User.object.filter(id=1).delete()


3、修改数据
方式1
# update user set username='username' where id=1;
models.User.object.filter(id=1).update(username='username')
update只修改筛选出来的字段

方式2
user_obj = models.User.filter(id=1).first()
user_obj.username = 'username'
user_obj.save()  # save会自动判断对象是否存在,存在就是update更新,不存在就是insert插入
# 方法2从头到尾将所有字段全部更新一遍,无论改数据是否被修改




4、查看数据
res = models.User.object.filter()  # 获取User表的所有数据
res = models.User.object.filter(id=1)  # 获取id=1字段的所有数据
res = models.User.object.all()  # 获取表所有数据

11.4、ORM创建表关系

什么是外键:
	代表两张表之间的关系
MySQL关系型数据库
	一对一
		一张表与另外一张表记录一一对应
	一对多
		一张表中的一条记录对应另外一张表中多条记录
	多对多
		两张表中的任意多条记录对应另外一张表的多条记录
		外键关系建立在第三张表中


# ORM创建表关系

# 图书表
class Book(models.Model):
	title = CharField(max_length=32)
	price = DecimalField(max_digits=8,decimal_places=2)

	# 外键字段,一对多
	publish = models.ForeignKey(to='Publish',to_field='id')  # 如果关联的字段是 id 字段,那么可以忽略不写to_field='id'

	# 外键,多对多
	authors = models.ManyToManyField(to='Author')
	"""
	authors是虚拟字段,不会真正的在book表中东创建出来
	"""

# 出版社
class Publish(models.Model):
    addr = models.CharField(max_length=32)


# 作者
class Author(models.Model):
    name = models.CharField(max_length=128)

    # 外键:一对一方式1
    author_detail = OneToOneField(to='AuthorDetail')
    # 一对一方式2
    models.FormaryField(unique=True)

# 作者详情
class AuthorDetail(models.Model):
    phone = models.CHarField(max_length=32)

12、Django请求周期流程图

# 浏览器
	发送请求

# 第一层:web服务网关接口
	swgiref模块:socket服务端

# 第二层:Django框架
	# 中间件

	# 路由层
	urls.py

	# 视图函数层
	views.py

	# 模板层
	templates

	# 模型层
	models.py


1、并行
	同时执行任务
2、并发
	看起来像是同时执行任务

13、路由层

'''
1、路由匹配:urls.py
url	:Django1.x版本的url匹配为正则匹配
	:2.x及以上为精准匹配
'''
# 书写:
from django.conf.urls import url
from django.contrib import admin
from app01 import views

urlpatterns = [
	url(r'^admin', admin.site.urls),
	url(r'^home/', views.home)  # 基本书写规则
]

"""
可以将url看成一个函数
第一个参数为正则匹配的规则
	自上而下寻找匹配的内容
第二个参数为对应的视图函数
	找到匹配内容触发相对应的视图函数
第三个参数

第四个参数
	别名:通过解析可以获取相对应的路由地址
"""
# url代码
def url(regex, view, kwargs=None, name=None):
    if isinstance(view, (list, tuple)):
        # For include(...) processing.
        urlconf_module, app_name, namespace = view
        return RegexURLResolver(regex, urlconf_module, kwargs, app_name=app_name, namespace=namespace)
    elif callable(view):
        return RegexURLPattern(regex, view, kwargs, name)
    else:
        raise TypeError('view must be a callable or a list/tuple in the case of include().')

# url注意事项
url(r'index', views.index)  # 这样书写但凡匹配中出现index都执行该视图函数
	http://127.0.0.1:8000/indexxxxxxx
	http://127.0.0.1:8000/iiiiiindex
url(r'^index', views.index)  # 这样书写凡是以index开头的都会被匹配到
	http://127.0.0.1:8000/indexxxxxxx

url(r'^index$', views.index)  # 精准匹配不出现相对应的字符都不会被匹配到
	http://127.0.0.1:8000/index
	# 但是这样书写太过于绝对


"""
GET请求的两种传值方式:
	方式1:
		http://111.1.1.1:8000/index/?a=1
		后端:需要在视图函数设置形参
		前端:需要匹配相对应的规则
	方式2:
		http://111.1.1.1:8000/index/1
		后端:需要在视图函数设置形参
		前端:需要匹配相对应的规则
"""

13.1、无名有名分区

# 分组:将相对应的数据传输到视图函数中

# 无名分组
url(r'index/(\d+)', views.index)  # 需要匹配:/index/数字
	http://127.0.0.1:8000/index/4  # 同时会将“数字”当成参数传入到后端的视图函数中,需要位置形参接收
def index(request, xx):
    print(xx)
    return HttpResponse('index')

# 有名分组
url(r'index/(?P\d+)', views.index)  # 需要匹配:/index/数字
	http://127.0.0.1:8000/index/4  # 同时会将“数字”当成参数传入到后端的视图函数中,需要关键字形参接收
def index(request, name):
    print(name)
    return HttpResponse('index')

13.2、反向解析

"""
反向解析:
	通过一个路由名别得到该别名所在的url完整的地址

路由是可以起别名的
"""
# 书写格式
url(r'^index/', views.index, name='xxx')

# 1、反向解析
# url
url(r'^index/', views.index, name='xxx')
# 后端反向解析
# 需要导入模块
from django.shortcuts import render,HttpResponse, reverse
def index(request):
    print(reverse('xxx'))
    return render(request,'index.html')
# 前端反向解析
解析



# 无名分组反向解析
# url
url(r'^index/(\d+)', views.index, name='xxx')
# 后端
def index(request,xx):  # xx接收浏览器路径后面携带的参数数据
    print(reverse('xxx', args=(1,)))  # xxxurl别名,1:相对应的url
    print(xx)
    return render(request,'index.html')
# 前端
解析  # 数字可以理解为前端向后端发送的数据


# 有名分组反向解析
url(r'^index/(?P\d+)', views.index, name='xxx')
# 后端
def index(request,a):
	# 写法1:
    print(reverse('xxx', kwargs={'a':4}))
	# 写法2:
	print(reverse('xxx', args=(4,)))
    print(a)
    return render(request,'index.html')
# 前端
# 写法1:
解析
# 写法2:
解析


"""
有名无名反向解析无法混合使用

"""

13.3、路由分发

"""
当Django项目越来越大,需要的路由就会越来越多,非常难维护


这时候就会用到路由分发

Django中每个应用都可以有自己相对应的文件
	urls.py
	templates
	static
"""

# 总路由
# 导入模块:include
from django.conf.urls import url, include
from django.contrib import admin
"""
# 使用方式推导1:导入文件名字相同,容易导致代码错乱可以起别名
from app01 import urls
from app02 import urls

urlpatterns = [
	url(r'^admin/', admin.site.urls),
	url(r'^appp01', include(urls)),
	url(r'^appp02', include(urls)),
]

"""
# 使用方式推导2:这样就可以解决相对应的问题
from app01 import urls as app01_urls
from app02 import urls as app02_urls

urlpatterns = [
	url(r'^admin/', admin.site.urls),
	url(r'^appp01', include(app01_urls)),
	url(r'^appp02', include(app02_urls)),
]

# 另外一种使用方式:
# 不需要导入模块:
urlpatterns = [
	url(r'^admin/', admin.site.urls),
	url(r'^appp01', include('app01.urls')),
	url(r'^appp02', include('app02.urls'))
] # 注意:总路由里面的url不能加$符结尾
--------------------------------------------------------------

# 子路由
# app01
from django.conf.urls import url
from app01 import views

urlpatterns = [
    url(r'^reg/', views.reg)
]

# app02
from django.conf.urls import url
from app02 import views

urlpatterns = [
    url(r'^reg/', views.reg)
]

13.4、名称空间

# 当多个应用出现相同的别名的时候反向解析就没有办法识别

# 解决
# 总路由
url(r'^app01/', include(app01.urls,namespace='app01'))
url(r'^app01/', include(app01.urls,namespace='app02'))
# 子路由
urlpatterns = [
    url(r'^reg/', views.reg, name='reg')
]
urlpatterns = [
    url(r'^reg/', views.reg, name='reg')
]
# 后端解析
reverse('app01:reg')
reverse('app02:reg')

# 前端
{% url 'app01:reg' %}
{% url 'app02:reg' %}

"""
只要名字不冲突就没有必要使用名称空间

一般情况下,起别名的时候将别名添加上应用前缀即可

urlpatterns = [
    url(r'^reg/', views.reg, name='app01_reg')
]
urlpatterns = [
    url(r'^reg/', views.reg, name='app02_reg')
]
"""

14、JsonResponse类的使用(JSON格式的数据)

"""
视图函数中的返回值都是继承HttpResponse对象
	render redirect HttpResponse
"""

项目开发分类
1、混合项目开发
	前端页面与后端代码在一起

2、前后端项目分离
	前端是一个应用,后端是一个应用,后端只需要提供一个接口即可


前端与后端数据传输
	JSON格式数据:跨语言数据传输

"""
补充:
import json
	支持的数据类型:
		str list dict set tuple 等基本数据类型
	序列化出来的数据:可以看字符串
dumps
loads

dump
load


import pickle
	支持的数据类型:
		python中所有的数据类型
	序列化出来的数据:
		都是二进制数据,只能在python中使用
dumps
loads

dump
load


# JS中如何序列化
JSON.stringify()		:序列化
JSON.parse()			:反序列化



josn模块
json.dumps(ensure_asciii=False)		:取消编码
"""

# JsonResponse使用
from django.http import JsonResponse


def index(request):
	user_dict = {'user':'xx沙', 'pswd':123}
	return JsonResponse(user_dic,json_dumps_params={'ensure_ascii':False})  # json_dumps_params查看源码根据源码填入字典,可以更改显示编码问题


 ** 在形参与实参中的作用
	形参:接收多余的关键字形参
	实参:将字典打散以关键字实参的方式传入

form表单上传文件

"""
上传文件注意事项:
	前端:
		1、必须是post请求
		2、form表单参数enctype="multipart/form-data"
	后端:
		request.FILES		:接收文件数据
		其他的根据提交方式提取即可
-----------------------------------------------
form表单可以传输的数据格式
	1、urkencoded
	2、form-data
	# 不能提交json格式数据


数据格式
	1、urkencoded
	2、form-data
	3、json

提交json格式数据
	方式1:ajax,三种数据格式都可以提交
	方式2:第三方工具
			postman
			apizza
"""

# 获取前端提交的数据格式
# 后端
def index(request):
	if request.method == 'POST':
		file_obj = request.FILES.get('myfile')
			with open(file_obj.name, 'wb') as f:
				for i in file_obj:
					f.write(i)
	return render(request, 'upload_file.html')


# 前端

文件上传:

16、CBV和FBV

FBV:function based view
CBV:class bases view

# CBV 必须西继承一个类
from django.views import View

class MyLogin(View):

    def get(self, request):
        return render(request,'from.html')

    def post(self,request):
        return HttpResponse('post函数')
 
--------------------------------------------------------
"""
FBV和CBV各有千秋
CBV特点
	能够直接根据请求方式的不同直接匹配到对应的方法执行
"""
---------------------------------------------------------
# CBV源码
# 突破口urls.py中
url(r'^login/',views.MyLogin.as_view())
# url(r'^login/',views.view)  # FBV一模一样
# CBV与FBV在路由匹配上的本质是一样的,都是路由 对应 函数内存地址
"""
函数名/方法名 加括号执行优先级最高
猜测
	as_view()
		要么是被@staticmethod修饰的静态方法
		要么是被@classmethod修饰的类方法  被修饰的类方法
		
	@classonlymethod
	def as_view(cls, **initkwargs):
		pass
"""
    @classonlymethod
    def as_view(cls, **initkwargs):
        """
        Main entry point for a request-response process.
        """
        def view(request, *args, **kwargs):
            self = cls(**initkwargs)  # cls是我们自己写的类
            return self.dispatch(request, *args, **kwargs)
		"""
		再看python源码的时候 一定要时刻提醒自己面向对象属性方法查找顺序
			先从对象自己找
			再去产生对象的类里面找
			之后再去父类找
		
		总结:看源码只要看到了self点一个东西,一定要想清楚当前这个self到底是谁
		"""
        return view

# CBV精髓   
def dispatch(self, request, *args, **kwargs):
		# 获取当前请求的小写格式,然后对比当前请求方式是否合法
        # 
        if request.method.lower() in self.http_method_names:
            handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
            """
            getatter:反射:通过字符串来操作对象的属性或者方法
            	handler = getattr(自己写的类产生的对象,'get\post',当找不到'get\post'属性或者方法的时候就会用第三个参数)
            	handler = 自己写的MyLogin里面的get\post方法
            
            """
        else:
            handler = self.http_method_not_allowed
        return handler(request, *args, **kwargs)

17、模板层

17.1、模板语法之传值

{{ 变量名 }}		:变量相关双括号
{% 逻辑 %}		:逻辑相关花括号百分号
# 前端

{{ n }}

{{ f }}

{{ se }}

{{ d }}

{{ l }}

{{ t }}

{{ s }}

{{ b }}

{{ func }}

{{ MyClass }}

内部能够判断出当前的变量名是否可以加括号调用,如果可以就会加括号调用执行,针对的是函数名和类名,

{{ obj }}

{{ obj.get_class }}

{{ obj.get_func }}

{{ obj.get_self }}

# 后端 def index(request): # 模板语法已传递的后端数据类型 n = 123 f = 123.123 s = '钱' l = ['赚', '钱'] d = {'赚钱':' 难啊', '学': '习'} b = True se = {'加', '油'} t = (11, 22, 33) # return render(request, 'index.html', {}) # 字典一个一个传值 def func(): print('被执行了') return '可以执行' class MyClass(object): def get_self(self): return 'self' @staticmethod def get_func(): return 'func' @classmethod def get_class(cls): return 'cls' # 对象被展示到html页面上,就类似执行力打印操作,也会触发__str__方法 def __str__(self): return '打印' obj = MyClass() return render(request, 'index.html', locals()) # Django模板语法的取值 是固定的格式,只能采用“句点符”

{{ d.赚钱 }}

{{ l.1 }}

{{ d.字段.2.ff}}

# 既可以点键也可以点索引 还可以两者混用

17.2、模板语法之过滤

# 相当于python中的内置方法

语法:
	{{ 变量 | 过滤器:参数 }}  # 变量相当于第一个参数,参数相当于第二个

过滤器:# 过滤器中管道符后面最多可以传递参数
	1、length
		计算长度: {{ str | length }}
	2、defalut
		默认值:{{ bool | default:'默认值' }}
		bool为True,就用bool自己的,如果为False就用'默认值'
	3、date
		日期:{{ time | date:'Y-m-d H:i:d' }}
	4、filesizeformat
		文件大小:{{ file | filesizeformat }}
	5、safe
		h1 = '

' 前端标签:{{ h1 | safe }} # 使标签显示到前端页面 # 后端标签直接显示到前端页面 from django.utils.safestring import mark_safe hh = mark_safe('

这是标签

') {{ hh }} xss攻击: # 转义:可以书写html代码并执行 # 前端 | safe # 后端 from django.utils.safestring import mark_safe res = mark_safe('

大垃圾

') """ 以后在写全栈项目的时候前端代码不一定非要在前端页面书写 也可以现在后端写好,然后传递给前端页面 """

17.2、模板语法之标签

在模板中可以使用 if else for

# 需要后端返回前端一个内存地址

# 使用方法
# 后端
def index(request):
	lis = [1,2,3,4]
	dic = {'字典':'dict','字典1':'dict1'}
	return render(request, 'index.html', locals())
# 前端
{% for li in lis %}  # 循环列表
    

{{ li }}

{% if forloop.first %} # 第一次循环first结果True

第一次

{% elif forloop.last %} # 最后一次循环结果为False

最后一次

{% else %}

中间

{% endif %} {% endfor %} {% for foo in dic.values %} # 循环字典获取values

{{ foo }}

{% endfor %} {% for foo in dic.keys %} # 循环字典获取keys

{{ foo }}

{% endfor %} {% for foo in dic.items %} # 循环items获取键值对

{{ foo }}

{% endfor %}

17.3、模板语法之继承

# 一个页面通过一些方法可以被其他页面继承即使用

# 主页面
{% block '起个名字:h1' %}
	其他页面可以继承之后可以更改的代码区
{% endblock %}


# 子页面
{% extends '继承页面的名称' %}

{% block '主页面的可以被更改位置的名字:h1' %}
	重新书写代码
{% endblock %}

17.4、模板语法之导入

# 创建一个html页面,内部只写标签代码即可
# 其他页面需要该功能导入该页面即可


导入
{% include '导入模板的名称' %}  # 该位置使用的就是之前创建好的模板页面

18、测试环境的搭建

tests.py	# 测试脚本文件

# 配置环境
import os
if __name__ == "__main__":
	os.environ.setdefault("")  # manage.py中的前几行代码
	import django
	django.setup()
	# 书写测试代码,包括各种模块导入

19、ORM查询方式

.all()
	查询所有数据,列表的形式展示出来
.first()
	查询出第一条数据
.last()
	查询出最后一条数据
get()
	相当于filter,内部书写条件,但没有就会报错
exclude()
	排除括号内书写的条件,相当于取反
order by('条件')
	排序,默认升序
	降序需要在'-条件'添加符号
reverse()
	翻转,经过排序之后翻转才有意义
count()
	计数,通过一个条件或者计算所有
exists()
	判断某个条件存不存在,返回布尔值
values()
	获取指定的字段数据,列表套字典的形式展示出来
values_list()
	获取指定的字段,列表套元祖的形式
distinct()
	去重,一定不能加主键,可以与values组合使用,给某个字段去重

19.1、基于双下滑线查询

__gt=n
	大于n
__lt=n
	小于n
__gte=n
	大于等于
__lte=n
	小于等于


__in=[条件,条件]
	SQL语句是 or ,查询某个字段的值是条件1与条件2数据
__range=[条件。条件]
	在什么什么之间,between
__contains='条件'
	模糊查询,什么字段包含某个条件,默认区分大小写
__icontains='条件'
	同上,忽略大小写
__startswith='条件'
	模糊查询,什么字段内包含以什么条件开头的数据 
__endswith='条件'
	模糊查询,什么字段内包含以什么条件结尾的数据 
register__time__month='1'
	按照月份取出数据,month月
register__time__year='2020'
	年取出数据
register__time__day='1'
	日

19.2、一对多外键字段的增删改

# 增
	方式1:直接书写实际字段 id
	models.Book.object.create(title='',price='',publish_id=1)  # 直接书写外键外键字段添加对应的值即可
	方式2:虚拟字段,直接传入数据对象,内部会自动找到当前对象所对应的主键值,然后写入数据
	publish_obj = models.Publish..object.filter(pk=).first()
	models.Book.object.create(publish=publish_obj)

# 删
models.Publish.object.filter(pk=2).delete()  # 级联删除
# 清空
book_obj = models.Publish.object.all()
book_obj.publish.clear()

# 改
	方式1:
	models.Book.object.filter(pk=1).update(字段='新数据')
	方式2:
	publish_obj = models.Publish.object.filter(pk=1).fiser
	models.Book.object.filter(pk=1).updata(publish=pubish_obj)

19.3、多对多的增删改

多对多的增删改查就是操作第三张关系表
# 增
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.authors  # 就类似于已经跨到了第三张表
book_obj.authors.add(1)  # 给书籍主键为1的书籍绑定一个主键为1的作者
book_obj.authors.add(1,2)  # 给书籍主键为1的书籍绑定一个主键为1,2的作者
author_obj = models.Author.objects.filter(pk=1).first()
author_obj1 = models.Author.objects.filter(pk=2).first()
author_obj2 = models.Author.objects.filter(pk=3).first()
book_obj.authors.add(author_obj, author_obj1, author_obj2)
"""
    add:给第三张关系表添加数据
        括号内既可以传数字,也可以传对象,都支持多个
"""
# 删
# 方法1:
book_obj = models.Book.objects.filter(pk=2).first()  # 获取书籍对象
book_obj.authors.remove(2)  # 删除这个书籍对象的多对多的关系表中对应的关系id

# 方法2
book_obj = models.Book.objects.filter(pk=2).first()
author_obj2 = models.Author.objects.filter(pk=3).first()  # 获取书籍对象
book_obj.authors.remove(author_obj2)  # 操作书籍对象删除对应的书籍对象参数,支持多个参数删除

# 方法3
# 清空,不需要传参数
book_obj.authors.clear()


# 改
# 方式1
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.authors.set([1, 2])

# 方式2
author_obj = models.Author.objects.filter(pk=1).first()
author_obj1 = models.Author.objects.filter(pk=2).first()
book_obj.authors.set([author_obj, author_obj1])
"""
	set:括号内必须是可迭代对象,该对象可以是数字,也可以是对象,支持多个

	顺序:先删除所有,在添加
	注意:在修改数据的时候需要将修改的和不修改的全部写入,不然数据就会只剩下修改的了
"""
# 清空
# 在第三张清空某个书籍与作者的绑定关系
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.authors.clear()
"""
    clear():括号内不需要添加数据
"""

set():括号内必须是可迭代对象,支持多个
add():括号内可以是数字即对应的id,和对象,支持多个
remove():可以是id数字,也可以是对象
clear():清空,括号内不需要数据

19.4、多表查询-基于对象的跨表查询(子查询)

"""
基于正向查询
	当结果可能有多个的时候需要加.all()
	如果数据是多个的时候就不需要点.all()
	
"""

"""
基于对象反向查询
	当查询结果可以有多个的时候需要加_set.all()
	当结果只有一个的时候不需要加_set.all()
	即反向查询一对一表关系就不用加set
"""
# 正向
book_obj = models.Book.oobject.filter(pk=1).fiser()  # 获取书籍对象
res = book_obj.publish  # 跨到另一张表中,res 就是publish对象
res.name  # 对象 点数属性查询结果

book_obj = models.Book.object.filter(pk=1).first()
res = booK_obj.authors.all().first()  # 跨到另外一张表中,取出所有对象中的第一个对象
res.name  # 对象 点属性


# 反向
author_obj = models.Author.objects.filter(pk=1).first()
author_obj.booK_set.all()  # 所有的对象

19.5、基于双下划线跨表查询(连表查询)

正向
res = models.Author.objects.filter(pk=1).values('自己的字段__对应表的字段')  # 通过values字段 双下划线找出对应表的字段即可

反向
models.Publish.objects.filter(book__id=1).values('name')  # 通过filter过滤对应的表 双下划线 对应的数据,在通过values找出对应的字段

19.6、F与Q

# F查询就是可以拿到数据库原有的数据
# 1、导入模块
from django.db.models import F
"""F查询默认是针对数字类型数据"""
models.Book.object.filter(price=F('price')+100)  # F内获取当前字段的值,进行运算,然后更改

"""设置针对字符类型"""
from django.db.models.functions import Concat
from django.db.models import Value
models.Book.objects.udate(title=Concat(F('title'),value('拼接的字符')))

# Q查询简单使用就是 将过滤条件变成 或 or 的关系
from django.db.models import Q

models.Book.objects.filter(Q(字段=条件), Q(字段=条件))  # 逗号分割还是 and 关系
models.Book.objects.filter(Q(字段=条件) | Q(字段=条件))  # 更改为管道符 | 才会变成 或 or 的关系

models.Book.objects.filter(~Q(字段=条件), Q(字段=条件))  # Q前面加上 波浪 ~ 代表当前 Q 的条件是取反,多个就额外添加,或者将取反的过滤条件括起来前面加 ~ 

models.Book.objects.filter(~(Q(字段=条件), Q(字段=条件))  # 内部全部取反

# Q 的高阶用法  能够将查询条件左边也变成字符串的形式
	q = Q()
	q.connector = 'or'  # 更改Q里面的链接条件为 or
	q.children.append(('maichu__gt',100))  # 支持内服放字符串类型数据
	q.children.append(('price__lt',700))
	res = models.Book.objects.filter(q)  # filter内部支持放Q对象,默认还是and关系
	print(res)

Django操作数据库的SQL语句查看

# 此条配置添加扫settings.py的配置文件中
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console':{
            'level':'DEBUG',
            'class':'logging.StreamHandler',
        },
    },
    'loggers': {
        'django.db.backends': {
            'handlers': ['console'],
            'propagate': True,
            'level':'DEBUG',
        },
    }
}