Django开发(续接上文)
12. 管理员操作
13. 用户登录
http无状态短连接:
什么是cookie和session?
http://127.0.0.1:8000/admin/list/
https://127.0.0.1:8000/admin/list/
13.1 登录
登录成功后:
- cookie,随机字符串
- session,用户信息
在其他需要登录才能访问的页面中,都需要加入:
def index(request):
info = request.session.get("info")
if not info:
return redirect('/login/')
...
目标:在18个视图函数前面统一加入判断。
info = request.session.get("info")
if not info:
return redirect('/login/')
13.2 中间件的体验
-
定义中间件
from django.utils.deprecation import MiddlewareMixin from django.shortcuts import HttpResponse class M1(MiddlewareMixin): """ 中间件1 """ def process_request(self, request): # 如果方法中没有返回值(返回None),继续向后走 # 如果有返回值 HttpResponse、render 、redirect print("M1.process_request") return HttpResponse("无权访问") def process_response(self, request, response): print("M1.process_response") return response class M2(MiddlewareMixin): """ 中间件2 """ def process_request(self, request): print("M2.process_request") def process_response(self, request, response): print("M2.process_response") return response
-
应用中间件 setings.py
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', 'app01.middleware.auth.M1', 'app01.middleware.auth.M2', ]
-
在中间件的process_request方法
# 如果方法中没有返回值(返回None),继续向后走 # 如果有返回值 HttpResponse、render 、redirect,则不再继续向后执行。
13.3 中间件实现登录校验
-
编写中间件
from django.utils.deprecation import MiddlewareMixin from django.shortcuts import HttpResponse, redirect class AuthMiddleware(MiddlewareMixin): def process_request(self, request): # 0.排除那些不需要登录就能访问的页面 # request.path_info 获取当前用户请求的URL /login/ if request.path_info == "/login/": return # 1.读取当前访问的用户的session信息,如果能读到,说明已登陆过,就可以继续向后走。 info_dict = request.session.get("info") print(info_dict) if info_dict: return # 2.没有登录过,重新回到登录页面 return redirect('/login/')
-
应用中间件
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', 'app01.middleware.auth.AuthMiddleware', ]
13.4 注销
def logout(request):
""" 注销 """
request.session.clear()
return redirect('/login/')
13.5 当前用户
14.图片验证码
14.1 生成图片
pip install pillow
import random
from PIL import Image, ImageDraw, ImageFont, ImageFilter
def check_code(width=120, height=30, char_length=5, font_file='Monaco.ttf', font_size=28):
code = []
img = Image.new(mode='RGB', size=(width, height), color=(255, 255, 255))
draw = ImageDraw.Draw(img, mode='RGB')
def rndChar():
"""
生成随机字母
:return:
"""
return chr(random.randint(65, 90))
def rndColor():
"""
生成随机颜色
:return:
"""
return (random.randint(0, 255), random.randint(10, 255), random.randint(64, 255))
# 写文字
font = ImageFont.truetype(font_file, font_size)
for i in range(char_length):
char = rndChar()
code.append(char)
h = random.randint(0, 4)
draw.text([i * width / char_length, h], char, font=font, fill=rndColor())
# 写干扰点
for i in range(40):
draw.point([random.randint(0, width), random.randint(0, height)], fill=rndColor())
# 写干扰圆圈
for i in range(40):
draw.point([random.randint(0, width), random.randint(0, height)], fill=rndColor())
x = random.randint(0, width)
y = random.randint(0, height)
draw.arc((x, y, x + 4, y + 4), 0, 90, fill=rndColor())
# 画干扰线
for i in range(5):
x1 = random.randint(0, width)
y1 = random.randint(0, height)
x2 = random.randint(0, width)
y2 = random.randint(0, height)
draw.line((x1, y1, x2, y2), fill=rndColor())
img = img.filter(ImageFilter.EDGE_ENHANCE_MORE)
return img, ''.join(code)
if __name__ == '__main__':
img, code_str = check_code()
print(code_str)
with open('code.png', 'wb') as f:
img.save(f, format='png')
15. Ajax请求
浏览器向网站发送请求时:URL 和 表单的形式提交。
- GET
- POST
特点:页面刷新。
除此之外,也可以基于Ajax向后台发送请求(偷偷的发送请求)。
-
依赖jQuery
-
编写ajax代码
$.ajax({ url:"发送的地址", type:"get", data:{ n1:123, n2:456 }, success:function(res){ console.log(res); } })
15.1 GET请求
$.ajax({
url: '/task/ajax/',
type: "get",
data: {
n1: 123,
n2: 456
},
success: function (res) {
console.log(res);
}
})
from django.shortcuts import render, HttpResponse
def task_ajax(request):
print(request.GET)
return HttpResponse("成功了")
15.2 POST请求
$.ajax({
url: '/task/ajax/',
type: "get",
data: {
n1: 123,
n2: 456
},
success: function (res) {
console.log(res);
}
})
from django.shortcuts import render, HttpResponse
from django.views.decorators.csrf import csrf_exempt
@csrf_exempt
def task_ajax(request):
print(request.GET)
print(request.POST)
return HttpResponse("成功了")
15.3 关闭绑定事件
{% extends 'layout.html' %}
{% block content %}
<div class="container">
<h1>任务管理</h1>
<h3>示例1</h3>
<input id="btn1" type="button" class="btn btn-primary" value="点击"/>
</div>
{% endblock %}
{% block js %}
<script type="text/javascript">
$(function () {
// 页面框架加载完成之后代码自动执行
bindBtn1Event();
})
function bindBtn1Event() {
$("#btn1").click(function () {
$.ajax({
url: '/task/ajax/',
type: "post",
data: {
n1: 123,
n2: 456
},
success: function (res) {
console.log(res);
}
})
})
}
</script>
{% endblock %}
15.4 ajax请求的返回值
一般都会返回JSON格式。
{% extends 'layout.html' %}
{% block content %}
<div class="container">
<h1>任务管理</h1>
<h3>示例1</h3>
<input id="btn1" type="button" class="btn btn-primary" value="点击"/>
</div>
{% endblock %}
{% block js %}
<script type="text/javascript">
$(function () {
// 页面框架加载完成之后代码自动执行
bindBtn1Event();
})
function bindBtn1Event() {
$("#btn1").click(function () {
$.ajax({
url: '/task/ajax/',
type: "post",
data: {
n1: 123,
n2: 456
},
dataType: "JSON",
success: function (res) {
console.log(res);
console.log(res.status);
console.log(res.data);
}
})
})
}
</script>
{% endblock %}
import json
from django.shortcuts import render, HttpResponse
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
def task_list(request):
""" 任务列表 """
return render(request, "task_list.html")
@csrf_exempt
def task_ajax(request):
print(request.GET)
print(request.POST)
data_dict = {"status": True, 'data': [11, 22, 33, 44]}
return HttpResponse(json.dumps(data_dict))
知识点的回顾:
-
安装Django
pip install django
-
创建Django项目
>>> django-admin startproject mysite
注意:Pycharm可以创建。如果用Pycharm创建,记得settings.py中的DIR templates 删除。
-
创建app & 注册
>>>python manage.py startapp app01 >>>python manage.py startapp app02 >>>python manage.py startapp app03
INSTALLED_APPS = [ ... 'app01.apps.App01Config' ]
注意:否则app下的models.py写类时,无法在数据库中创建表。
-
配置 静态文件路径 & 模板的路径(放在app目录下)。
-
配置数据库相关操作(MySQL)
-
第三方模块(django3版本)
pip install mysqlclient
-
自己先去MySQL创建一个数据库。
-
配置数据库连接settings.py
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'gx_day16', # 数据库名字 'USER': 'root', 'PASSWORD': 'root123', 'HOST': '127.0.0.1', # 那台机器安装了MySQL 'PORT': 3306, } }
-
在app下的models.py中编写
from django.db import models class Admin(models.Model): """ 管理员 """ username = models.CharField(verbose_name="用户名", max_length=32) password = models.CharField(verbose_name="密码", max_length=64) def __str__(self): return self.username class Department(models.Model): """ 部门表 """ title = models.CharField(verbose_name='标题', max_length=32) def __str__(self): return self.title
-
执行两个命令:
>>>python manange.py makemigrations >>>python manange.py migrate
-
-
在 urls.py ,路由 ( URL 和 函数的对应关系)。
-
在views.py,视图函数,编写业务逻辑。
-
templates目录,编写HTML模板(含有模板语法、继承、
{% static 'xx'%}
) -
ModelForm & Form组件,在我们开发增删改查功能。
- 生成HTML标签(生成默认值)
- 请求数据进行校验。
- 保存到数据库(ModelForm)
- 获取错误信息。
-
Cookie和Session,用户登录信息保存起来。
-
中间件,基于中间件实现用户认证 ,基于:
process_request
。 -
ORM操作
models.User.objects.filter(id="xxx") models.User.objects.filter(id="xxx").order_by("-id")
-
分页组件。
1.Ajax请求
2.订单
class Order(models.Model):
""" 订单 """
oid = models.CharField(verbose_name="订单号", max_length=64)
title = models.CharField(verbose_name="名称", max_length=32)
price = models.IntegerField(verbose_name="价格")
status_choices = (
(1, "待支付"),
(2, "已支付"),
)
status = models.SmallIntegerField(verbose_name="状态", choices=status_choices, default=1)
admin = models.ForeignKey(verbose_name="管理员", to="Admin", on_delete=models.CASCADE)
想要去数据库中获取数据时:对象/字典
# 对象,当前行的所有数据。
row_object = models.Order.objects.filter(id=uid).first()
row_object.id
row_object.title
# 字典,{"id":1,"title":"xx"}
row_dict = models.Order.objects.filter(id=uid).values("id","title").first()
# queryset = [obj,obj,obj,]
queryset = models.Order.objects.all()
# queryset = [ {'id':1,'title':"xx"},{'id':2,'title':"xx"}, ]
queryset = models.Order.objects.all().values("id","title")
# queryset = [ (1,"xx"),(2,"xxx"), ]
queryset = models.Order.objects.all().values_list("id","title")
小结
至此,基于Ajax + 对话框的形式实现的页面的增删改查。
- 表单,实现增删改查。
- Ajax,实现增删改查。
3.图表
- highchart,国外。
- echarts,国内。
更多参考文档:https://echarts.apache.org/handbook/zh/get-started