赞
踩
启动项目命令
python manage.py runserver
分页功能封装到类中去
封装的类的代码
- """
- 自定义的分页组件,以后如果想要使用这个分页组件,你需要做:
- def pretty_list(request):
- # 靓号列表
- data_dict = {}
- search_data = request.GET.get('q', "")
- if search_data:
- data_dict["mobile__contains"] = search_data
- from app01.utils.pagination import Pagination
- # 根据自己的情况去筛选自己的数据
- queryset = models.PrettyNum.objects.filter(**data_dict).order_by("-level")
- # 实例化分页对象1
- page_object = Pagination(request, queryset)
- context = {
- "queryset": page_object.page_queryset,
- "search_data": search_data, # 分完页的数据
- "page_string": page_object.html() # 页码
- }
- return render(request, 'pretty_list.html', context)
- 在html页面中
- {% for obj in queryset %}
- {{ obj.xx }}
- {% endfor %}
- <ul class="pagination">
- {{ page_string }}
- </ul>
- """
- from django.utils.safestring import mark_safe
- class Pagination(object):
-
- def __init__(self, request, queryset, page_size=10, page_param="page", plus=5):
-
- from django.http.request import QueryDict
- import copy
- query_dict = copy.deepcopy(request.GET)
- query_dict._mutable = True
- self.query_dict = query_dict
-
- self.page_param = page_param
- page = request.GET.get(page_param, "1")
- if page.isdecimal():
- page = int(page)
- else:
- page = 1
- self.page = page
- self.page_size = page_size
-
- self.start = (page - 1) * page_size
- self.end = page * page_size
-
- self.page_queryset = queryset[self.start:self.end]
-
- total_count = queryset.count()
-
- # 总页码
- total_page_count, div = divmod(total_count, page_size)
- if div:
- total_page_count += 1
- self.total_page_count = total_page_count
- self.plus = plus
-
- def html(self):
- if self.total_page_count <= 2 * self.plus + 1:
- # 数据库中的数据比较少,都没有达到11页
- start_page = 1
- end_page = self.total_page_count + 1
- else:
- # 当前页<5时
- if self.page <= self.plus:
- start_page = 1
- end_page = 2 * self.plus + 1
- else:
- if (self.page + self.plus) > self.total_page_count:
- start_page = self.total_page_count - 2 * self.plus
- end_page = self.total_page_count
- else:
- # 数据库中的数据比较多>11页
- start_page = self.page - self.plus
- end_page = self.page + self.plus
-
- # 页码
- page_str_list = []
- self.query_dict.setlist(self.page_param, [1])
- print(self.query_dict.urlencode())
-
- # 上一页
- if self.page > 1:
- self.query_dict.setlist(self.page_param, [self.page - 1])
- prev = '<li><a href="?{}">上一页</a></li>'.format(self.query_dict.urlencode())
- else:
- self.query_dict.setlist(self.page_param, [1])
- prev = '<li><a href="?{}">上一页</a></li>'.format(self.query_dict.urlencode())
- page_str_list.append(prev)
-
- for i in range(start_page, end_page):
- self.query_dict.setlist(self.page_param, [i])
- if i == self.page:
- ele = '<li class="active"><a href="?{}">{}</a></li>'.format(self.query_dict.urlencode(), i)
- else:
- ele = '<li><a href="?{}">{}</a></li>'.format(self.query_dict.urlencode(), i)
- page_str_list.append(ele)
-
- page_str_list.append('<li><a href="?{}">首页</a></li>'.format(self.query_dict.urlencode()))
-
- # 下一页
- if self.page < self.total_page_count:
- self.query_dict.setlist(self.page_param, [self.page + 1])
- prev = '<li><a href="?{}">下一页</a></li>'.format(self.query_dict.urlencode())
- else:
- self.query_dict.setlist(self.page_param, [self.total_page_count])
- prev = '<li><a href="?{}">下一页</a></li>'.format(self.query_dict.urlencode())
- page_str_list.append(prev)
-
- self.query_dict.setlist(self.page_param, [self.total_page_count])
- page_str_list.append('<li><a href="?{}">尾页</a></li>'.format(self.query_dict.urlencode()))
-
- search_string = """
- <li>
- <form style="float: left;margin-left: -1px" method="get">
- <input type="text" name="page"
- style="position: relative;float: left;display: inline-block;width: 80px;border-radius: 0;"
- class="form-control" placeholder="页码">
- <button style="border-radius: 0" class="btn btn-default" type="submit">跳转</button>
- </form>
- </li>
- """
-
- page_str_list.append(search_string)
-
- page_string = mark_safe("".join(page_str_list))
- return page_string

小bug,搜索+分页情况下
分页时候保留原来的搜索条件
http://127.0.0.1:8000/pretty/list/?q=888&page=1
在用户列表页面使用分页功能
ModelForm引入时间样式(自动生成了id为id_create_time)
- {% extends 'layout.html' %}
-
- {% block css %}
- <link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/bootstrap-datepicker/1.9.0/css/bootstrap-datepicker.min.css">
- {% endblock %}
-
- {% block content %}
- <div class="container">
- <div class="panel panel-default">
- <div class="panel-heading">
- <h3 class="panel-title">新建用户</h3>
- </div>
- <div class="panel-body">
- <form method="post" 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>
- {% endblock %}
-
- {% block js %}
- <script src="https://cdn.bootcdn.net/ajax/libs/bootstrap-datepicker/1.9.0/js/bootstrap-datepicker.js"></script>
- <script src="https://cdn.bootcdn.net/ajax/libs/bootstrap-datepicker/1.9.0/locales/bootstrap-datepicker.zh-CN.min.js"></script>
- <script>
- $(function(){
- $('#id_create_time').datepicker({
- format: 'yyyy-mm-dd',
- startDate: '0',
- language: "zh-CN",
- autoclose: true
- });
- })
- </script>
- {% endblock %}

引入时间样式(自定义组件id为dt)
- {% extends 'layout.html' %}
- {% load static %}
-
- {% block css %}
- <link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/bootstrap-datepicker/1.9.0/css/bootstrap-datepicker.min.css">
- {% endblock %}
-
- {% block content %}
- <div class="container">
- <div class="panel panel-default">
- <div class="panel-heading">
- <h3 class="panel-title">新建用户</h3>
- </div>
- <div class="panel-body">
- <form method="post">
- {% csrf_token %}
- <div class="form-group">
- <label>姓名</label>
- <input type="text" class="form-control" placeholder="姓名" name="user">
- </div>
- <div class="form-group">
- <label>密码</label>
- <input type="text" class="form-control" placeholder="密码" name="pwd">
- </div>
- <div class="form-group">
- <label>年龄</label>
- <input type="text" class="form-control" placeholder="年龄" name="age">
- </div>
- <div class="form-group">
- <label>余额</label>
- <input type="text" class="form-control" placeholder="余额" name="ac">
- </div>
- <div class="form-group">
- <label>入职时间</label>
- <input id="dt" type="text" class="form-control" placeholder="入职时间" name="ctime">
- </div>
- <div class="form-group">
- <label>性别</label>
- <select class="form-control" name="gd">
- {% for item in gender_choices %}
- <option value="{{ item.0 }}">{{ item.1 }}</option>
- {% endfor %}
- </select>
- </div>
- <div class="form-group">
- <label>部门</label>
- <select class="form-control" name="dp">
- {% for item in depart_list %}
- <option value="{{ item.id }}">{{ item.title }}</option>
- {% endfor %}
- </select>
- </div>
-
- <button type="submit" class="btn btn-primary">提 交</button>
- </form>
- </div>
- </div>
- </div>
- {% endblock %}
-
- {% block js %}
- <script src="https://cdn.bootcdn.net/ajax/libs/bootstrap-datepicker/1.9.0/js/bootstrap-datepicker.js"></script>
- <script src="https://cdn.bootcdn.net/ajax/libs/bootstrap-datepicker/1.9.0/locales/bootstrap-datepicker.zh-CN.min.js"></script>
- <script>
- $(function(){
- $('#dt').datepicker({
- format: 'yyyy-mm-dd',
- startDate: '0',
- language: "zh-CN",
- autoclose: true
- });
- })
- </script>
- {% endblock %}

在html中增加属性的方法1
在html中增加属性的方法2
在html中增加属性的方法3
UserEditModelForm类继承了BootStrapModelForm类的方法,BootStrapModelForm继承了forms.ModelForm的方法所以使用继承能够更好封装代码功能
封装每部分的功能,拆分到每个模块中去
运行创建数据库代码的命令语句
python manage.py makemigrations
python manage.py migrate
两种方式实现密码输入框
实现密码不一致不会被清空
密码加密
实现重置密码功能
管理员添加,编辑,删除和重置密码功能实现
admin.py代码
- from django.core.exceptions import ValidationError
- from django.shortcuts import render, redirect
- from app01 import models
- from app01.utils.pagination import Pagination
-
-
- def admin_list(request):
- """ 管理员列表 """
-
- data_dict = {}
- search_data = request.GET.get('q', "")
- if search_data:
- data_dict["username__contains"] = search_data
-
- queryset = models.Admin.objects.filter(**data_dict)
-
- page_object = Pagination(request, queryset)
- context = {
- "queryset": page_object.page_queryset,
- "page_string": page_object.html(),
- "search_data": search_data
- }
- return render(request, 'admin_list.html', context)
-
-
- from django import forms
- from app01.utils.bootstrap import BootStrapModelForm
- from app01.utils.encrypt import md5
-
-
- class AdminModelForm(BootStrapModelForm):
- confirm_password = forms.CharField(
- label="确认密码",
- widget=forms.PasswordInput(render_value=True)
- )
-
- class Meta:
- model = models.Admin
- fields = ["username", "password", "confirm_password"]
- widgets = {
- "password": forms.PasswordInput(render_value=True)
-
- }
-
- def clean_password(self):
- pwd = self.cleaned_data.get("password")
- return md5(pwd)
-
- def clean_confirm_password(self):
- pwd = self.cleaned_data.get("password")
- confirm = md5(self.cleaned_data.get("confirm_password"))
- if confirm != pwd:
- raise ValidationError("密码不一致")
- return confirm
-
-
- class AdminEditModelForm(BootStrapModelForm):
- class Meta:
- model = models.Admin
- fields = ['username']
-
-
- class AdminResetModelForm(BootStrapModelForm):
- confirm_password = forms.CharField(
- label="确认密码",
- widget=forms.PasswordInput(render_value=True)
- )
-
- class Meta:
- model = models.Admin
- fields = ['password', 'confirm_password']
- widgets = {
- "password": forms.PasswordInput(render_value=True)
- }
-
- def clean_password(self):
- pwd = self.cleaned_data.get("password")
- md5_pwd = md5(pwd)
-
- exists = models.Admin.objects.filter(id=self.instance.pk, password=md5_pwd).exists()
- if exists:
- raise ValidationError("密码不能与之前的密码相同")
-
- return md5_pwd
-
- def clean_confirm_password(self):
- pwd = self.cleaned_data.get("password")
- confirm = md5(self.cleaned_data.get("confirm_password"))
- if confirm != pwd:
- raise ValidationError("密码不一致")
- return confirm
-
-
- def admin_add(request):
- """ 添加管理员 """
- title = "新建管理员"
-
- if request.method == "GET":
- form = AdminModelForm()
- return render(request, 'change.html', {"form": form, "title": title})
-
- form = AdminModelForm(data=request.POST)
- if form.is_valid():
- form.save()
- return redirect('/admin/list/')
-
- return render(request, 'change.html', {'form': form, "title": title})
-
-
- def admin_edit(request, nid):
- """ 编辑管理员 """
-
- row_object = models.Admin.objects.filter(id=nid).first()
- if not row_object:
- # return render(request, 'error.html', {"msg": "数据不存在"})
- return redirect('/admin/list/')
-
- title = "编辑管理员"
-
- if request.method == "GET":
- form = AdminEditModelForm(instance=row_object)
- return render(request, 'change.html', {"form": form, "title": title})
-
- form = AdminEditModelForm(data=request.POST, instance=row_object)
- if form.is_valid():
- form.save()
- return redirect('/admin/list/')
-
- return render(request, 'change.html', {"form": form, "title": title})
-
-
- def admin_delete(request, nid):
- """ 删除管理员 """
- models.Admin.objects.filter(id=nid).delete()
- return redirect('/admin/list/')
-
-
- def admin_reset(request, nid):
- """ 重置密码 """
- row_object = models.Admin.objects.filter(id=nid).first()
- if not row_object:
- return redirect('/admin/list/')
-
- title = "重置密码 - {}".format(row_object.username)
-
- if request.method == "GET":
- form = AdminResetModelForm()
- return render(request, 'change.html', {"form": form, "title": title})
-
- form = AdminResetModelForm(data=request.POST, instance=row_object)
- if form.is_valid():
- form.save()
- return redirect('/admin/list/')
- return render(request, 'change.html', {"form": form, "title": title})

admin_list.html代码
- {% extends 'layout.html' %}
-
- {% block content %}
- <div class="container">
- <div style="margin-bottom: 10px" class="clearfix">
- <a class="btn btn-success" href="/admin/add/" target="_blank">
- <span class="glyphicon glyphicon-plus-sign" aria-hidden="true"></span>
- 新建管理员
- </a>
-
- <div style="float: right;width: 300px;">
- <form method="get">
- <div class="input-group">
- <input type="text" name="q" class="form-control" placeholder="关键字"
- value="{{ search_data }}">
- <span class="input-group-btn">
- <button class="btn btn-default" type="submit">
- <span class="glyphicon glyphicon-search" aria-hidden="true"></span>
- </button>
- </span>
- </div>
- </form>
- </div>
- </div>
-
- <div class="panel panel-default">
- <!-- Default panel contents -->
- <div class="panel-heading">
- <span class="glyphicon glyphicon-th-list" aria-hidden="true"></span>
- 管理员列表
- </div>
-
- <!-- Table -->
- <table class="table table-bordered">
- <thead>
- <tr>
- <th>ID</th>
- <th>用户名</th>
- <th>密码</th>
- <th>重置密码</th>
- <th>操作</th>
- </tr>
- </thead>
- <tbody>
- {% for obj in queryset %}
- <tr>
- <th>{{ obj.id }}</th>
- <td>{{ obj.username }}</td>
- <td>******</td>
- <td>
- <a href="/admin/{{ obj.id }}/reset/">重置密码</a>
- </td>
- <td>
- <a class="btn btn-primary btn-xs" href="/admin/{{ obj.id }}/edit/">编辑</a>
- <a class="btn btn-danger btn-xs" href="/admin/{{ obj.id }}/delete/">删除</a>
- </td>
- </tr>
- {% endfor %}
- </tbody>
- </table>
- </div>
- <div class="clearfix">
- <ul class="pagination" style="float:left;">
- {{ page_string }}
- </ul>
- </div>
- </div>
- {% endblock %}

change.html模板
- {% extends 'layout.html' %}
-
- {% block content %}
- <div class="container">
- <div class="panel panel-default">
- <div class="panel-heading">
- <h3 class="panel-title">{{ title }}</h3>
- </div>
- <div class="panel-body">
- <form method="post" 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>
- {% endblock %}

表示字段不能为空
提示用户名或密码输入错误
django自动帮我们把session功能定义好了,使用只需要这样一个语句
登录成功后:
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/')
编写中间件
- from django.utils.deprecation import MiddlewareMixin
- from django.shortcuts import HttpResponse, redirect
-
-
- class AuthMiddleware(MiddlewareMixin):
-
- def process_request(self, request):
- # 0.排除那些不需要登录就能访问的页面
- # request.path_info == "/login/"
- if request.path_info == "/login/":
- return
-
- # 1.读取当前访问的用户的session信息,如果能读到,说明已登录过,就可以继续向后走
- info_dict = request.session.get("info")
- 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',
- ]
从session中取到用户名
{{ request.session.info.name }}
设置图像验证码
- import random
- from PIL import Image, ImageDraw, ImageFont, ImageFilter
-
-
- def check_code(width=120, height=40, char_length=5, font_file='ZixunHappyBold.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__':
- # 1. 直接打开
- # img,code = check_code()
- # img.show()
-
- # 2. 写入文件
- # img,code = check_code()
- # with open('code.png','wb') as f:
- # img.save(f,format='png')
-
- # 3. 写入内存(Python3)
- # from io import BytesIO
- # stream = BytesIO()
- # img.save(stream, 'png')
- # stream.getvalue()
-
- # 4. 写入内存(Python2)
- # import StringIO
- # stream = StringIO.StringIO()
- # img.save(stream, 'png')
- # stream.getvalue()
-
- pass

设置七天免登录功能
图片验证码account.py
- from django import forms
- from django.shortcuts import render, redirect, HttpResponse
- from app01 import models
- from app01.utils.bootstrap import BootStrapForm
- from app01.utils.encrypt import md5
- from app01.utils.code import check_code
-
-
- class LoginForm(BootStrapForm):
- username = forms.CharField(
- label="用户名",
- widget=forms.TextInput,
- required=True
- )
- password = forms.CharField(
- label="密码",
- widget=forms.PasswordInput(render_value=True),
- required=True
- )
- code = forms.CharField(
- label="验证码",
- widget=forms.TextInput,
- required=True
- )
-
- def clean_password(self):
- pwd = self.cleaned_data.get("password")
- return md5(pwd)
-
-
- def login(request):
- """ 登录 """
- if request.method == "GET":
- form = LoginForm()
- return render(request, 'login.html', {'form': form})
-
- form = LoginForm(data=request.POST)
- if form.is_valid():
- # 验证码的校验
- user_input_code = form.cleaned_data.pop('code')
- code = request.session.get('image_code', "")
- if code.upper() != user_input_code.upper():
- form.add_error("code", "验证码错误")
- return render(request, 'login.html', {'form': form})
-
- # 验证成功,获取到的用户名和密码1
-
- # 去数据库校验用户名和密码是否正确,获取用户对象
- admin_object = models.Admin.objects.filter(**form.cleaned_data).first()
- if not admin_object:
- form.add_error("password", "用户名或密码错误!")
- return render(request, 'login.html', {'form': form})
-
- # 用户名和密码正确
- # 网站生成随机字符串;写到用户浏览器的cookie中,在写入到session中;
- request.session["info"] = {'id': admin_object.id, 'name': admin_object.username}
- request.session.set_expiry(60 * 60 * 24 * 7)
-
- return redirect("/admin/list/")
-
- return render(request, 'login.html', {'form': form})
-
-
- from io import BytesIO
-
-
- def image_code(request):
- """ 生成图片验证码 """
-
- # 调用pillow函数,生成图片
- img, code_string = check_code()
-
- # 写入到自己的session中(以便于后续获取验证码再进行校验)
- request.session['image_code'] = code_string
- # 给session设置60s超时
- request.session.set_expiry(60)
-
- stream = BytesIO()
- img.save(stream, 'png')
-
- return HttpResponse(stream.getvalue())
-
-
- def logout(request):
- """ 注销 """
-
- request.session.clear()
-
- return redirect('/login/')

login.html
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>Title</title>
- <link rel="stylesheet" href="/static/plugins/bootstrap-3.3.5/css/bootstrap.css">
- <style>
- .account {
- width: 400px;
- border: 1px solid #dddddd;
- border-radius: 5px;
- box-shadow: 5px 5px 20px #aaa;
-
- margin-left: auto;
- margin-right: auto;
- margin-top: 100px;
- padding: 20px 40px;
- }
-
- .account h2 {
- margin-top: 10px;
- text-align: center;
- }
- </style>
- </head>
- <body>
- <div class="account">
- <h2>用户登录</h2>
- <form method="post" novalidate>
- {% csrf_token %}
- <div class="form-group">
- <label>用户名</label>
- {{ form.username }}
- <span style="color: red;">{{ form.username.errors.0 }}</span>
- </div>
- <div class="form-group">
- <label>密码</label>
- {{ form.password }}
- <span style="color: red;">{{ form.password.errors.0 }}</span>
- </div>
- <div class="form-group">
- <label for="id_code">图片验证码</label>
- <div class="row">
- <div class="col-xs-7">
- {{ form.code }}
- <span style="color: red;">{{ form.code.errors.0 }}</span>
- </div>
- <div class="col-xs-5">
- <img id="image_code" src="/image/code/" style="width: 125px;">
- </div>
- </div>
- </div>
-
- <input type="submit" value="登 录" class="btn btn-primary">
- </form>
- </div>
- </body>
- </html>

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。