创建项目框架
django-admin startproject 项目名
创建子app
-
业务分化,可以优化团队合作,可以明确找锅
-
python manage.py startapp 子app名
启动项目
-
python manage.py runserver
项目目录结构
-
__init__.py
: 声明当前文件夹为一个可导入的包 -
settings.py
: 整个项目的配置文件 -
urls.py
: 主控路由映射文件 -
wsgi.py
: 项目上线时使用的uwsgi服务器的连接文件 -
manage.py
: 控制管理当前项目
子app目录结构
-
admin.py
: django内置了一个数据库管理工具 -
models.py
: 数据库,模型类 -
views.py
: 存储不同
配置settings.py
-
语言 转中文
LANGUAGE_CODE = 'zh-Hans' -
定义时区
TIME_ZONE = 'Asia/Shanghai' -
配置模板 在TEMPLATES列表字典中配置DIRS 并手动创建template文件夹
TEMPLATES = [
{
'DIRS': [os.path.join(BASE_DIR,'template')],
}] -
谁可以访问我
ALLOWED_HOSTS = ["*"] -
配置图片 手动创建static文件夹
STATICFILES_DIRS=(
os.path.join(BASE_DIR,'static'),
) -
在INSTALLED_APPS中加入子app 否则无法创建数据库模板类
INSTALLED_APPS = [
'子app名',
]
ORM映射
-
在models.py中创建模板类
class Student(models.Model):
# 学生名字
name = models.CharField(max_length=30,verbose_name='学生名字') # 字符串 最大30字符
# 年龄
age = models.IntegerField(default=0,verbose_name='年龄') # 数字类型 默认为 0岁 -
在admin.py中注册模板类
from . import models
admin.site.register(models.Student) -
为自己的app创建表
1. python manage.py migrate 框架Django有自带的数据表 生成相关数据表
2. python manage.py makemigrations 查找差异 创建迁移文件
3. python manage.py migrate 根据迁移文件 生成数据表及字段
admin界面
-
Django所提供用来帮助你管理项目所使用到的数据表的
*注意: 访问之前先创建 框架Django有自带的数据表 也就是 python manage.py migrate
否则会保Django-session的错
-
为admin界面创建超级用户 管理所有app:
python3 manage.py createsuperuser
-
用来为数据表具体某一个数据提供一个可读性更高的名字
#提供一个可读性更高的名字
def __str__(self):
return self.name
Django-Hello
返回一个html页面
-
在template中创建一个xxx.html模板文件
-
在views.py写相关视图函数,连通一个xxx.html模板
-
在urls.py里配置相关path路径
html模板语法
模板变量,模板标签
·为模板页面返回模板变量
- {{ var }} 来自views.py的 var 变量
·编写视图函数:
- app -> views.py -> def(request)
- 视图函数操作模型类表
* 让视图函数返回所有学生
* content = models.Student.objects.all()
* return render(request,'xxx.html',locals())
·编写映射关系: 路由映射关系是通过path函数找到对应视图
- 路由映射,必须写末尾的斜杠
- 路由查找,从上到下,匹配的到某一个,直接调用视图函数即可
- 404:页面没找到 403:服务器拒绝 402:保留位 401:用户权限鉴定失败 400:错误的请求
·返回模板页面 == HTML页面
- 配置模板页面的路径,设置一个路径在settings文件下,保存所有的静态目录,TEMPLATES
- 视图函数使用render进行页面渲染并返回
·模板标签:
- 必须要有闭合标签
- 如:{% for i in 迭代对象 %} {% endfor %}
静态资源:
#·css,js,mp3,audio -----》 路径查找: 绝对、相对
#- settings.py ->
STATICFILES_DIRS=(os.path.join(BASE_DIR,'static'),)
#·在html中上方全局加载
- {% load static %}
让视图函数从数据库里拿数据
-
有一个数据库:sqlite3 学习使用的轻量级数据库文件
-
创建表:吧表创建在对应的app下-> models.py
-
python manage.py makemigrations 查找当前数据库差异,迁移文件
-
python manage.py migrate 通过迁移文件执行真正的SQL
获取用户表单
-
用户的提交数据方式:get,post request.method == 'GET' or 'POST'
-
明确防跨站请求伪造令牌
—— {% csrf_token %}
视图函数判断请求方式 post
-
request.POST.get(‘表单的name值’) -> 表单-> value
-
存储数据 models.Student.create(字段=value等等)
-
request.method # 判断当前用户访问方式
-
request.method == 'GET'
-
request.method == 'POST'
-
-
-
-
获取表单多值时候,不能使用get函数
-
我们需要使用getlist 获取多个值
-
解析到的数据类型为:application/x-www-form-urlencoded,form-data
-
-
-
视图函数判断请求方式 get
-
request.GET:获取GET形式提交的数据
-
get形式提交的数据
-
-
获取ip: request.META:访问的头部信息
-
REMOTE_ADDR:获取访问者的IP地址
-
if 'HTTP_X_FORWARDED' in request.META:
ip = request.META.get('HTTP_X_FORWARDED')
else:
ip = request.META['REMOTE_ADDR']
#查询数据库ip是否已存在
models.Students.objects.get(ip=IP)
-
-
获取文件类型
-
request.FILES
-
静态路由
#例:
path('路由字符串/', views.index)
path('abc/', views.index)动态路由
将参数做到连接里
-
路由命名传参:
-
path('index/<str:name>/<int:age>/', views.index), -
re_path(r'^index/(?P<name>[a-z]{3})/(?P<age>\d{1,2})/',views.index ), -
(?P<id>\w+)/
-
-
路由非命名传参:更灵活,但是必须对应参数位置
-
re_path(r'^index/([a-z]{3})/(\d{1,2})/',views.index)
-
-
空白符号:
\r \n \v \t \b
路由分发
-
路由分发特性与优点:
-
APP:业务分化,方便团队合作
-
主路由文件:只做分发
-
from django.urls import path,re_path,include
urlpatterns = [
path('admin/', admin.site.urls),
re_path('',include('xue_app.urls'))
] -
子路由文件:需要我们手动创建相关app的urls.py,实现视图映射
-
from django.urls import path
#导入子app的视图文件
from xue_app import views
#配置子app路由 结尾加 /
urlpatterns = [
path('', views.index),
path('show/', views.show),
] -
主路由-》子路由-》分发
-
路由命名
路由命名特性与优点
当路由修改时,如果HTML页面跳转与视图函数重定向使用的是原始的连接内容,那么都需要更改
耦合性太强
现在通过路由反向解析,可以解决这个问题
-
path('', views, name=)
-
html:
-
href={% url 'url_name' 'args1' 'args2'... %}
-
-
views:
-
from django.shortcuts import render,redirect,reverse
redirect(reverse('url_name',args=('args1','args2')))
-
命名空间
-
在路由文件:子路由
-
app_name 全局变量,一般使用app名作为命名空间名
-
href={% url 'app_name:url_name' 'args1' 'args2'... %} -
from django.shortcuts import render,redirect,reverse
redirect(reverse('app_name:url_name',args=('args1','args2')))
-
-
用户的提交数据方式:get,post request.method == 'GET' or 'POST'
-
明确防跨站请求伪造令牌 {% csrf_token %}
-
视图函数判断请求方式 POST
-
request.POST.get() -> 表单 -> value值
-
存储数据 models.Student.create(字段=value等等)
模板过滤器
-
{{ var|add:1 }}
-
add:过滤器名字
-
参数:var、1
-
-
模板过滤器最多只能接收两个参数,必须要有一个参数:1~2
自定义过滤器
创建自定义过滤器流程
-
将当前app注册到settings->INSTALL_APPS
-
在app目录下创建
templatetags
文件夹,用来保存所有的过滤器文件 -
在templatetags文件夹下创建一个
__init__.py
文件,声明当前文件夹为一个可导入的包 -
在templatetags文件夹下创建一个你的.py文件,用来保存对应的过滤器函数
-
导入from django.template import Library
-
需要在这个文件下有一个全局变量名为:register = Library()
-
编写过滤器函数
-
注册函数为真正过滤器
-
@register.filter(name='your_func')
-
-
模板页面要想使用自定义过滤器,首先导入过滤器文件:{% load youfilter %}
-
{{ var|your_func}}
自定义标签
-
与自定义过滤器一个文件夹下即可
-
@register.simple_tag(name='')
模板继承
-
首先在模板文件夹下定义一个base.html
-
可以在子模版中,通过最顶部使用{% extends 'base.html' %}引入过来
-
在base.html的父模板页面中可以使用{% block title %}{% endblock %}指明块
-
父模板中没有的块,在子模版中强行加入,是不会被渲染出来的
思考:解决了什么问题?HTML代码编写时,更精简,复用性更高
模板组件
-
-
使用{% include %} 标签将额外编写的组件HTML代码加载进来
-
可以实现HTML代码的复用,解耦和
-
节约代码量,使HTML干净整洁
配置settings.py文件
# 找到DATABASES
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
# 注掉上面 变更为
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql', # 数据库引擎
'NAME': "django_data", # 使用的数据库库名,该库需要手动创建
"USER": "root", # 自己的用户名
"PASSWORD": "chenkai", # 自己的数据库密码
"HOST": "172.16.19.49", # 数据库主机地址 自己的本地ip
"PORT": "3306" # mysql的端口号
}
}
主机“CK”不允许连接到此MySQL服务器的问题
-
使用wins系统可能会遇到一个问题:
解决方法:
进入MySQL的bin目录,执行如下命令:
#登录mysql
mysql -u 用户名 -p密码
# 进入mysql配置
user mysql;
# 变更配置
update user set host = '%' where user = 'root';
# 给出 特权 Ps:让他可以这么做
flush privileges;
关系
一对一关联反向查询
查询:
-
表层面:
-
查询所有是教授的老师 英雄为母表 ADC为子表
-
子表 有一个继承母表市局的字段(正向查询),同样母表也有一个隐藏的小写子表表名字段用来查询子表的数据(反向查询)
-
母表.objects.filter(小写子表名__子表特有字段__gt=0) ------》 反向查询
-
用的是隐藏起来哪个关联表字段进行查询 就是反向查询
-
子表名.继承母表字段名 ---》 正向
-
-
数据层面
-
m1 = 子表.objects.get() ---》反向m1.继承母表的变量字段 ----》 正向
-
小写子表名 不是一条m1的字段,他是django做出来隐藏的
-
#英雄 --》 ADC(为子表)
#增
a1 = models.Hero.objects.create(name='黄忠')
a2 = models.Skill.objects.create(kill=a1,skill='百步穿杨')
#查
b1 = models.Hero.objects.get(name='黄忠')
b2 = models.Skill.objects.get(kill=b1)
#改
b2.skill='一箭狙神'
b2.save()
#删
b2.delete()
-
多对一查询
-
关系Foreigkey建立在多的一方
-
例:关系:老师学生
-
-
数据层面
-
老师结果.student_set.all()
-----》 反向 -
_set
==models.objects
-
根据外键 查询 ---》 正向
-
-
表层面:
-
Teacher.objects.filter(student__name__startswith='贾')
---》 反向 -
Student.objects.filter(tea__name='贾老师')
---》 正向
-
-
修改
-
单独修改简单:直接字段赋值,save() 即可
-
批量修改
-
结果集.update(tea=要变更的值)
直接为这些set数据 批量修改 -
直接立竿见影到数据库,不需要save
-
-
删除:
-
on_delete =
-
models.CASCADE
:老师删除,球员也跟着消失,外键绑定 -
models.SET_NULL
:老师删除,球员外键为null,数据还在,外键关系消失 -
null=True
-
blank=True
-
shell
-
开启一个包含当前项目所有环境的命令行工具命令:
python manage.py shell
-
例:终端在manage.py 同级目录下:
python manage.py shell
-
表关系 学生 ---》 老师
添加
from s_app import models
a1 = models.Teacher.objects.create(name='李老师')
a2 = models.Teacher.objects.create(name='贾老师')
a1
<Teacher: 李老师>
a2
<Teacher: 贾老师>
q1 = models.Student.objects.create(tea=a1,name='张小宁')
q2 = models.Student.objects.create(tea=a1,name='贾小璇')
q3 = models.Student.objects.create(tea=a2,name='李小括')
q4 = models.Student.objects.create(tea=a2,name='潘小飞')
q1
<Student: 张小宁>
q2
<Student: 贾小璇>
q3
<Student: 李小括>
q4
<Student: 潘小飞>
q1.tea.name
'李老师'
查:
-
查看贾老师班里都有谁
c1 = models.Student.objects.filter(tea__name='贾老师')
c1
<QuerySet [<Student: 李小括>, <Student: 潘小飞>]>
-
产看潘小飞是哪个老师教的
c2 = models.Teacher.objects.filter(student__name='潘小飞')
c2
<QuerySet [<Teacher: 贾老师>]>
改:
# 把潘小飞调给李老师教
q4.tea.name = '李老师'
q4.save()
q4.tea.name
'李老师'
把所有同学调给贾老师教
l = models.Student.objects.filter(tea=a1)
j = models.Student.objects.filter(tea=a2)
l.update(tea=a2)
删
-
结果集.直接delete()
#删除张小宁
q1.delete()
#批量删除贾老师所有学生(将一个数据集直接删除)
j.delete()
多对多
-
多对多关系在模型中使用
ManyToManyField
字段定义
修改/外键关系操作
-
数据保留,外键关系消失,删除和添加只影响外键关系
指定或批量 添加外键关系
-
add
-----》 例:子表结果.关联字段.add(某结果集[0],某结果集[3],某结果集[6],)
指定或批量 删除外键关系
-
remove
-----》 例:子表结果.关联字段.remove(某结果集[0],某结果集[3],某结果集[6],)
彻底删除
-
结果/结果集.delete()
查询
-
数据层面 :针对某些特定字段数据进行查询 ---> (反向查询:
关联表_set
)-
正向
-
子表结果.关联字段.all()
-
-
反向
-
母表结果.隐藏小写子表名字段__set.all()
-
-
-
表层面 : 针对的是整张表的数据 ---> (反向查询:直接使用
小写关联表名
)-
正向
-
子表.objects.filter(关联字段__子表某字段=‘一个指定结果’)
-
-
反向
-
母表.objects.filter(隐藏的小写子表名__子表某字段=‘一个指定结果’
-
-
COOKIE:
-
什么是cookie?
-
类似令牌一样的东西,用来把每次客户端访问服务端的数据信息提交给我
-
request 获取
-
response 设置
-
明文传输,极度不安全
-
默认有效期:随客户端关闭而消失
-
Django对于Cookie的处理方式
取
每个HttpRequest
对象都对应一个COOKIES
对象,该对象是字典形式.
request.COOKIES['session变量名'] # 获取
存
对COOKIES的设置通过一个页面HttpResponse
对象的set_cookie
HttpResponse.set_cookie(key, value='', max_age=None, expires=None, path='/', domain=None, secure=None, httponly=False)
#语法: 页面.set_cookie('session变量名',session的值) # 设置 session值
删
delete_cookie['session变量名']
防止篡改COOKIE
-
通过
set_signed_cookie
函数进行持有签名的 COOKIE 值设置,避免用户在客户端进行修改 -
要记得,这个函数并不是对 COOKIE 值进行加密
HttpResonse.set_signed_cookie(key, value, salt='', max_age=None, expires=None, path='/',
domain=None, secure=None, httponly=True)
-
为 cookie 值添加签名,其余参数与
set_cookie
相同
Request.get_signed_cookie(key, salt='', max_age=None)
-
从用户请求中获取通过salt盐值加了签名的 Cookie 值。 这里的 salt 要与之前存储时使用的 salt 值相同才可以解析出正确结果。 还要注意的是,如果对应的key值不存在,则会引发
KeyError
异常,所以要记得异常捕获来确定是否含 有 Cookie 值
def check_salt_cookie(request): try: salt_cookie = request.get_signed_cookie(key='salt_cookie',salt='nice') except KeyError: #获取不到该key值的Cookie response = HttpResponse('正在设置一个salt Cookie值') response.set_signed_cookie(key='salt_cookie',salt='nice',value='salt_cookie') return response else: #获取到了对应key值,展示到新的HttpResonse中 return HttpResponse('获取到的salt Cookie值:%s' % salt_cookie) 第一次访问的时候,还没有加 Cookie 值,所以我们在获取的时候会抛出 KeyError 异常
此时捕获异常,并且设置 Cookie 即可;
再次刷新的时候,因为这里已经给出了 Cookie 值,则不会引发异常,会在页面中展示获取到的加盐 cookie
session
-
什么是session?
-
session是基于cookie的,在网络中,又称会话控制,简称会话。用以存储用户访问站点时所需的信息及配置属性。当用户在我 们的 Web 服务中跳转时,存储在 Session 中的数据不会丢失,可以一直在整个会话过程中存活。
-
在
django
中,默认的 Session 存储在数据库中session
表里。默认有效期为两个星期。 -
加密传输 更安全
-
客户端访问服务端,服务端为每一个客户端返回一个唯一的 sessionid ,比如 xxx 。
-
客户端需要保持某些状态,比如维持登陆。那么服务端会构造一个 {sessionid: xxx } 类似这样的字典数据加 到 Cookie 中发送给用户。注意此时,只是一个随机字符串,返回给客户端的内容并不会像之前一样包含实际数 据。
-
服务端在后台把返回给客户端的 xxx 字符串作为 key 值,对应需要保存的服务端数据为一个新的字典,存储在 服务器上,例如: {xxx : {id:1}}
-
获取Session
session_data = request.session.get(Key)
session_data = request.session[Key]
获取Session
ession_data = request.session.get(Key)
session_data = request.session[Key]
删除Session
del request.seesion[Key]
-
删除对应session, Key 值不存在时,引发 KeyError
request.session.clear()
-
清空 Session 中的所有数据。这里客户端还会保留 sessionid 只不过在服务端 sessionid 对应的数据没有了。
request.session.flush()
INSTALLED_APPS = ( ... 'django.contrib.sessions', ... )
-
MIDDLEWARE_CLASSES = ( 'django.contrib.sessions.middleware.SessionMiddleware', ... )
-
直接删除当前客户端的的
Seesion
数据。这里不光服务端sessionid
对应的数据没有了,客户端的sessionid
也会被删除