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
- 1、web应用的概念
- 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',
},
}
}