Django进阶二
一. Session:https://www.cnblogs.com/liwenzhou/p/8343243.htm
1. 什么要有session?Cookied的缺点: 1. 存储的最大数据量只有4096字节 2. 数据都保存在客户端(浏览器)上,不安全
2. Session的简单流程(需要插入图片) 保存在服务端的键值对 1. 请求来了之后,还是生成随机字符串 2. 以随机字符串为key,在服务端生成一个大字典,真正保存数据是value 3. 把随机字符串以cookie的形式回复给浏览器 4. 下一次请求再来的时候,会携带上一步的随机字符串 5. 从请求中拿到随机字符串, 6. 去后端以 该随机字符串为key找对应的value 7. value里面存的就是真正有用的数据
3. Django中如何使用Session 1. 无论设置Session还是获取Session都是针对request对象来操作 2. 设置Session request.session["key"] = "value" request.session.setdefault('k1', 'v1') # 存在则不设置 3. 获取session request.session.get("key") # 如果没有key则返回None 推荐使用 request.session["key"] # 如果没有key则会报错 4. 删除session 1. 将所有Session失效日期小于当前日期的数据删除 request.session.clear_expired() 2. 删除当前的会话数据并删除会话的Cookie request.session.flush() 3. 删除session del request.session['k1'] 4. 删除当前会话的所有session request.session.delete() 5. 其他常用命令 1. 设置超时时间 request.session.set_expiry(7) * 如果value是个整数,session会在些秒数后失效。 * 如果value是个datatime或timedelta,session就会在这个时间后失效。 * 如果value是0,用户关闭浏览器session就会失效。 * 如果value是None,session会依赖全局session失效策略。 2. 获取会话session的key request.session.session_key 3. 检查会话session的key在数据库中是否存在 request.session.exists("session_key") 6. Django中的Session配置(settings) 1. 数据库Session SESSION_ENGINE = 'django.contrib.sessions.backends.db' # 引擎(默认) 2. 缓存Session SESSION_ENGINE = 'django.contrib.sessions.backends.cache' # 引擎 SESSION_CACHE_ALIAS = 'default' # 使用的缓存别名(默认内存缓存,也可以是memcache),此处别名依赖缓存的设置 3. 文件Session SESSION_ENGINE = 'django.contrib.sessions.backends.file' # 引擎 SESSION_FILE_PATH = None # 缓存文件路径,如果为None,则使用tempfile模块获取一个临时地址tempfile.gettempdir() 4. 缓存+数据库 SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db' # 引擎 5. 加密Cookie Session SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies' # 引擎 其他公用设置项: SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认) SESSION_COOKIE_PATH = "/" # Session的cookie保存的路径(默认) SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名(默认) SESSION_COOKIE_SECURE = False # 是否Https传输cookie(默认) SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http传输(默认) SESSION_COOKIE_AGE = 60 * 60 * 24 * 2 # Session的cookie失效日期(2周)(默认) SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否关闭浏览器使得Session过期(默认) SESSION_SAVE_EVERY_REQUEST = False # 是否每次请求都保存Session,默认修改之后才保存(默认)
二. 分页:https://www.cnblogs.com/liwenzhou/p/8343243.html最下面
1. 如何在单独的一个脚本文件中使用Django的一些变量或方法 #!/usr/bin/env python3 import os if __name__ == '__main__': os.environ.setdefault("DJANGO_SETTINGS_MODULE", "about_session.settings") import django django.setup() from app01 import models # 批量导入500条数据 data = [models.User(username="user{}".format(i), password="123") for i in range(1, 501)] models.User.objects.bulk_create(data) 注释:bulk_create() Django ORM批量创建的一个方法
2. 分页: 每页显示10条 1 0->10 2 10->20 3 20->30 n (n-1)*10->n*10
#!/usr/bin/env python3 """ 分页功能 """ class Paging(object): def __init__(self, current_page, total_count, url_prefix, per_page=10, max_show=11): """ 初始化一个自定义的分页实例 :param current_page: 当前页码 :param total_count: 总的数据量 :param url_prefix: 分页中a标签的url前缀 :param per_page: 每一个显示多少条数据 :param max_show: 页面上最多显示多少个页码 """ self.total_count = total_count self.per_page = per_page self.max_show = max_show self.url_prefix = url_prefix # 最多显示页码数的一半 half_show = max_show // 2 # 因为URL取到的参数是字符串格式,需要转换成int类型 try: current_page = int(current_page) except Exception as e: # 如果输入的页码不是正经页码,默认展示第一页 current_page = 1 # 求总共需要多少页显示 total_page, more = divmod(total_count, per_page) if more: total_page += 1 # 如果输入的当前页码数大于总数据的页码数,默认显示最后一页 if current_page > total_page: current_page = total_page self.current_page = current_page # 计算一下显示页码的起点和终点 show_page_start = current_page - half_show show_page_end = current_page + half_show # 特殊情况特殊处理 # 1. 当前页码 - half_show <= 0 if current_page - half_show <= 0: show_page_start = 1 show_page_end = max_show # 2. 当前页码数 + hale_show >= total_page if current_page + half_show >= total_page: show_page_end = total_page show_page_start = total_page - max_show + 1 # 3. 总共需要的页码数 < max_show if total_page < max_show: show_page_start = 1 show_page_end = total_page self.show_page_start = show_page_start self.show_page_end = show_page_end self.total_page = total_page @property def start(self): """ 数据切片的起点 :return: """ return (self.current_page - 1) * self.per_page @property def end(self): """ 数据切片的终点 :return: """ return self.current_page * self.per_page @property def num(self): """ 分页起始序号 :return: """ return (self.current_page - 1) * self.max_show def page_html(self): """ 分页的html代码 :return: """ tmp = [] page_html_start = '<nav aria-label="Page navigation" class="text-center"><ul class="pagination">' page_html_end = '</ul></nav>' tmp.append(page_html_start) # 添加一个首页 tmp.append('<li><a href="/{}?page=1">首页</a></li>'.format(self.url_prefix)) # 添加一个上一页 # 当当前页是第一页的时候不能再点击上一页 if self.current_page - 1 <= 0: tmp.append( '<li class="disabled"><a href="#" aria-label="Previous"><span aria-hidden="true">«</span></a></li>') else: tmp.append( '<li><a href="/{}?page={}" aria-label="Previous"><span aria-hidden="true">«</span></a></li>'.format( self.url_prefix, self.current_page - 1)) # for循环添加要展示的页码 for i in range(self.show_page_start, self.show_page_end + 1): # 如果for循环的页码等于当前页码,给li标签加一个active的样式 if self.current_page == i: tmp.append('<li class="active"><a href="/{1}?page={0}">{0}</a></li>'.format(i, self.url_prefix)) else: tmp.append('<li><a href="/{1}?page={0}">{0}</a></li>'.format(i, self.url_prefix)) # 添加一个下一页 # 当前 当前页已经是最后一页,应该不让下一页按钮能点击 if self.current_page + 1 > self.total_page: tmp.append( '<li class="disabled"><a href="#" aria-label="Previous"><span aria-hidden="true">»</span></a></li>') else: tmp.append( '<li><a href="/{}?page={}" aria-label="Previous"><span aria-hidden="true">»</span></a></li>'.format( self.url_prefix, self.current_page + 1)) # 添加一个尾页 tmp.append('<li><a href="/{}?page={}">尾页</a></li>'.format(self.url_prefix, self.total_page)) tmp.append(page_html_end) page_html = "".join(tmp) return page_html
from django.shortcuts import render from app01 import models from public.paging import Paging # Create your views here. def user_list(request): """ 显示用户列表 :param request: :return: """ if request.method == "GET": # 查找到所有的用户 books = models.User.objects.all() # 拿到总数据量 total_count = books.count() # 从url拿到page参数 current_page = request.GET.get("page", None) page_obj = Paging(current_page, total_count, url_prefix="user_list", max_show=7) # 对总数据进行切片,拿到页面显示需要的数据 data = books[page_obj.start:page_obj.end] page_html = page_obj.page_html() return render(request, "user_list.html", {"data": data, "num": page_obj.num, "page_html": page_html})
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>用户列表</title> <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.min.css"> </head> <body> <div class="container"> <div class="row"> <div class="col-md-8 col-md-offset-2"> <table class="table table-bordered"> <thead> <tr> <th>#</th> <th>用户名</th> </tr> </thead> <tbody> {% for user in data %} <tr> <td>{{ forloop.counter|add:num }}</td> <td>{{ user.name }}</td> </tr> {% endfor %} </tbody> </table> {{ page_html|safe }} </div> </div> </div> </body> </html>
三. 中间件:https://www.cnblogs.com/liwenzhou/p/8761803.html
1. 什么时候使用中间件?
当需要在全局改变Django框架的输入输出时
2. 中间件不宜添加过多,功能过于复杂
否则会增加请求的响应时间
3. Django如何使用 1. 五个方法(三个常用) 主要记忆:执行时间、执行顺序、参数和返回值 1. process_request(self,request) 1. 执行时间 在执行视图函数之前执行 2. 执行顺序 按照注册的顺序执行 3. 参数和返回值 1. request参数和视图函数中是同一个对象 2. 返回值: 1. 返回None:请求继续往后执行 2. 返回响应对象:请求就结束了,要返回响应了 2. process_response(self, request, response) 1. 执行时间 视图函数执行之后(拿到响应对象之后) 2. 执行顺序 按照注册的倒序执行 3. 参数和返回值 1. 参数:request请求对象 response响应对象 2. 返回值: 只能返回响应对象 1. 返回默认的 2. 自己生成一个响应对象返回 3. process_view(self, request, view_func, view_args, view_kwargs) 1. 执行时间 视图函数之前,在urls.py找到将要执行的视图函数之后 2. 执行顺序 注册的顺序执行 3. 参数和返回值 1. 参数: 1. request: 请求对象 2. view_func:将要执行的视图函数 2. 返回值: 1. 返回None:继续往后执行 2. 返回响应对象,直接跳出,按照process_response方法的顺序执行 有条件触发: 4. process_template_response(self,request,response) 1. 执行时间: 视图函数之后,并且返回的响应对象是要有render方法 2. 执行顺序: 按照注册的倒序执行 3. 返回值: 对传递过来的响应对象,调用其render方法,把返回值向后继续传递 5. process_exception(self, request, exception) 1. 执行时间: 当视图函数中抛出异常的时候才执行 2. 执行顺序: 注册的倒序 3. 参数和返回值 exception:视图函数中抛出的异常 返回响应对象,就跳出按照process_response方法的顺序执行
代码示例: ------------------------------------------------------------------------------ 在项目目录下创建py文件 from django.utils.deprecation import MiddlewareMixin class MD1(MiddlewareMixin): def process_request(self, request): print("MD1里面的 process_request") class MD2(MiddlewareMixin): def process_request(self, request): print("MD2里面的 process_request") pass ------------------------------------------------------------------------------- 在settings.py的MIDDLEWARE配置项中注册上述两个自定义中间件 MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'middlewares.MD1', # 自定义中间件MD1 'middlewares.MD2' # 自定义中间件MD2 ]
四. ORM(多对多) https://www.cnblogs.com/liwenzhou/p/8660826.html
1. ORM多对多字段 class Book(models.Model): """ 图书表 """ name = models.CharField(max_length=24) publisher = models.ForeignKey(to="Publisher") class Author(models.Model): """ 作者表 多对多,自动帮我们在数据库建立第三张关系表 """ name = models.CharField(max_length=24) books = models.ManyToManyField(to="Book", related_name="authors") 参数: - to:表示和哪张表建立多对多的关系 - related_name:表示返乡查询时使用的那个字段名,默认反向查询时使用表名_set的方式
2. 多对多字段的方法 1. 查询 # 多对多 基于对象的查询 # 正向查询 print(models.Author.objects.first().books.all()) # 反向查询 print(models.Book.objects.first().authors.all()) # 多对多 基于QuerySet 的查询 # 正向查询 print(models.Author.objects.all().values("books__name")) # 反向查询 print(models.Book.objects.all().values("authors__name")) 2. 删除 1. 从关联对象集中移除执行的model对象 models.Book.objects.first().authors.remove(3) 2. 从关联对象集中移除一切对象。 models.Book.objects.first().authors.clear() 3. 添加 1. 当form表单提交的数据是列表(多选的select\多选的checkbox)取值? request.POST.getlist("hobby") 2. .set([id1,id2,...]) 参数是一个列表 --> 删除原来的设置新的 models.Author.objects.first().books.set([9]) print(models.Author.objects.first().books.all()) 3. .add(id值) --> 在原来的基础上增加新的纪录 models.Author.objects.first().books.add(9) print(models.Author.objects.first().books.all())
五. ajax:https://www.cnblogs.com/liwenzhou/p/8718861.html
1. stringify与parse方法 JavaScript中关于JSON对象和字符串转换的两个方法: 1. JSON.parse(): 用于将一个 JSON 字符串转换为 JavaScript 对象 JSON.parse('{"name":"Q1mi"}'); JSON.parse('{name:"Q1mi"}') ; // 错误 JSON.parse('[18,undefined]') ; // 错误 2. JSON.stringify(): 用于将 JavaScript 值转换为 JSON 字符串。 JSON.stringify({"name":"Q1mi"})
2. 目前已知浏览器和服务端发请求的方式 1. 浏览器地址栏 输入url直接回车 GET 2. a标签 GET 3. form表单 GET/POST 4. ajax GET/POST
3. ajax的特点: 优点: 1. 偷偷发请求,用户无感知 2. 局部刷新 相对于其他请求方式而言,返回的数据量小 3. 同一个页面可以发送多次请求 异步 缺点: 1. 如果滥用,对服务端的压力比较大
4. ajax的使用: jQuery版: 导入jQuery $.ajax({ url: "往哪里发请求", type: "发送请求的类型", data: { "k1": "v1", "k2": "v2", }, success:function(res){ } })
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>注册页面</title> <link rel="stylesheet" href="/static/plugins/bs/css/bootstrap.min.css"> </head> <body> <div class="container"> <div class="row"> <div class="col-md-4 col-md-offset-2"> <form action="" method="post" class="form-signin"> {% csrf_token %} <h2 class="form-signin-heading">请注册</h2> <div class="username"> <label for="username" class="sr-only">用户名</label> <input type="text" id="username" name="username" class="form-control" placeholder="Username" required autofocus> </div> <label for="password" class="sr-only">密码</label> <input type="password" id="password" name="password" class="form-control" placeholder="Password" required> <button class="btn btn-lg btn-primary btn-block" type="submit">注册</button> </form> </div> </div> </div> <!-- /container --> <script src="/static/plugins/jquery-3.3.1.min.js"></script> <script> $(function () { $("#username").blur(function () { $.ajax({ url: "/check/", type: "post", data: { "username": $("#username").val(), "csrfmiddlewaretoken": $("[name = 'csrfmiddlewaretoken']").val() }, success: function (res) { if (res == 0) { $(".username").addClass("has-error") } else{ $(".username").addClass("has-success").removeClass("has-error") } } }) }) }) </script> </body> </html>
from django.shortcuts import render, HttpResponse from app01 import models # Create your views here. def reg(request): if request.method == "GET": return render(request, "reg.html") def check(request): username = request.POST.get("username") obj = models.User.objects.filter(username=username) if not obj.exists(): return HttpResponse("1") else: return HttpResponse("0")
5. AJAX请求如何设置csrf_token $.ajax({ url: "/cookie_ajax/", type: "POST", data: { "username": "Q1mi", "password": 123456, "csrfmiddlewaretoken": $("[name = 'csrfmiddlewaretoken']").val() // 使用jQuery取出csrfmiddlewaretoken的值,拼接到data中 }, success: function (data) { console.log(data); } })