2019-03-26 Django大纲

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

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 %}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,482评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,377评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,762评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,273评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,289评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,046评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,351评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,988评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,476评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,948评论 2 324
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,064评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,712评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,261评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,264评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,486评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,511评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,802评论 2 345

推荐阅读更多精彩内容