Django系统开发(中):https://developer.aliyun.com/article/1427947
9.3 新建靓号
- 列表点击跳转:
/pretty/add
- URL
- ModelForm类
from django import forms class PrettyModelForm(forms.ModelForm):
- 函数
- 实例化类的对象。
- 通过render将对象传入到HTML中。
- 模板的循环展示所有的字段。
def pretty_add(request): """ 添加靓号 """ if request.method == "GET": form = PrettyModelForm() return render(request, 'pretty_add.html', {"form": form}) form = PrettyModelForm(data=request.POST) if form.is_valid(): form.save() return redirect('/pretty/list') else: return render(request, "pretty_add.html", {"form": form})
{% extends 'layout.html' %} {% block content %} <div> <div class="container"> <div class="panel panel-default"> <div class="panel-heading"> <h3 class="panel-title" href="/depart/add">添加靓号</h3> </div> <div class="panel-body"> <form method="post" novalidate> <!-- novalidate关闭浏览器校验 --> {% csrf_token %} {% for field in form %} <div class="form-group"> <label>{{ field.label }}</label> {{ field }} <span style="color: red">{{ field.errors.0 }}</span> </div> {% endfor %} <button type="submit" class="btn btn-primary">保 存</button> </form> </div> </div> </div> </div> {% endblock %}
9.4 编辑靓号
- 列表页面:
/pretty/数字/edit
- URL
- 函数
- 根据ID获取当前编辑的对象
- ModelForm配合
- 提交修改
不允许手机号重复
- 添加:【正则表达式】【手机号不能存在】
queryset = models.PrettyNum.objects.filter(mobile="18888888888") obj = models.PrettyNum.objects.filter(mobile="18888888888").first() exists = models.PrettyNum.objects.filter(mobile="18888888888").exis
def clean_mobile(self): txt_mobile = self.cleaned_data["mobile"] exists = models.PrettyNum.objects.exclude(id=self.instance.pk).filter(mobile=txt_mobile).exists() if exists: raise ValidationError("手机号已存在") # 验证通过,用户输入的值返回 return txt_mobile
9.5 搜索手机号
# 索引方法1: models.PrettyNum.objects.filter(mobile="19999999999",id=8) # 索引方法2:(字典) data_dict = {"mobile":"19999999999","id":8} models.PrettyNum.objects.filter(**data_dict)
# 数字索引 models.PrettyNum.objects.filter(id=12) # 等于12 models.PrettyNum.objects.filter(id__gt=12) # 大于12 models.PrettyNum.objects.filter(id__gte=12) # 大于等于12 models.PrettyNum.objects.filter(id__lt=12) # 小于12 models.PrettyNum.objects.filter(id__lte=12) # 小于等于12 data_dict = {"id__lte":12} models.PrettyNum.objects.filter(**data_dict)
models.PrettyNum.objects.filter(mobile="999") # 等于 models.PrettyNum.objects.filter(mobile__startswith="199") # 筛选出以199开头 models.PrettyNum.objects.filter(mobile__endswith="999") # 筛选出以999结尾 models.PrettyNum.objects.filter(mobile__contains="999") # 筛选出包含999 data_dict = {"mobile__contains":"999"} models.PrettyNum.objects.filter(**data_dict)
9.6 分页
queryset = models.PrettyNum.objects.all() queryset = models.PrettyNum.objects.filter(id=1)[0:10] queryset = models.PrettyNum.objects.all()[0:1]
- 分页的逻辑和处理规则
- 封装分页类
- 从头到尾开发
- 写项目用公共组件
- Bug,搜索+分页的情况下
分页时候,保留原来的搜索条件
10.时间插件
<!-- 引入CSS和JS 给时间框添加id --> {% block css %} <link rel="stylesheet" href="{% static 'plugins/bootstrap-datepicker-master/dist/css/bootstrap-datepicker.min.css' %}"> {% endblock %} {% block js %} <script src="{% static 'plugins/bootstrap-datepicker-master/js/bootstrap-datepicker.js' %}"></script> <script src="{% static 'plugins/bootstrap-datepicker-master/dist/locales/bootstrap-datepicker.zh-CN.min.js' %}"></script> <script> $(function () { $('#id_create_time').datepicker({ format: 'yyyy-mm-dd', startDate: '0', languag: "zh-CN", autoclose: true }); }) </script> {% endblock %}
11.ModelForm和BootScript
- ModelForm可以帮助我们生成HTML标签
# 定义UserModelForm类用于生成Input框 class UserModelForm(forms.ModelForm): name = forms.CharField(min_length=3, label="用户名") class Meta: model = models.UserInfo fields = ["name", "password"] form = UserModelForm()
{{ form.name }} 普通的Input框 无CSS样式 {{ form.password }} 普通的Input框 无CSS样式
- 定义插件
class UserModelForm(forms.ModelForm): class Meta: model = models.UserInfo fields = ["name", "password", "age", "account", "create_time", "gender", "depart"] widgets = { "name": forms.TextInput(attrs={"class": "form-control"}) }
class UserModelForm(forms.ModelForm): name = forms.CharField( min_length=3, label="用户名", widget=forms.TextInput(attrs={"class": "form-control"}) ) class Meta: model = models.UserInfo fields = ["name", "password", "age", "account", "create_time", "gender", "depart"]
{{ form.name }} BootStrap的Input框 {{ form.password }} BootStrap的Input框
- 重新定义init方法,批量设置
class UserModelForm(forms.ModelForm): class Meta: model = models.UserInfo fields = ["name", "password"] def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # 循环找到所有的插件,添加了class="form-control" for name, field in self.fields.items(): field.widget.attrs = { "class": "form-control", "placeholder": field.label }
class UserModelForm(forms.ModelForm): class Meta: model = models.UserInfo fields = ["name", "password"] def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # 循环找到所有的插件,添加了class="form-control" for name, field in self.fields.items(): # 字段中若有属性,保留原来的属性,若没有属性,则增加 if field.widget.attrs: field.widget.attrs["class"] = "form-control" field.widget.attrs["placeholder"] = field.label else: field.widget.attrs = { "class": "form-control", "placeholder": field.label }
- 自定义类
class BootStrapModelForm(forms.ModelForm): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # 循环找到所有的插件,添加了class="form-control" for name, field in self.fields.items(): # 字段中若有属性,保留原来的属性,若没有属性,则增加 if field.widget.attrs: field.widget.attrs["class"] = "form-control" field.widget.attrs["placeholder"] = field.label else: field.widget.attrs = { "class": "form-control", "placeholder": field.label }
# 继承BootStrapModelForm类中的功能 class UserEditModelForm(BootStrapModelForm): class Meta: model = models.UserInfo fields = ["name", "password"]
12.管理员操作
13.用户登录
cookie和session?
cookie用于存放用户认证信息 如k1=sfsagglfskfsdfasdf
session是一个概念 用于存储用户的配置信息
登录成功后:
- cookie,随机字符串
- session,用户信息
在其他需要登录才能访问的页面中,都需要加入:
info = request.session.get("info") if not info: return redirect('/login')
目标:在18个视图函数前面统一加入判断
13.1 中间件
- 定义中间件
from django.utils.deprecation import MiddlewareMixin from django.shortcuts import HttpResponse class M1(MiddlewareMixin): """ 中间件1 """ def process_request(self, request): print("M1.进来了") return HttpResponse("无权访问") def process_response(self, request, response): print("M1.走了") return response
- 注册中间件,在settings中
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', ]
# 如果方法中没有返回值(返回None),继续向后走 # 如果有返回值 HttpResponse、render、redirect,则不在继续向后执行。
13.2 中间件实现登录校验
- 编写中间件
from django.utils.deprecation import MiddlewareMixin from django.shortcuts import HttpResponse, redirect class AuthMiddleware(MiddlewareMixin): """ 中间件1 """ def process_request(self, request): if request.path_info == "/login/": return info_dict = request.session.get("info") if info_dict: return 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.3 注销
13.4 显示当前用户
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='kumo.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)
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); } })
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) 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="点击" onclick="clickMe();"/> </div> {% endblock %} {% block js %} <script type="text/javascript"> $(function () { // 页面框架加载完成之后代码自动执行 bindBtn1Event(); }) function bindBtn1Event() { $("#btn1").click(function () { $.ajax({ url: '/task/ajax/', type: "get", data: { n1: 123, n2: 456 }, success: function (res) { console.log(res); } }) }) } </script> {% endblock %}