Django总结
Django
命令行使用
创建django项目
django-admin startproject mysite
启动django项目
python manage.py runserver
创建应用app
python manage.py startapp app01
注意:
1.新创建的app需要你去settings配置文件中注册
2.pycharm只会帮你注册第一个你在创建项目的时候写的应用
3.使用命令行创建django项目 不会自动帮你创建templates文件夹 只能自己创建
4.settings文件中 需要你手动在TEMPLATES写配置os.path.join(BASE_DIR, 'templates')
HTTP(超文本传输协议)
请求格式
请求首行(请求方式,协议版本。。。)
请求头(一大堆k:v键值对)
\r\n
请求体(真正的数据 发post请求的时候才有 如果是get请求不会有)
响应状态码
用特定的数字表示一些意思
1XX:服务端已经成功接收到了你的数据 正在处理 你可以继续提交其他数据
2XX:服务端成功响应(200请求成功)
3XX:重定向
4XX:请求错误(404 请求资源不存在 403 拒绝访问)
5XX:服务器内部错误(500 )
请求方式
get请求
朝别人要数据
post请求
向别人提交数据(eg:用户登录)
wsgire模块( web服务网关接口)
1 socket代码帮你封装好了
2 http数据自动帮你处理好了
1.请求来的时候 帮你拆分http数据格式
2.响应走的时候 有帮你封装成了符合http数据格式的数据
动静态网页
1.将后端获取到的时间传递给前端页面
利用字符串的替换 实现数据传递
2.将字典传递给前端页面 并且可以很方便的操作
借助于jinja2模块实现模板的渲染
from jinja2 import Template
temp = Template(data)
res = temp.render(user={'name':'jason'})
模板语法
什么是模板:只要是在html里面有模板语法就不是html文件了,这样的文件就叫做模板。
**模板的渲染:后端获取的数据 传递给html页面 **
在 Django 模板中遍历复杂数据结构的关键是句点字符 .(也就是点)
注意:句点符也可以用来引用对象的方法(无参数方法)。
模板之语法符号:{{}} 变量相关,{%%} 逻辑相关
模板之过滤器:语法 {{obj|filter__name:param}}
小白必会三板斧+json格式数据
from django.shortcuts import render,HttpResponse,redirect
HttpResponse # 返回字符串的
render # 返回一个html页面 还可以给模板传递
redirect # 重定向
JsonResponse # 返回json格式数据的
前后端分离 就是基于json格式传输数据
后端就专门写接口 前端调用你这个接口 就能够拿到一个json格式的字符串
然后前端利用序列化反序列转换成前端对应的数据类型
前端 后端
JSON.stringify 序列化 >>> json.dumps
JSON.parse 反序列 >>> json.loads
静态文件
网站所用到的
自己写好js
自己写好css
第三方的框架 bootstrap fontwesome sweetalert
静态文件配置
通常情况下 网站所用到的静态文件资源 统一都放在static文件夹下
STATIC_URL = '/static/' # 是访问静态资源的接口前缀
只要你想访问静态资源 你就必须以static开头
手动配置静态文件访问资源
STATICFILES_DIRS = [
os.path.join(BASE_DIR,'static'),
]
接口前缀 动态解析
{% load static %}
form表单
form表单默认的编码格式是urlencoded
你可以通过制定enctype参数来修改form表单提交数据的编码格式
form表单传输文件的时候 编码格式就必须有默认的改为formdata
django后端针对只要是符合urlencoded格式的数据都会自动解析放到request.POST,针对文件数据 会解析并放到request.FILES
action参数可以写的形式
1.不写 默认朝当前地址提交
2.只写后缀/index/
3.写全路径
form表单默认朝后端提交的方式 默认是get请求
get请求携带参数的方式 是在url后面?
url?username=admin&password=123
缺点
1.不安全
2.get请求携带的参数有大小限制(最大不能超过4KB左右)
form表单上传文件
注意事项(上传文件)
1.提交方式必须是post
2.enctype参数必须有默认的urlencoded变成formdata
form校验组件
校验数据通常是前后端都有校验,但是前端校验可有可无 哪怕再牛逼,后端也必须要有校验 反正一句话 前端可有不校验 后端必须校验
1.搭建前端页面 >>> 渲染页面
2.获取前端用户提交的数据校验 >>> 校验数据
3.对数据的校验的结果 展示到前端页面给用户查看 >>> 展示错误信息
form组件能够自动帮你完成上面的三件事
form组件的使用
from django import forms
class MyRegForm(forms.Form):
username = forms.CharField(min_length=3,max_length=8)
password = forms.CharField(min_length=3,max_length=8)
email = forms.EmailField()
如何校验数据
from app01 import views
# 1.给自定义的类传一个字典
obj = views.MyRegForm({'username':'jason','password':'12','email':'123'})
# 2.判断数据是否全部合法
obj.is_valid() # 只有数据全部符合要求才会是True
Out[4]: False
# 3.查看符合校验规则的数据
obj.cleaned_data
Out[5]: {'username': 'bjl'}
# 4.查看不符合条件的数据以及不符合的原因是什么
obj.errors
Out[6]:
{
'password': ['Ensure this value has at least 3 characters (it has 2).'],
'email': ['Enter a valid email address.']
}
# 5.校验数据的时候 默认情况下类里面所有的字段都必须传值
obj = views.MyRegForm({'username':'bjl','password':'123'})
obj.is_valid()
Out[12]: False
obj.errors
Out[13]: {'email': ['This field is required.']}
# 6.默认情况下可以多传 但是绝对不能少传
obj = views.MyRegForm({'username':'bjl','password':'1233','email':'123@qq.com','xxx':'ooo'})
obj.is_valid()
Out[15]: True
如何渲染页面(有三种方法 只写推荐的这种)
forms组件只会帮你渲染获取用户输入(输入,选择,下拉框...)的标签 提交按钮需要你自己手动写
{% for foo in form_obj %}
<p>{{ foo.label }}{{ foo }}</p>
{% endfor %}
如何展示错误信息
用对象点errors.0
<form action="" method="post" novalidate>
{% for foo in form_obj %}
<p>
{{ foo.label }}:{{ foo }}
<span style="color: red">{{ foo.errors.0 }}</span>
</p>
{% endfor %}
<input type="submit">
</form>
如何取消前端帮我们做的校验 form表单中添加一个参数即可
<form action="" method="post" novalidate>
forms组件钩子函数
针对字段 你还可以做额外的校验 需要通过钩子函数
局部钩子
# 当你需要对某一个字段数据进行额外的一些列校验 你可以考虑使用钩子函数
# 针对单个字段的 使用局部钩子
def clean_username(self):
username = self.cleaned_data.get('username')
if '不符合社会主义核心价值观 ' in username:
# 给username字段下面提示错误信息
self.add_error('username','用户名不符合社会主义核心价值观')
return username
全局钩子
# 针对多个字段的校验 使用全局钩子 eg:校验两次密码是否一致
def clean(self):
password = self.cleaned_data.get('password')
confirm_password = self.cleaned_data.get('confirm_password')
if not password == confirm_password:
self.add_error('confirm_password','两次密码不一致')
return self.cleaned_data
request对象及方法
前后端数据交互,获取请求方式
获取post请求携带的数据
request.POST
获取get请求携带的数据
request.GET
request.POST.get('username') 默认只取列表的最后一个元素,如果想将列表完整取出 要用getlist()
Django连接MySQL
第一步配置文件中配置
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql', # 指定数据库 MySQL postgreSQL
'NAME': 'demo', # 到底使用哪个数据库
'USER':'root',
'PASSWORD':'root',
'HOST':'127.0.0.1',
'PORT':3306,
'CHARSET':'utf8'
}
}
第二步
django默认使用的是mysql db连接数据库 但是该模块不支持了
所以你要告诉django不要用mysqldb该用pymysql连接
你可以在项目名下面的__init__.py也可以在应用名下面的__init__.py文件中指定
import pymysql
pymysql.install_as_MySQLdb()
然后可以在test.py文件夹中写下列代码:
import os
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "untitled12.settings")
import django
django.setup()
就可以测试mysql代码了
Django表的创建
django的orm不会自动帮你创建库,库需要你自己手动创建,表会自动帮你创建 你只需要书写符合django orm语法的代码即可
去应用下所在的models.py中书写类
from django.db import models
# Create your models here.
class Userinfo(models.Model):
# 设置id字段为userinfo表的主键 id int primary key auto_increment
id = models.AutoField(primary_key=True) # 在django中 你可以不指定主键字段 django orm会自动给你当前表新建一个名为id的主键字段
# 设置username字段 username varchar(64) CharField必须要指定max_length参数
username = models.CharField(max_length=64) # 在django orm中 没有char字段 但是django 暴露给用户 可以自定义char字段
# 设置password字段 password int
password = models.IntegerField()
******************************数据库迁移(同步)命令***********************************
python manage.py makemigrations # 不会创建表 仅仅是生成一个记录 将你当前的操作记录到一个小本本上(migrations文件夹)
python manage.py migrate # 将你的orm语句真正的迁移到(同步)到数据库中
只要你在models.py中修改了跟数据库相关的代码 你就必须重新开始执行上面两条命令
数据的增删改查
后端如何获取前端用户想要编辑的数据对象
利用get请求url后面可以携带参数的方式 将数据的主键值传递给后端
编辑功能的思路:获取用户想要编辑的数据对象 展示到前端页面 用户修改之后点击修改 再去修改数据库中对应的数据
**查 **
get() :
1.条件存在的情况下 获取的直接是数据对象本身
2.条件不存在的情况下 会直接报错 所以不推荐你使用get方法查询数据
filter():
1.条件存在的情况下 获取到的是一个可以看成列表的数据 列表里面放的才是一个个数据对象本身
2.条件不存在的情况下 并不会报错 返回的是一个可以看成空列表的数据
3.filter括号内可以写多个参数逗号隔开 这多个参数在查询的时候 是and关系
4.filter的结果支持索引取值 但是不支持负数 并且不推荐你使用索引 推荐你使用它封装好的方法 first取第一个数据对象
all() :
res = models.表名.objects.all() 查所有数据
增
1.create():models.表名.objects.create(id="")
1.括号内些关键字参数的形式 创建数据
2.该方法会有一个返回值 返回值就是当前对象本身
2.利用对象点方法的方式
user_obj = models.User(**kwargs)
user_obj.save() # 将当前对象保存到数据库中
改
1.update()
models.Userinfo.objects.filter(**kwargs).update() # 批量更新
2.(不推荐使用 效率极低 会将每一个字段对应的值全部重写一遍)
edit_obj = models.Userinfo.objects.filter(pk=edit_id).first() # pk会自动帮你查找当前表的主键字段
edit_obj.username = username
edit_obj.save()
删
models.Userinfo.objects.filter(pk=delete_id).delete()
说真正的数据是不会被删除的 通常都是给数据设置一个是否删除的标志位
反向解析
根据某一个东西 动态解析出一个结果 该结果可以直接访问对应的url
url(r'^test_add/', views.testadd,name='xxx')
前端解析
{% url 'xxx' %}
后端解析
from django.shortcuts import render,HttpResponse,redirect,reverse
url = reverse('xxx')
模板的继承
事先需要在模板中 通过block划定区域
{% block 区域名字 %}
{% endblock %}
子板中如何使用
{% extends '模板的名字'%}
{% block 区域名字 %}
{% endblock %}
一个页面上 block块越多 页面的扩展性越高
通常情况下 都应该有三片区域
{% block css %}
{% endblock %}
{% block content %}
{% endblock %}
{% block js %}
{% endblock %}
子板中还可以通过
{{ block.super }} 来继续使用母版的内容
模板的导入
当你写了一个特别好看的form表单 你想再多个页面上都使用这个form表单
你就可以将你写的form表单当作模块的形式导入 导入过来之后 就可以直接展示
{% include 'xxx.html' %}
创建多对多表关系的方式
有三种:全自动/纯手动/半自动(只推荐半自动)
半自动:
手动建表 但是你会告诉orm 第三张表是你自己建的
orm只需要给我提供方便的查询方法
第三种虽然可以使用orm查询方法
但是不支持使用
add(),set(),remove(),clear()
半自动 一定要加两个额外的参数:through='Book2Author', through_fields=('book','author')
后面字段的顺序:由第三张表通过哪个字段查询单表 就把哪个字段放前面
单表查询
只要是queryset对象 就可以无限制的点击queryset对象的方法
1.单表查询必知必会13条
1.all() # 查所有
2.filter() # 根据条件过滤 多个条件之间是and关系
3.get() # 直接获取数据对象 查询条件不存在直接报错
4.first() # 取queryset的第一个数据对象
5.last() # 取queryset的最后一个数据对象
6.exclude() # 除此之外
7.values() # queryset 类似于列表套字典
8.values_list() # queryset 类似于列表套元组
9.count() # 统计数据个数
10.distinct() # 一定要是完全一样的数据才能去重
11.order_by() # 排序 默认是升序 加负号就变成降序
12.reverse() # 反转 排序之后才能反转
13.exists() # 判断queryset是否有值 结果是个布尔值
2.神奇的双下划线查询
price__gt 大于
price__lt 小于
price__gte 大于等于
price__lte 小于等于
price__in=[100,200,300] 100或者200或者300
price__range=(200,800) 在200到8000之间(顾头不顾尾)
title__contains 包含 模糊匹配
title__icontains 忽略大小写
publish_date__year 只针对年份
publish_date__month 只针对月份
title__startswith 以什么开始
title__endswith 以什么结束
多表查询
多表查询
前期表准备
图书管理系统
一对多
多对多
一对一
外键字段的增删改查
一对多字段
create(publish_id=1)
create(publish=publish_obj)
update(publish_id=2)
update(publish=publish_obj1)
models.Publish.objects.filter(pk=2).delete()
# orm外键默认是级联更新 级联删除的
多对多字段
# 朝第三张关系表中添加数据
book_obj.authors.add(1)
book_obj.authors.add(1,2,3,4)
book_obj.authors.add(author_obj)
book_obj.authors.add(author_obj,author_obj1,author_obj2)
# 朝第三张表修改数据
book_obj.authors.set((1,))
book_obj.authors.set((1,2,3))
book_obj.authors.set((author_obj,))
book_obj.authors.set((author_obj,author_obj1))
# 朝第三张表删除关系
book_obj.authors.remove(1)
book_obj.authors.remove(1,2,3,4)
book_obj.authors.remove(author_obj)
book_obj.authors.remove(author_obj,author_obj1)
# 朝第三张表清空当前书籍对象所有的记录
book_obj.authors.clear()
跨表查询
正反向的概念:
外键字段在谁那儿 谁就是正向
没有外键字段的 就是反向
口诀:
正向查询按字段
反向查询按表名小写
聚合查询
聚合函数
关键字:aggregate
from django.db.models import Max,Min,Sum,Count,Avg
F与Q查询
from django.db.modles import F,Q
F 能够帮助你获取到表中字段所对应的数据
# 书籍的库存数与卖出数
models.Book.objects.filter(kucun__gt=F('maichu'))
因为filter过滤的条件的都是and连接
modesls.Book.objects.filter(Q(title='python'),Q(price=666))
modesls.Book.objects.filter(Q(title='python')|Q(price=666))
modesls.Book.objects.filter(~Q(title='python')|Q(price=666))
# Q进阶用法
q = Q()
q.connector = 'or'
q.children.append(('title','python'))
q.children.append(('title__icontains','python'))
q.children.append(('price',666))
models.Book.objects.filter(q) # 默认还是and关系
查询优化(面试比较喜欢问的)
only
# res = models.Book.objects.only('title')
# for r in res:
# print(r.title) # 查一次
# print(r.price) # 查多次
only会将括号内的字段对应的值 直接封装到返回给你的对象中 点该字段 不需要再走数据库
一旦你点了不是括号内的字段 就会频繁的去走数据库查询
defer
# res = models.Book.objects.defer('title')
# for r in res:
# print(r.title) # 查多次
# print(r.price) # 查一次
defer会将括号内的字段排除之外将其他字段对应的值 直接封装到返回给你的对象中 点该其他字段 不需要再走数据库
一旦你点了括号内的字段 就会频繁的去走数据库查询
select_related 和 prefetch_related
# res = models.Book.objects.select_related('publish')
# res1 = models.Author.objects.select_related('author_detail')
# # res = models.Book.objects.all()
# for r in res1:
# print(r.author_detail)
# print(r.author_detail.phone)
# print(r.author_detail.addr)
"""
select_related 会自动帮你做连表操作 然后将连表之后的数据全部查询出来封装给对象
select_related括号内只能放外键字段
并且多对多字段不能放
如果括号内外键字段所关联的表中还有外键字段 还可以继续连表
select_related(外键字段__外键字段__外键字段...)
"""
# prefetch_related
res = models.Book.objects.prefetch_related('publish')
# print(res)
for r in res:
print(r.publish.name)
"""
prefetch_related 看似连表操作 其实是类似于子查询
prefetch_related括号内只能放外键字段
并且多对多字段不能放
如果括号内外键字段所关联的表中还有外键字段 还可以继续连表
select_related(外键字段__外键字段__外键字段...)
"""
"""
第一个 内部自动连表 消耗的资源就在连表上 但是走数据库的次数较少
第二个 内部不做连表 消耗的资源就在查询次数上 但是给用户的感觉跟连表操作一样
"""
批量插入数据
关键词:bulk_create
book_list = []
for i in range(100000):
book_list.append(models.Book(title='第%s本书'%i))
models.Book.objects.bulk_create(book_list) # 批量插入数据,时间很短
自定义分页器
自定义分页器的使用 新建一个py文件将代码直接拷贝过去
后端
from app01.utils.mypage import Pagination
使用封装好的分页器代码
def login(request):
book_queryset = models.Book.objects.all()
current_page = request.GET.get('page',1)
all_count = book_queryset.count()
1.实例化产生对象
page_obj = Pagination(current_page=current_page,all_count=all_count)
2.对真实数据进行切片操作
page_queryset = book_queryset[page_obj.start:page_obj.end]
return render(request,'login.html',locals())
前端
{% for book_obj in page_queryset %}
<p>{{ book_obj.title }}</p>
{% endfor %}
{{ page_obj.page_html|safe }}
AJAX
1.异步提交
2.局部刷新
我们所学的ajax是基于jQuery封装好简易版本,所以你在写ajax的时候一定要确保导入可jQuery
基本语法结构
$.ajax({
url:'', # 指定朝哪个后端地址发送请求 不写默认朝当前地址提交
type:'post', # 指定提交方式
data:{'username':'bjl','password':'123'},
success:function(data){ # data指代的就是后端返回的异步提交的结果
# 异步回调机制逻辑处理代码
}
})
编码格式种类
1.urlencoded
2.formdata
3.application/json
发送json格式数据
1.需要手动指定编码格式
contentType:'application/json'
2.一定要确保数据也是符合json格式的
data:JSON.stringify({'username':'jason'})
django后端针对json格式的数据 是不会做任何处理的 会原封不动的放在request.body中
手动去处理获取数据
1.将bytes类型转成json格式字符串
2.利用json模块json.loads反序列化出来
发送文件格式数据
ajax传文件 需要使用到js内置对象 FormData
该对象及可以携带普通的键值对 给django后端的request.POST也可以携带文件给django后端的request.FILES
# 1.现生成一个formdata对象
var MyFormData = new FormData();
# 2.添加普通的键值对
MyFormData.append('username','jason');
MyFormData.append('password','123');
# 3.添加文件
var fileObj = $('#myfile')[0].files[0];
MyFormData.append('myfile',fileObj)
"""
如何获取type=file的input标签存储的用户上传文件
"""
$.ajax({
url:'',
type:'post',
data:MyFormData,
# 需要手动指定两个关键性的参数
contentType:false,
processData:false,
success:function(data){
...
}
})
ajax+sweetalert
sweetalert下载地址: github.com/lipis/bootstrap-sweetalert
把dist复制到文件夹下(别忘了settins里的静态文件配置)
$("#b55").click(function () {
swal({
title: "你确定要删除吗?",
text: "删除可就找不回来了哦!",
type: "warning",
showCancelButton: true, // 是否显示取消按钮
confirmButtonClass: "btn-danger", // 确认按钮的样式类
confirmButtonText: "删除", // 确认按钮文本
cancelButtonText: "取消", // 取消按钮文本
closeOnConfirm: false, // 点击确认按钮不关闭弹框
showLoaderOnConfirm: true // 显示正在删除的动画效果
},
function () {
var deleteId = 2;
$.ajax({
url: "/delete_book/",
type: "post",
data: {"id": deleteId},
success: function (data) {
if (data.code === 0) {
swal("删除成功!", "你可以准备跑路了!", "success");
} else {
swal("删除失败", "你可以再尝试一下!", "error")
}
}
})
});
})
auth模块
其实auth模块本意上也是设置session
用户认证是在你的django中执行了orm的数据库的迁移和生成后就会在你的数据库中自动生成一个用户认证的表 这个表存储的是你auth要提取的信息
首先views中导入下面语句
from django.contrib import auth
auth模块基础
如何创建超级用户 用于登录django admin的后台管理
createsuperuser
校验用户是否存在
user_obj = auth.authenticate(username=username,password=password) # 返回的是数据对象 没有返回None
保存用户登录状态
auth.login(request,user_obj) # 执行完这一句之后 只要是能够拿到request的地方
# 都可以通过request.user获取到当前登录用户对象
判断当前用户是否登录
request.user.is_authenticated()
获取当前用户数据对象
request.user
如何给视图函数加上校验用户是否登录的校验
from django.contrib.auth.decorators import login_required
# @login_required(login_url='/xxx/') # 局部配置
@login_required # 全局配置
def home(request):
return HttpResponse('home页面')
# 当用户没有登录的情况下 跳转的url有两种配置方式
1.在装饰器括号内通过login_url参数局部指定
2.全局配置 用户没有登录的情况下 所有的视图统一跳转到一个url
配置文件中
LOGIN_URL = '/login/'
修改密码
校验原密码是否正确
is_right = request.user.check_password(old_password)
设置新密码
request.user.set_password(new_password)
request.user.save()
用户注册
from django.contrib.auth.models import User
User.objects.create_user(username=username,password=password) # 创建普通用户
User.objects.create_superuser(username=username,password=password,email='123@qq.com') # 创建超级用户 邮箱字段必须填写
扩展auth_user表
第一种(不好用)
利用一对一表关系 扩展字段
第二种(继承)
1.自己写一个默写类 继承原来的auth_user类 然后在settings配置文件中 告诉django使用你新建的类来 替代auth_user表
from django.db import models
from django.contrib.auth.models import AbstractUser
# Create your models here.
class Userinfo(AbstractUser):
"""
强调 你继承了AbstractUser之后 你自定义的表中 字段不能跟原有的冲突
"""
phone = models.BigIntegerField()
avatar = models.FileField()
register_time = models.DateField(auto_now_add=True)
2.一定要在settings配置文件中指定
AUTH_USER_MODEL = 'app01.Userinfo'
# 固定语法: AUTH_USER_MODEL = '应用名.表名'
"""
通过上面的方式 继承的表 还可以继续使用auth模块所有的功能
"""
温馨提示 当你需要些用户相关的功能的时候可以考虑使用auth模块