Django
虚拟环境
创建:virtualenv --no-site-packages -p python.exe的路径 环境名
安装与使用
安装:pip install django==2.1.7
创建Django项目:django-admin startproject 项目名
创建django应用:python manage.py startapp 应用名
启动,修改IP和端口
修改端口:python manage.py runserver 端口号
修改IP和端口:python manage.py runserver IP:端口号
数据库简单配置与迁移
修改settings.py文件中DATABASE的数据:NAME,USER,PASSWORD,HOST,PORT,OPTIONS
不管用不用,都必须迁移默认的模型 迁移django默认提供的模型:python manage.py migrate
管理后台
访问:IP:端口/admin/
创建账号:python manage.py createsuperuser
模型
迁移
生成迁移文件: python manage.py makemigrations
执行迁移文件:python manage.py migrate
注意:当第一次迁移Django默认提供的表时,直接执行migrate命令即可
模型定义
-
字段定义
IntegerField:整型字段
CharField:字符串
BooleanField:布尔值
DateTimeField:年月日时分秒字段
DateField:年月日
TimeField:时间戳
ImageField:图片
FloatField:浮点数
DecimalField:浮点数,指定了长度的浮点数
TextField:文本,textarea
AutoField:自增字段,不用定义
-
约束定义
max_length:最大长度
min_length:最小长度
unique:是否唯一
null:是否为空
default:默认值
auto_now_add和auto_now:互斥
模型操作
-
增
对象.save()
模型.objects.create(字段1=值1,字段2=值2,...)
-
删
对象.delete()
模型.objects.filter().delete()
-
改
修改的对象.save()
模型.objects.filter().update(字段1=值1,字段2=值2,...)
-
查
all():queryset结果
first():取结果中第一个对象
last():取结果中最后一个对象
模型.objects.filter(字段='值')
-
模型.objects.get(条件)
条件必须成立
查询结果只有一个
exclude(条件):过滤不满足条件的信息
count():查询结果的个数
values('字段'):将对象的内容序列化成字典/json
-
order_by('字段')
升序:order_by('字段')
降序:order_by('-字段')
-
contains:包含
- 模型.objects.filter(字段__contains='值')
startswith:以什么开头
endswith:以什么结尾
-
大小于
大于,大于等于:gt,gte
小于,小于等于:lt, lte
-
aggregate:聚合
- Avg, Sum, Count, Max, Min
-
F:对比两个属性字段,可以进行加减算法
- 模型.objects.filter(字段1__gt=F('字段2'))
-
Q:用于与或非
或:Q(条件1) | Q(条件2)
非:~Q(条件1)
模型关系
一对一
OneToOneField(关联模型)
-
模型定义
class A(): id = models.IntegerField()
class B(): aa = models.OneToOneField(A, related_name='cc')
已知:A对象a,查询B对象 related_name没定义时: a.b related_name已定义时: a.cc
已知:B对象b,查询A对象 b.aa
注意:OneToOneField定义的字段可以写在关联模型的任意一方
一对多
ForeignKey(关联模型)
-
模型定义
class A(): id
class B(): aa = ForeignKey(A, related_name='cc')
已知:A对象a,查询B对象 related_name没定义时: a.b_set.all() related_name已定义时: a.cc.all()
已知:B对象b,查询A对象 b.aa
注意:ForeignKey定义的字段表示多的对方,因此只能放在'多'的模型中
多对多
ManyToManyField(关联模型):会自动生成中间表
-
模型定义
class A(): id
class B(): aa = ManyToMany(A, related_name='cc')
已知:A对象a,查询B对象 related_name没定义时: a.b_set.all()
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="" cid="n198" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit;">related_name已定义时:
a.cc.all()</pre>已知:B对象b,查询A对象 b.aa.all()
注意:ManyToMany定义的字段可以写在关联模型的任意一方
中间表的添加:add()、删除:remove()
字段中的on_delete参数值
models.CASCADE: 表示主键所在行的数据被删,外键所在行的数据也会被删,是完全关联在一起的
models.PROTECT: 表示主键作为外键存在别的表中时,不让删除主键的数据
models.SET_NULL: 表示主键删除,外键置空
模板
父模板:用于挖坑{% block name %} {% endblock %}
子模板:负责继承父模板后,进行填坑
标签:{% 标签 %}
{% extends '父模板' %}
{% block name %} {% endblock %}
{% if 条件 %} {% else %} {% endif %}
{% ifequal 变量 值 %} {% endifequal %}
{% for i in [] %} {% endfor %}
解析静态文件地址: {% static 'css/xxx.css' %} 继承模板的时候,要有: {% load static %}
解析路由地址: {% url 'user:index' %}
变量:{{ 变量名 }}
{{ forloop.counter }}
{{ forloop.counter0 }}
{{ forloop.revcounter }}
{{ forloop.revcounter1 }}
{{ forloop.first }}
{{ forloop.last }}
{{ stu.course.all }}:通过学生查询所有的课程信息
{{ stu.course.下标 }}
过滤器
- 定义:使用管道符 '|'
路由规则
path
转换器:int, str, uuid, path
re_path
/(\d+)/(\w+)/
(?P<参数名>\d+)
include
urlpatterns = [ path('admin/', admin.site.urls), # 包含 # TODO:Django2.0以下写法, path('goods/', include('goods.urls')), path('app/', include('app.urls')) ]
- 拆分路由地址,将不同应用的URL文件进行拆分
请求与响应
请求
method:判断请求方式,主要GET/POST
path:获取访问的路由地址
FILES:获取图片或文件的信息
-
GET:获取get请求方式的数据
get()
getlist()
POST:获取post请求方式的数据
COOKIES:cookie内容
session:存储在服务端的数据
响应
-
跳转:HttpResponseRedirect()
-
无参
- HttpResponseRedirect(reverse('namespace:name'))
-
有参
HttpResponseRedirect(reverse('namespace:name', kwargs={'参数名': '值'}))
HttpResponseRedirect(reverse('namespace:name', args=(值, )))
-
页面反向解析
- {% url 'namespace:name' 值1 值2 值3 ... %}
-
JsonResponse():响应json格式的数据
HttpResponse(字符串)
render(页面)
用户USER
使用django自带的USER模块
注册:User.objects.create_user()
校验:user = auth.authenticate(username, password)
登录:auth.login(request, user)
退出:auth.logout(requset)
装饰器:login_required() 要配合在setting里面设置才有用: LOGIN_URL = '/user/login/'
自定义USER模块
登录:request.session['user_id'] = user.id 添加键值对的时候,同时会把数据库中创建的session_key传给浏览器
-
退出
request.session.flush() 同时删除数据库和浏览器中的session
request.session.delete(session_key) 删除数据库中对应的session记录
del request.session['user_id'] 删除数据库中之前添加的键值对,相当于删除浏览器识别session的唯一标识
-
装饰器
from django.http import HttpResponseRedirect from django.urls import reverse
from user.models import MyUser
def is_login(func):
<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="" cid="n352" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit;">def check(request, *args, **kwargs):
登录的校验
if 'user_id' in request.session:
user = MyUser.objects.get(pk=request.session['user_id'])
request.user = user
return func(request, *args, **kwargs)
else:
return HttpResponseRedirect(reverse('user:my_login'))
return check</pre>
中间件MIDDLEWARE
process_request(self, request):请求进来时直接进行拦截(应用场景:登录校验)
process_view(self, request, view_func, view_args, view_kwargs):调用view方法之前进行拦截调用
process_exception(self, request, exception):不主动调用,只有出现异常时才执行
process_response(self, response):最后响应浏览器时才调用
process_template_response():没有应用场景
执行顺序
中间件按照排列顺序,从上往下依次执行process_request(), 如果返回None表示继续访问中间件或者方法, 如果return HttpResponse() 表示直接响应内容给浏览器
process_request()执行完毕后,从上往下执行process_view()
前面的方法没有返回响应时,从下往上执行process_response()
文件上传
安装:pip install pillow
模型中定义字段:
icon = models.ImageField(upload_to='upload')
设置media文件夹路径:
MEDIA_URL = 'media' MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
展示图片需要在工程目录的urls.py文件中指定静态文件路由:
static(MEDIA_URL, document_root=MEDIA_ROOT)
展示图片:
前端中定义属性<form enctype='multipart/form-data'>
表单验证
定义
class UserForm(forms.Form):
forms.CharField
forms.IntegerField
forms.ImageField
def clean(self):
# 自动调用
return self.cleaned_data
def clean_字段(self):
# 校验指定字段
return self.cleaend_data
forms = UserForm(request.POST, request.FILES)
验证:form.is_valid()
验证错误信息:form.errors
分页
from django.core.paginator import Paginator
paginator = Paginator(所有数据,条数)
查看总页数:paginator.num_pages
获取某一页的数据: page_data = paginator.page(页码)
paginator.page_range:相当于range(1,总页码数)
page_data = paginator.page(页码)
越界会报错
page_data.has_next():是否有下一页
page_data.has_previous:是否有上一页
page_data.next_page_number:下一页页码
page_data.previous_page_number:上一页页码
page_data.paginator:获取paginator对象
权限
RBAC
用户表--权限表--角色表:
都是多对多关联关系
用户和权限:user_permissions字段
用户和角色:groups字段
角色和权限:permissions字段
权限列表
1.通过用户查询权限表
2.通过用户查询角色,角色查询权限
权限获取
获取所有权限:包括用户对应角色权限和用户对应权限表,user.get_all_permissions()
获取用户组权限:user.get_group_permissions()
权限校验装饰器
- @permission_required('应用名.权限名')
模板中
解析当前用户的权限,是个集合: {{ perms.user }}:{'应用名.权限名'}
{% if perms.user.add_users %}