下载
-
命令行
pip install django==1.11.26 -i https://pypi.tuna.tsinghua.edu.cn/simple
-
pycharm
创建项目
-
命令行
django-admin startproject 项目名
-
pycharm
file _> new project _> django _> 输入路径 _> 选择解释器 _> create
启动项目
-
命令行
python manage.py runserver # 127.0.0.1:8000
python manage.py runserver 80 # 127.0.0.1:80
python manage.py runserver 0.0.0.0:80 # 0.0.0.0:80
-
pycharm
点绿三角 django 前面是dj
可以修改配置 可以改IP和端口
使用顺序
settings 静态文件配置
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) #文件夹根目录
DEBUG = True #因为启动出错调试模式 上线后改为Flase,出错不报错,给用户更好的用户体验
ALLOWED_HOSTS = ['*'] #让所有的用户可以访问
INSTALLED_APPS = [ #app注册
'app01',
'app01.apps.App01Config' # 推荐写法
]
MIDDLEWARE = [
# 'django.middleware.csrf.CsrfViewMiddleware', #提交POST请求注释一个中间件
]
"""
如果使用sqlite3数据库
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
"""
"""
#如果使用mysql数据库
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql', #diango的服务器引擎
'NAME': 'bookmanager',
'USER': 'root',
'PASSWORD': '123',
'HOST': '127.0.0.1',
'PORT': 3306,
}
}
#默认使用pymysql模块 替换
import pymysql
pymysql.install_as_MySQLdb()
"""
LANGUAGE_CODE = 'en-us' #汉语 'zh-hans'
TIME_ZONE = 'UTC' #时区:英国的,改为亚洲上海 'Asia/Shanghai'
STATIC_URL = '/static/' #静态文件夹的别名,配置静态文件要以/static/为开头
STATICFILES_DIRS = [ # 路由
os.path.join(BASE_DIR,'static1'), # 存放静态文件的路径
os.path.join(BASE_DIR,'static1'),
]
# join(BASE_DIR必须是这个,静态文件夹static1)
# 加上静态文件的存放路径
models.py 映射关系
写映射关系操作数据库
settings 配置:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql', #使用mysql数据库引擎
'NAME': 'day43', #默认操作的库
'HOST': '127.0.0.1', #库所在的服务器地址
'PORT': 3306, #端口
'USER': 'root', #用户名
'PASSWORD': '123', #密登密码
}
}
#默认使用pymysql模块 替换 也可以写在day43的__init__.py里
import pymysql
pymysql.install_as_MySQLdb()
创库
用可视化工具创建一个MySQL数据库
创表
class User(models.Model):
username = models.CharField(max_length=32) # varchar(32)
password = models.CharField(max_length=32) # varchar(32)
#类 对象 属性
#表 数据行 字段
python manage.py makemigrations # 制作迁移文件 出现在migrations
python manage.py migrate # 执行SQL语句 同步
#terminal里执行命令
△id字段是自动添加的,如果你想要指定自定义主键,只需在其中一个字段中指定 primary_key=True 即可。如果Django发现你已经明确地设置了Field.primary_key,它将不会添加自动ID列。
urls.py 路由
路径 函数转换
==settings配置:
STATICFILES_DIRS = [ # 路由
os.path.join(BASE_DIR,'static1'), # 存放静态文件的路径
os.path.join(BASE_DIR,'static2'),
]
url(r^'用户输入输入的路径 0.0.0.0:80/index/',不加括号的函数名)
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^index/', index), # 路径和函数的对应关系,
url(r'^modal/', modal),
]
views.py 函数
def index(request): # 函数里写处理逻辑,request拿到网络路径,固定写法
print(request.path_info) # 打印网络路
import 导入:
导入返回字符串的包HttpResponse,返回html文件的包render,返回执行另一个逻辑的包
from django.shortcuts import HttpResponse,render, redirect
导入dpp01文件中的创建数据表的类的models.py文件
from app01 import models
return 返回:
return HttpResponse('index
')
返回字符串
return HttpResponse('<h1>index</h1>') # 返回字符串
return render(,,)
返回接受到请求的网络路径要渲染的html文件和要传的值
return render(request, 'index.html',{'k1':v1})
#返回 (网络路径必添,要渲染的html文件,{别名:要传的值})
return redirecct('路径')
执行另一个逻辑
ORM的操作
写函数来实现增删该查
.all 获取所有的数据
all_publishers = models.Publisher.objects.all()
#变量 = 文件名.类名.对象.取值方法
# objects.all() 查询出所有的出版社的信息,是一个对象列表
.filter(pk=pk) 获取所一个数据
第一个pk列名,第二个pk为从request中get到的
变量 = models.User.objects.filter(password='dsb') # 对象列表
# 用.first取第一个,若无,返回空列表,if 变量;判断时,不会报错,只是不会执行这个语句了
# 用[0]取值时,,若无,取不到值,if 判断时变量,会报错
get 获取所一个数据
变量 = models.User.objects.get(password='dsb') # 对象 特点 获取不到或者获取到多个都报错
create(name=pub_name) 添加数据
利用类的对象
obj = models.Publisher.objects.create(name=pub_name)
update(name=pub_name) 跟新数据
templates HTML文件
模板
某.html的settings配置
MIDDLEWARE = [
# 'django.middleware.csrf.CsrfViewMiddleware', #提交POST请求注释一个中间件
]
hyml中的样式路径配置
<head>
<title>Title</title>
<link rel="stylesheet" href="/static/plugins/bootstrap-3.3.7-dist/css/bootstrap.min.css">
<link rel="stylesheet" href="/static/plugins/font-awesome-4.7.0/css/font-awesome.min.css">
<script src="/static/js/jquery.js"></script>
<script src="/static/plugins/bootstrap-3.3.7-dist/js/bootstrap.js"></script>
</head>
模板语法
△登录
<div class="container">
<form class="form-signin" method="post" action="" novalidate>
<h2 class="form-signin-heading">Please sign in</h2>
<label for="inputEmail" class="sr-only">用户名</label>
<input type="text" id="inputEmail" class="form-control" name="username" placeholder="输入用户名" required=""
autofocus="">
<label for="inputPassword" class="sr-only">密码</label>
<input type="password" id="inputPassword" class="form-control" name="password" placeholder="输入密码" required="">
<div>{{ error }}</div>
<div class="checkbox">
<label>
<input type="checkbox" value="remember-me"> Remember me
</label>
</div>
<button class="btn btn-lg btn-primary btn-block">登录</button>
</form>
△查询所有的作者信息
all_authors = models.Author.objects.all()
for author in all_authors:
print(author)
print(author.name)
print(author.books,type(author.books)) # 关系管理对象
print(author.books.all(),type(author.books.all())) # 所关联的所有的对象
△for循环
views.py传过来的参数:
render(request,'pub.html',{'all_publishers':all_publishers})
{{ all_publishers }}
html的for循环:
{% for i in all_publishers %}
{{ forloop.counter }}
{{ i }}
{{ i.id }} {{ i.pk }}
{{ i.name }}
{% endfor %}
△if
{% if 条件 %}
xxx
{% else %}
xxxxx
{% endif %}
△form的注意点
- form标签的属性 action='提交的地址' method='post' novalidate 取消input标签自带的校验
- input标签必须要有name属性 有些标签有value值
- 需要有一个button按钮 或者 type='submit'的input
△get 和 post
get : 获取一个页面
1.直接在浏览器的地址栏中输入地址 回车
2.form表单 不指定method
3.a标签
参数: ?k1=v1&k2=v2
获取参数: request.GET.get('k1')
post : 提交数据
form表单 method = 'post'
获取数据: request.POST.get('k1')
static1 渲染
一个项目的结构
day43项目
.idea 配置
pycharm自动帮配的配置,打开别人的diango项目时要先删了此项
app01
方便在一个大的Django项目中,管理实现不同的业务功能
migrations 放表
放和数据库同步的表
admin.py 后台
后台管理:
1、应用注册
2、admin界面汉化
apps.py 元数据
应用程序设置
元数据
models.py
写映射关系操作数据库
它包含了你存储的数据的重要字段和行为
- 每个模型都是一个Python类,它是django.db.models.Model的子类。
- 模型的每个属性都代表一个数据库字段。
#类 对象 属性
#表 数据行 字段
class User(models.Model):
username = models.CharField(max_length=32) #varchar
password = models.CharField(max_length=32) #varchar
tests.py 测试
views.py
写函数逻辑
day43项目包
init.py 自动执行
#默认使用pymysql模块 替换 也可以写在settings.py里
import pymysql
pymysql.install_as_MySQLdb()
settings
静态文件配置
urls.py
路径 函数转换
wsgi.py 网关接口
WSGI(Python Web Server Gateway Intergace)
中文名:python服务器网关接口,python应用于web服务器之间的接口,很少用到,但是最好不要修改其内容
static1
templates
manage.py 命令行接口
应用的命令行接口
将Django project放到sys.path目录中,同时设置DJANGO_SETTINGS_MODULE环境变量为当前project的setting.py文件。
diango运行流程
Django处理一个请求的流程:
- 在浏览器的地址栏中输入地址,回车,发了一个GET请求
- wsgi模块接收了请求,将请求的相关信息封装成request对象
- 根据地址找到对应函数
- 执行函数获取到返回结果,wsgi模块将结果返回给浏览器
发请求的途径:
- 在浏览器的地址栏中输入地址 get请求
- a标签 get请求
- form表单 get/post
reqeust
reqeust.GET url上携带的参数 ?k1=v1&k2=v2
reqeust.POST form表单提交POST请求的参数
request.method 请求方式 GET、POST
response
HttpResponse('字符串') ——》 返回字符串
render(request,'模板的名字',{}) ——》 返回一个页面
redirect('地址') ——》 重定向
创建一个app
terminal里执行命令
python manage.py startapp app名称
注册
settings配置
INSTALLED_APPS = [
'app01',
'app01.apps.App01Config' # 推荐写法
]
Django使用MySQL数据库的流程
手动创建一个MySQL数据库
配置数据库
ENGINE MySQL
NAME 数据库的名字
HOST ip
PORT 3306
USER 用户名
PASSWORD 密码
在与settings同级目录下的__init__.py
中写代码:
import pymysql
pymysql.install_as_MySQLdb()
写models:
form django.db import models
class Publisher(models.Model):
name = models.CharField(max_length=32)
执行迁移的命令
python manage.py makemigrations # 检查已经注册的APP下面的models.py的变更情况
python manage.py migrate # 执行迁移
ORM 对象关系映射
对应关系:
类 _> 表
对象 _> 数据行(记录)
属性 _> 字段
ORM能做的事情:对数据做修改、对表做修改
常用的字段
AutoField 自增字段
IntegerField 整数
CharField 字符串
DatetimeField DateField 日期时间
auto_now:每次修改时修改为当前日期时间。
auto_now_add:新创建对象时自动添加当前日期时间。
BooleanField 布尔值
TextField 大文本
ImageField 图片
DecimalField 10进制小数
字段参数
null=True # 数据库中该字段可以为空
blank=True # 用户输入可以为空
db_column # 数据库字段的名
default # 默认值
primary_key # 主键
db_index # True 索引
unique # 唯一约束
verbose_name # 中文提示
choices # 让用户选择的数据
建表的参数
class Meta:
# 数据库中生成的表名称 默认 app名称 + 下划线 + 类名
db_table = "person"
# # admin中显示的表名称
verbose_name = '个人信息'
# verbose_name加s
verbose_name_plural = '所有用户信息'
# 联合索引
# index_together = [
# ("name", "age"), # 应为两个存在的字段
# ]
#
# # 联合唯一索引
unique_together = (("name", "age"),) # 应为两个存在的字段
ORM的操作
from django.db import models
class Publisher(models.Model):
name = models.CharField(max_length=32)
# 一对多的关系
class Book(models.Model):
name = models.CharField(max_length=32)
pub = models.ForeignKey(to='Publisher',on_delete=None)
def __str__(self):
return self.name
查询
from app01 import models
models.Publisher.objects.all() #查询所有的数据 QuerySet 对象列表
models.Publisher.objects.get(name='xxx')
#查询一条数据 只能查有且唯一的数据
models.Publisher.objects.filter(name='xxx')
#查询所有满足条件的数据 对象列表
for book in all_books:
print(book)
print(book.id)
print(book.pk)
print(book.name)
print(book.pub) # 所关联的出版社对象 对象.外键
print(book.pub_id) # 所关联的出版社对象的id 对象.外键_id
新增
obj = models.Publisher.objects.create(name='xxxx')
models.Book.objects.create(name=book_name,
pub=models.Publisher.objects.get(pk=pub_id))
obj = models.Book.objects.create(name=book_name, pub_id=pub_id)
obj = models.Publisher(name='xxxx')
obj.save() # 保存到数据库
obj = models.Book(name='xxx',pub_id=出版社的对象id)
obj.save()
多对多的新增:
书对作者
book_id = request.POST.getlist('book_id')
# 插入数据
obj = models.Author.objects.create(name=author_name)
obj.books.set(book_id) # 设置多对多的关系
删除
models.Publisher.objects.filter(pk=pk).delete() # 批量删除
models.Publisher.objects.get(pk=pk).delete() # 单条数据的删除
更新
models.Book.objects.filter(pk=pk).update(name=book_name,pub_id=pub_id) # 批量更新
obj = models.Book.objects.filter(pk=1).first()
obj.name = 'xxxx'
obj.pub_id = 2
# book_obj.pub = 出版社的对象
obj.save() #保存更新
外键
一对多的关系
class Book(models.Model):
name = models.CharField(max_length=32)
pub = models.ForeignKey('Publisher', on_delete=models.CASCADE)
"""
on_delete 在2.0版本之后是必填的
on_delete=
models.CASCADE 级联删除
PROTECT 保护
SET(1)
SET_DEFAULT 设置为默认值设置为某一个值
SET_NULL 设置为空
DO_NOTHING 什么都不变
"""
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "about_orm.settings")
import django
django.setup() # 初始化
from app01 import models
# 基于对象的查询
# 正向查询
book_obj = models.Book.objects.get(pk=3)
# print(book_obj)
# print(book_obj.pub)
# 反向查询
# 没有指定related_name 表名小写_set
pub_obj = models.Publisher.objects.get(pk=2)
# print(pub_obj.book_set,type(pub_obj.book_set)) # 关系管理对象
print(pub_obj.book_set.all())
# related_name='books'
# print(pub_obj.books.all())
# 基于字段的查询
ret = models.Book.objects.filter(pub__name='老男孩出版社')
# print(ret)
# 没有指定related_name 类名小写__字段
ret = models.Publisher.objects.filter(book__name='没有页码的python书')
# 指定related_name related_name__字段
ret = models.Publisher.objects.filter(books__name='没有页码的python书')
# 指定related_query_name='book' related_query_name_name__字段
# ret = models.Publisher.objects.filter(book__name='没有页码的python书')
# print(ret)
多对多
class Pulisher(models.Model):
name = models.CharField(max_length=32)
class Book(models.Model):
name = models.CharField(max_length=32)
pub = models.ForeignKey('Pulisher',on_delete=models.DO_NOTHING)
class Author(models.Model):
name = models.CharField(max_length=32)
books= models.ManyToManyField(to='Book')
# 查询
book_obj.pub # 所关联的对象 book_obj.pub_id 所关联的对象的id
author_obj.books # 关系管理对象
author_obj.books.all() # 所关联的所有的书籍对象
# 新增
Book.objects.create(name='xxx',pub=对象)
Book.objects.create(name='xxx',pub_id=对象的ID)
obj= Book(name='xxx',pub_id=对象的ID)
obj.save()
obj = Author.objects.create(name='xxx')
obj.books.set([书籍id,书籍id])
# 删除
Book.objects.filter(pk=pk).delete() # QuerySet 删除
Author.objects.get(pk=pk).delete() # 对象 删除
# 编辑
Book.objects.filter(pk=pk).update(name='xxx')
book_obj.name ='xxxx'
book_obj.save()
Author.objects.filter(pk=pk).update(name='xxx')
author_obj.books.set([id,id])
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "about_orm.settings")
import django
django.setup() # 初始化
from app01 import models
author_obj = models.Author.objects.get(pk=1)
# print(author_obj.books.all())
book_obj = models.Book.objects.get(pk=1)
# print(book_obj.author_set.all())
ret = models.Author.objects.filter(books__name='没有页码的python书')
ret = models.Book.objects.filter(author__name='bigbao')
# print(ret)
# set 设置多对多的关系 [id] [对象]
# author_obj.books.set([3,])
# author_obj.books.set( models.Book.objects.all()) # [对象,对象]
# add 添加多对多的关系 id 对象
# author_obj.books.add(1,2,3)
# author_obj.books.add(*models.Book.objects.all()) # *[对象,对象]
# remove 删除多对多的关系 id 对象
# author_obj.books.remove(1,2)
# author_obj.books.remove(*models.Book.objects.filter(pk__in=[1,2])) # [对象,对象]
# clear 清除多对多的关系
# author_obj.books.clear()
# create 新增一个所关联的对象 并且和当前的对象设置关系
author_obj.books.create(name='跟和尚学合气道', pub_id=1)
# book_obj.author_set
# 多对一 反向查询 一 ——》 多 关系管理对象
# 关系管理对象.set([对象,对象])
# 关系管理对象.add(对象,对象)
# 外键字段 null=True, 才有remove,clear
# 关系管理对象.remove(对象,对象)
# 关系管理对象.clear()
# 关系管理对象.create()
必知必会13条
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "about_orm.settings")
import django
django.setup() # 初始化
from app01 import models
# all() 查询所有的数据 QuerySet 对象列表
ret = models.Person.objects.all()
# filter 获取满足条件的所有的对象 QuerySet 对象列表
ret = models.Person.objects.filter(name='alex')
# exclude 获取不满足条件的所有的对象 QuerySet 对象列表
ret = models.Person.objects.exclude(name='alex')
# values()
# 不指定字段 获取所有字段名和值 QuerySet 对象列表 [ {},{} ]
# 指定字段 values('pid','name') 获取指定字段名和值 QuerySet 对象列表 [ {},{} ]
ret = models.Person.objects.all().values()
ret = models.Person.objects.filter(name='alex').values('pid', 'name')
# values_list()
# 不指定字段 获取所有的值 QuerySet 对象列表 [ (),() ]
# 指定字段 values_list('pid','name') 获取指定的值 QuerySet 对象列表 [ (),() ]
ret = models.Person.objects.all().values_list()
ret = models.Person.objects.filter(name='alex').values_list('name', 'pid', )
# order_by 排序 默认升序 -降序 可以多个字段排序
ret = models.Person.objects.all().order_by('age', '-pid')
# reverse 对已经排序的QuerySet做的反转
ret = models.Person.objects.all().order_by('pid').reverse()
# get 获取满足条件的一个的对象 对象
ret = models.Person.objects.get(name='alex')
# first 获取第一个元素 对象 获取不到的时候是none
ret = models.Person.objects.filter(name='xxx').first()
# last 获取最后一个元素 对象 获取不到的时候是none
ret = models.Person.objects.filter(name='xxx').last()
# count 计数
ret = models.Person.objects.all().filter(age=84).count()
# exists 数据是否存在
ret = models.Person.objects.filter(age=84).exists()
# distinct 去重 数据时完全一样才去重
ret = models.Person.objects.filter(age=84).values('age').distinct()
"""
返回对象列表
all
filter
exclude
order_by
reverse
values [{}]
values_list [()]
distinct
返回对象
get
first
last
返回数字
count
返回布尔值
exists
"""
单表的双下划线
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "about_orm.settings")
import django
django.setup() # 初始化
from app01 import models
ret = models.Person.objects.filter(pk__gt=3) # greater than where pk > 3
ret = models.Person.objects.filter(pk__gte=3) # greater than equal where pk >= 3
ret = models.Person.objects.filter(pk__lt=3) # less than where pk < 3
ret = models.Person.objects.filter(pk__lte=3) # less than equal where pk <= 3
ret = models.Person.objects.filter(pk__range=[1,3]) # 1 <= pk <= 3
ret = models.Person.objects.filter(pk__in=[1,3,7,10,100]) # 成员判断
ret = models.Person.objects.filter(name__contains='bigbao') # like 不忽略大小写
ret = models.Person.objects.filter(name__icontains='bigbao') # like ignore 忽略大小写
ret = models.Person.objects.filter(name__startswith='b') # 以什么开头 不忽略大小写
ret = models.Person.objects.filter(name__istartswith='b') # 以什么开头 忽略大小写
ret = models.Person.objects.filter(name__endswith='o') # 以什么结尾 不忽略大小写
ret = models.Person.objects.filter(name__iendswith='o') # 以什么结尾 忽略大小写
ret = models.Person.objects.filter(age__isnull=False) # 字段是否为空
ret = models.Person.objects.filter(birth__year='2019') # 按照年份
ret = models.Person.objects.filter(birth__contains='2019-12-19') # 时间包含
print(ret)
外间的操作
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "about_orm.settings")
import django
django.setup() # 初始化
from app01 import models
# 基于对象的查询
# 正向查询
book_obj = models.Book.objects.get(pk=3)
# print(book_obj)
# print(book_obj.pub)
# 反向查询
# 没有指定related_name 表名小写_set
pub_obj = models.Publisher.objects.get(pk=2)
# print(pub_obj.book_set,type(pub_obj.book_set)) # 关系管理对象
print(pub_obj.book_set.all())
# related_name='books'
# print(pub_obj.books.all())
# 基于字段的查询
ret = models.Book.objects.filter(pub__name='老男孩出版社')
# print(ret)
# 没有指定related_name 类名小写__字段
ret = models.Publisher.objects.filter(book__name='没有页码的python书')
# 指定related_name related_name__字段
ret = models.Publisher.objects.filter(books__name='没有页码的python书')
# 指定related_query_name='book' related_query_name_name__字段
# ret = models.Publisher.objects.filter(book__name='没有页码的python书')
# print(ret)
聚会和分组
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "about_orm.settings")
import django
django.setup() # 初始化
from app01 import models
from django.db.models import Max, Min, Avg, Sum, Count
ret = models.Book.objects.filter(id__gt=3).aggregate(max=Max('price'), min=Min('price'))
# 统计每一本书的作者个数
ret = models.Book.objects.annotate(Count('author')) # 按照book进行分组 统计作者的个数
# 统计出每个出版社的最便宜的书的价格
ret = models.Publisher.objects.annotate(Min('book__price')).values()
ret = models.Book.objects.values('pub', 'pub__name').annotate(Min('price'))
# 统计作者的图书的个数
ret = models.Author.objects.annotate(Count('books')).values()
ret = models.Book.objects.values('author').annotate(Count('id'))
# 统计不止一个作者的图书
ret = models.Book.objects.annotate(count=Count('author')).filter(count__gt=1)
# 根据一本图书作者数量的多少对查询集 QuerySet进行排序
ret = models.Book.objects.annotate(count=Count('author')).order_by('-count')
# 查询各个作者出的书的总价格
ret = models.Author.objects.annotate(Sum('books__price')).values()
ret = models.Book.objects.values('author').annotate(Sum('price'))
print(ret)
F
可以拿字段出来对比
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "about_orm.settings")
import django
django.setup() # 初始化
from app01 import models
from django.db.models import F, Q
# ret = models.Book.objects.filter(sale__gt=F('kucun'))
# ret = models.Book.objects.update(sale=F('sale')*2)
print(ret)
Q
| 或
- & 与
- 非
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "about_orm.settings")
import django
django.setup() # 初始化
from app01 import models
from django.db.models import F, Q
ret = models.Book.objects.exclude(pk__lte=3, pk__gte=2)
ret = models.Book.objects.filter(Q(~Q(Q(pk__gt=3) & Q(pk__lt=2))) & Q(name__contains='跟'))
print(ret)
事务
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "about_orm.settings")
import django
django.setup() # 初始化
from app01 import models
from django.db import transaction
try:
with transaction.atomic():
# 一系列的ORM操作
models.Publisher.objects.create(name='xxx')
models.Publisher.objects.create(name='xxx')
except Exception as e:
print(e)
print('xxx')
cookie
定义
保存在浏览器本地上一组组键值对
特点
1.cookie是由服务器进行设置的
2.浏览器保存在本地的
3.下次访问时自动携带对应的cookie
设置
response.set_cookie(key,value) # Set-Cookie: is_login=1; Path=/
response.set_signed_cookie('is_login','1',salt='xxxx')
#两种操作方式相同,第二种推荐,salt='xxxx',以xxxx来进行加盐
response.set_signed_cookie(key,value,salt='xxxx',max_age=5,path='/')
#max_age=5,让浏览器记住登录状态的时间最大为五秒,超过五秒清楚is_login
获取
request.COOKIES # {}
request.COOKIES[key]# 没有会报错
request.COOKIES.get(key)
request.get_signed_cookie(key,salt='xxxx',default='')
#default='' 默认值设置为空,不然取不到会报错
删除
response.delete_cookie(key) # 设置键值对的值为空 超时时间为0
装饰器
让装了装饰器的函数的名字不是inner,而是原来的名字
from functools import wraps
def wrapper(func):
@wraps(func) # 复制了原来函数的名字和注释
def inner(request,*arg,**kwargs):
# 之前
ret = func(request,*arg,**kwargs)
# 之后
return ret
return inner
@wrapper # f1 = wrapper(f1)
def f1(request):
pass
f1.__name__ # inner _> f1 #让装了装饰器的函数的名字不是inner,而是原来的名字
response
diango中有三种response
from django.shortcuts import render, redirect, HttpResponse
HttpResponse()
render()
redirect()
session
定义
保存在服务器上的一组组键值对,必须依赖cookie
为什么要有session?
- cookie保存在浏览器上,不太安全
- cookie的大小和个数有限制
设置
request.session[key] = value
request.session[is.login]=1
获取
request.session[key] #这样取值没有取值会报错
request.session.get(key)
删除
request.session.pop('is_login')
request.session.delete() # 删除所有的session数据
request.session.flush() # 删除所有的session数据和cookie
其他
request.session.clear_expired() #清除过期的session ?
request.session.set_expiry(value) #设置session过期的时间
配置
from django.conf import global_settings
#在global_settings中查看全局配置
#在settings中覆盖修改
SESSION_COOKIE_NAME = 'session' # cookie的名字
SESSION_SAVE_EVERY_REQUEST = True # 每次请求都更新session
SESSION_EXPIRE_AT_BROWSER_CLOSE = True # 浏览器关闭session就失效
SESSION_ENGINE = 'django.contrib.sessions.backends.db'
from django.contrib.sessions.backends import db #session在哪储存
# 数据库 缓存 缓存+数据库 文件 加密cookie
正则表达式
^ 开头
$ 结尾
[0-9] 数字
[a-zA-Z] 英文字母
[asd]{4,6}
+(一个或多个)
*(0个或多个)
? (0个或1个)
d 阿拉伯数字
w 匹配字母或数字或下划线或汉字 等价于'[^A-Za-z0-9_]
。
.(除了换行符之外的任意字符)
url的命名和反向解析
静态路由
url(r'^login/', views.login,name='login'),
反向解析ht
模板
{% url 'login' %} ——》 '/app01/login/'
py文件
from django.urls import reverse
reverse('login') ——》 '/app01/login/'
分组路由
位置传参
url(r'^del_publisher/(d+)/', views.del_publisher,name='del_pub'),
#分组后从url中捕获参数,捕获的参数会按照 位置传参 传递给函数
关键字传参
url(r'^del_publisher/(?P<pk>d+)/', views.del_publisher),
#分组后从url中捕获参数,捕获的参数会按照 关键字传参 传递给函数
反向解析
模板
{% url 'del_pub' '1' %} ——》 '/app01/del_publisher/1/'
py文件
from django.urls import reverse
reverse('del_pub',args=('1',)) ——》 '/app01/del_publisher/1/'
命令分组 路由
url(r'^del_publisher/(?P<pk>d+)/', views.del_publisher,name='del_pub'),
反向解析
模板
{% url 'del_pub' '1' %} ——》 '/app01/del_publisher/1/' 位置传参
{% url 'del_pub' pk='1' %} ——》 '/app01/del_publisher/1/' 关键字传参
py文件
from django.urls import reverse
reverse('del_pub',args=('1',)) ——》 '/app01/del_publisher/1/' 位置传参
reverse('del_pub',kwargs={'pk':'1'}) ——》 '/app01/del_publisher/1/' 关键字传参
namespace
多人合作开发解决路径重复问题
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^app01/',include('app01.urls',namespace='app01' )),
url(r'^app02/',include('app02.urls',namespace='app02')),
]
{% url 'app01:del_pub' '1' %}
reverse('app01:del_pub',args=('1',))
MVC
M: model 模型 与数据库交互
V: view 视图 HTML
C:controller 控制器 流程 和 业务逻辑
MTV
M:model ORM
T:template 模板 HTML
V:view 视图 业务逻辑
Django中的视图
FBV
def add_publisher(request,*args,**kwargs):
# 逻辑
return response
urls.py
url(r'^add_publisher',add_publisher )
CBV
from django.views import View
class Addpublisher(View):
def get(self,reuqest,*args,**kwargs)
# 处理GET请求的逻辑
self.request
return response
def post(self,reuqest,*args,**kwargs)
# 处理POST请求的逻辑
return response
urls.py
url(r'^add_publisher',Addpublisher.as_view() )
CBV中不同的请求能找到相应函数执行的原因:
继承了View,程序加载的时候,执行View中的Addpublisher.as_view(),
Addpublisher.as_view()定义了一个view函数,返回view,通过反射获取请求方式对应的方法(get/post)。
as_view的流程:
1. 程序加载的时候,执行Addpublisher.as_view():
定义了一个view函数,返回view
url(r'^add_publisher',view )
2. 请求到来时,执行view函数:
1. 实例化对象 ——》 self
2. self.request = request
3. 执行self.dispatch(request, *args, **kwargs)
1. 判断请求方式是否被允许:
1. 允许: 通过反射获取请求方式对应的方法(get/post) ——》 handler
2. 不允许:self.http_method_not_allowed ——》 handler
2. 执行handler,将它的结果返回
加装饰器
FBV
FBV 直接加
@login_required
def publisher(request):
CBV
解决装饰器加同时加在类和函数上时的参数导致的复用性问题:
不加method_decorator,加在类方法上,需要第一个参数需要是self,如果在login_required的inner括号里加上了self,函数便无法用这个装饰器了,所以装饰器加在类上时要借助method_decorator
from django.utils.decorators import method_decorator
登录验证的装饰器
def login_required(func):
def inner(request, *args, **kwargs):
# print(request.COOKIES)
# is_login = request.COOKIES.get('is_login')
# is_login = request.get_signed_cookie('is_login', salt='xxxx', default='')
is_login = request.session.get('is_login')
# print(request.path_info)
# print(request.get_full_path())
print(request.META.get('HTTP_ACCEPT'))
print(is_login)
if is_login != 1:
# 没有登录 跳转到登录页面
url = request.path_info
return redirect('/login/?url={}'.format(url))
ret = func(request, *args, **kwargs)
return ret
# if is_login == '1':
# # 登录
# ret = func(request, *args, **kwargs)
# return ret
# else:
# url = request.path_info
# return redirect('/login/?url={}'.format(url))
return inner
# 加在方法上
@method_decorator(login_required)
def get(self, request, *args, **kwargs):
# 重写dispatch方法,加在dispatch方法上
@method_decorator(login_required)
def dispatch(self, request, *args, **kwargs):
ret = super().dispatch(request, *args, **kwargs)
return ret
#直接找到父类的dispatch方法加上去 ——最简单!推荐!
@method_decorator(login_required,name='dispatch')
class Addpublisher(View)
# 加在类上
@method_decorator(login_required,name='post')
@method_decorator(login_required,name='get')
class Addpublisher(View)
request对象的方法
request.method # 请求方法 GET POST
request.GET # url上携带的参数 {}
request.POST # form提交POST请求的参数 {} 编码类型是urlencode
request.body # 请求体 b''
request.path_info # 路径 不包含ip和端口 也不包含参数
request.COOKIES # cookie的字典
request.session # session的数据
request.FILES # 上传的文件 编码的类型是 enctype="multipart/form-data"
request.META # 请求头 小写 ——》 大写 HTTP_ - _> _
request.get_full_path() # 路径 不包含ip和端口 包含参数
request.get_signed_cookie(key) # 获取加密cookie
request.is_ajax() # 是否是ajax
response对象的方法
HttpResponse('xxxx') # 返回字符串 Content-Type: text/html; charset=utf-8
render(request,'模板的路径',{}) # 返回一个页面
redirect('路径') # 重定向 状态码301 302 响应头 Location:路径
from django.http.response import JsonResponse
模板中
变量 {{ 变量名 }}
通过(.)取相应的内容
.key > .属性 .方法 > .索引
过滤器
{{ 变量|过滤器 }} {{ 变量|过滤器:参数 }}
{{ kong | default:'没有传参' }}
filter
{{ 变量|filter:参数 }}
default add length slice join first last lower upper title truncatechars truncatewords
date:"Y-m-d H:i:s" safe
USE_L10N = False
DATETIME_FORMAT = 'Y-m-d H:i:s'
标签
{% %}
for
{% for i in list %}
{{ i }}
{% endfor %}
forloop.counter 循环的序号 从1开始
forloop.counter0 循环的序号 从0开始
forloop.revcounter 循环的序号 到1结束
forloop.revcounter0 循环的序号 到0结束
forloop.first 是否是第一次循环
forloop.last 是否是最后一次循环
forloop.parentloop 当前循环的外层循环 {}
{% for i in list %}
{{ forloop }}
{{ i }}
{% empty %}
空空如也
{% endfor %}
if 不支持算数运算
{% if 条件 %}
x
{% elif 条件1 %}
xx
{% else %}
xxx
{% endif %}
注意点:
- 不支持算数运算
- 不支持连续判断 10 > 5 > 1 false
csrf
{% csrf_token %} # form表单中有一个隐藏的input标签 name=‘csrfmiddlewaretoken’
母版和继承
母版:
模板,提取出多个页面公共部分放在一个母版中,定义上多个block块,让子页面重新复写。
继承:
- {% extends ‘母版的名字’ %}
2. 重写block块。
注意点:
1. {% extends ‘母版的名字’ %} 母版名字 的引号好带上 不带会当做变量
-
{% extends ‘母版的名字’ %} 上不要写内容
-
要替换母版的内容都写在block块中
-
定义多个block块, css,js
-
组件:
把一小段的HTML代码段 ——》 nav.html
{% include 'nav.html ' %}
静态文件的使用:
{% load static %}
"{% static '静态文件的相对路径' %}"
母版和组件的继承和引用怎么用?
使用admin的步骤
-
创建超级用户
python manage.py createsuperuser
-
注册model
在app下的admin.py中注册
from django.contrib import admin from app01 import models # Register your models here. admin.site.register(models.Person)
-
访问网站登录操作
中间件
process_request(self,request)
参数:
request 请求的对象,和视图中的request是同一个
执行时间:视图函数之前
执行顺序:
按照注册的顺序 顺序执行
返回值
None : 正常流程
HttpReponse: 当前中间件之后的中间件的process_request方法、路由匹配、视图也不执行,直接执行当前中间件的process_response方法
process_response(self, request, response)
参数:
request 请求的对象,和视图中的request是同一个
response 返回的响应对象
执行时间:视图函数之后
执行顺序:
按照注册的顺序 倒叙执行
返回值
HttpReponse: 必须返回响应对象
process_view(self, request, view_func, view_args, view_kwargs)
参数:
request 请求的对象,和视图中的request是同一个
view_func 视图函数
view_args 视图函数的位置参数
view_kwargs 视图函数的关键字参数
执行时间:路由匹配之后,视图函数之前
执行顺序:
按照注册的顺序 顺序执行
返回值
None 正常流程
HttpReponse: 当前中间件之后的process_view、视图不执行,执行最后一个中间的process_response
process_exception(self, request, exception)
参数:
request 请求的对象,和视图中的request是同一个
exception 错误对象
执行时间(触发条件):视图层面有错误才执行
执行顺序:
按照注册的顺序 倒叙执行
返回值
None 当前中间没有处理异常,交由下一个中间件处理异常,所有的中间件都没有处理,Django处理错误
HttpReponse: 当前中间处理好异常,之后执行最后一个中间件的process_response方法
pocess_template_response(self,request,response)
参数:
request 请求的对象,和视图中的request是同一个
response 返回的响应对象
执行时间:视图必须返回一个template_response对象
执行顺序:
按照注册的顺序 倒叙执行
返回值
HttpReponse: 必须返回响应对象
response.template_name = 'index1.html' # 改模板
response.context_data # 改变量
1. 简介目录
![img](file:///C:UsersacerAppDataRoamingTencentQQTemp%W@GJ$ACOF(TYDYECOKVDYB.png)https://www.cnblogs.com/maple-shaw/p/9029086.html
2. 路由系统
![img](file:///C:UsersacerAppDataRoamingTencentQQTemp%W@GJ$ACOF(TYDYECOKVDYB.png)https://www.cnblogs.com/maple-shaw/articles/9282718.html
3. 视图
![img](file:///C:UsersacerAppDataRoamingTencentQQTemp%W@GJ$ACOF(TYDYECOKVDYB.png)https://www.cnblogs.com/maple-shaw/articles/9285269.html
4. 模板
![img](file:///C:UsersacerAppDataRoamingTencentQQTemp%W@GJ$ACOF(TYDYECOKVDYB.png)https://www.cnblogs.com/maple-shaw/articles/9333821.html
5.ORM
字段和参数:![img](file:///C:UsersacerAppDataRoamingTencentQQTemp%W@GJ$ACOF(TYDYECOKVDYB.png)https://www.cnblogs.com/maple-shaw/articles/9323320.html
查询操作:![img](file:///C:UsersacerAppDataRoamingTencentQQTemp%W@GJ$ACOF(TYDYECOKVDYB.png)https://www.cnblogs.com/maple-shaw/articles/9403501.html
练习题:![img](file:///C:UsersacerAppDataRoamingTencentQQTemp%W@GJ$ACOF(TYDYECOKVDYB.png)https://www.cnblogs.com/maple-shaw/articles/9414626.html
6. cookie和session
![img](file:///C:UsersacerAppDataRoamingTencentQQTemp%W@GJ$ACOF(TYDYECOKVDYB.png)https://www.cnblogs.com/maple-shaw/articles/9502602.html
7.中间件
![img](file:///C:UsersacerAppDataRoamingTencentQQTemp%W@GJ$ACOF(TYDYECOKVDYB.png)https://www.cnblogs.com/maple-shaw/articles/9333824.html
8. ajax
![img](file:///C:UsersacerAppDataRoamingTencentQQTemp%W@GJ$ACOF(TYDYECOKVDYB.png)https://www.cnblogs.com/maple-shaw/articles/9524153.html
9. form组件
![img](file:///C:UsersacerAppDataRoamingTencentQQTemp%W@GJ$ACOF(TYDYECOKVDYB.png)https://www.cnblogs.com/maple-shaw/articles/9537309.html
AJAX
js技术,发送请求的一种方式.
特点:
- 异步
- 传输的数据量小
- 局部刷新
发请求的途径:
- form表单发请求 指定method GET/POST
- action 地址 method enctype
- input select option 标签要有name属性,有的还需要有value
- 有button按钮或者type='submit'的input框
- 直接在地址栏中输入地址 回车 get
- a标签 get
- ajax
发ajax请求的写法:
jQuery:
$.ajax({
url: '/test/', // url路径
type: 'post', // 请求方式
data: { // 请求数据
name: 'alex',
age: 84,
hobby: JSON.stringify(['吐口水', 'TESA', '篮球', '毒鸡汤']),
},
success: function (res) { // 响应成功的回调函数
console.log(res);
console.log(res.status);
console.log(typeof(res))
},
error:function (res) { // 响应失败的回调函数
console.log(res)
}
})
上传文件
$('#b1').click(function () {
var form_obj = new FormData(); // enctype="multipart/form-data"
form_obj.append('name', 'alex')
form_obj.append('f1', $('#f1')[0].files[0])
$.ajax({
url: '/upload/',
type: 'post',
data: form_obj,
processData: false, // 不需要处理编码方式
contentType: false, // 不需要处理contentType请求头
success:function (res) { // 响应成功的回调函数 res _> 返回的响应体
alert(res)
}
})
})
CSRF中间件
-
process_request方法:
从cookie中获取csrftoken的值,放到request.META中
-
process_view方法:
- 判断视图是否使用csrf_exempt装饰器,使用了就不校验
- 判断请求方式是否是'GET', 'HEAD', 'OPTIONS', 'TRACE',如果是,也不校验
- 进行校验:
- csrf_token = request.META.get('CSRF_COOKIE') # cookie中获取csrftoken的值
- 请求方式是POST
- request_csrf_token = request.POST.get('csrfmiddlewaretoken', '')
- 获取不到,从头中获取x-csrftoken的值 = >request_csrf_token
- 进行比较csrf_token request_csrf_token的值:
- 对比成功 接收请求
- 对比不成功 拒绝请求
ajax通过Django的csrf校验
前提:
有csrftoken的cookie:
-
{% csrf_token %}
-
from django.views.decorators.csrf ensure_csrf_cookie
方式一:
给data中添加csrfmiddlewaretoken的键值对
方式二:
给headers添加x-csrftoken的键值对
headers: {
'x-csrftoken': $('[name="csrfmiddlewaretoken"]').val()},
方式三:
导入文件
csrf相关的装饰器
from django.views.decorators.csrf import csrf_exempt,csrf_protect,ensure_csrf_cookie
csrf_exempt 豁免csrf的校验 CBV需要加在dispatch方法上才生效
csrf_protect 强制校验
ensure_csrf_cookie 添加csrftoken的cookie
form组件
定义:
from django import forms
class RegForm(forms.Form):
user = forms.CharField(label='用户名')
pwd = forms.CharField(label='密码',widget=forms.PasswordInput)
使用:
视图函数:
def reg2(request):
form_obj = RegForm()
if request.method == 'POST':
form_obj = RegForm(request.POST)
if form_obj.is_valid():
# 校验成功
# form_obj.cleaned_data # 清洗后的数据
return HttpResponse('注册成功')
return render(request, 'reg2.html', {'form_obj': form_obj})
模板:
{{ form_obj.as_p }} _> 生成所有字段的input框
{{ form_obj.user }} _> 某个字段的input框
{{ form_obj.user.label }} _> 某个字段的中文提示
{{ form_obj.user.id_for_label }} _> 某个字段的input框的ID
{{ form_obj.errors }} _> 所有的错误
{{ form_obj.user.errors }} _> 某个字段的所有错误
{{ form_obj.user.errors.0 }} _> 某个字段的第一个错误
常用的字段
CharField
ChoiceField
MultipleChoiceField
字段的参数
initial 初始值
required 是否必填
disabled 是否禁用
label 中文提示
initial 默认值
min_length 最小长度
error_messages 错误信息
choices 可选择的数据
校验
-
自带的校验
-
自定义校验规则
-
写函数
from django.core.exceptions import ValidationError def check_name(value): # 自定义校验规则 # 如果校验合格 什么都不做 # 校验不合格 抛出异常 if 'alex' in value: raise ValidationError('不能包含alex,非法字符')
-
-
使用内置的校验器
from django.core.validators import RegexValidator validators=[RegexValidator(r'^1[3-9]d{9}$', '手机号格式不正确')]
局部钩子和全局钩子
def clean_user(self):
# 局部钩子
# 校验成功 返回当前字段的值
# 校验不成功 抛出异常
if 'alex' in self.cleaned_data.get('user'):
raise ValidationError('不能包含alex,非法字符')
return self.cleaned_data.get('user')
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
else:
self.add_error('re_pwd','两次密码不一致!!!')
raise ValidationError('两次密码不一致')