1 命令行创建工程
1.1 先cd到要创建工程的目录下:
cd E:\Code Learning\Python\6.django
1.2 虚拟环境下django-admin.exe的位置 + startproject + 项目名称:
"C:\Users\ZQ\.conda\envs\pytorch\Scripts\django-admin.exe" startproject project_02
自动创建下面的包和模块
2 命令行创建app
2.1 cd project_02 到当前工程路径下:
2.2 创建app指令:
python manage.py startapp app01
自动创建下面的包和模块
3 注册app
3.1 找到工程目录下的settings模块注册创建好的app:
app名称.apps.app的类名
4 连接MySQL数据库
4.1 django没有创建database的功能,需要先登录mysql数据库创建:
CREATE DATABASE db02 DEFAULT CHARSET utf8 COLLATE utf8_general_ci;
USE db02;
4.2 继续在工程目录下的setting模块修改数据库配置:
5 配置URL路由并定义视图函数
5.1 找到工程目录下的urls模块配置路由:
url路径名+视图函数名
5.2 找到app目录下的views模块定义操作函数(用户访问url时发送请求,编写对应函数对该请求做出响应):
6 启动Django项目
6.1 命令行启动
python manage.py runserver
出现以下界面
6.2 pycharm配置启动
点击进入浏览器,在地址栏添加要访问的url路径:
服务器地址+资源rul路径:http://127.0.0.1:8000/index/
出现以下代表访问成功:
7创建目录(可选)
为使项目结构更清晰,建议创建如下结构目录:
7.1 middleware模块为中间件模块,用来做登录校验等。
- 定义的中间件类需要继承MiddlewareMixin类,并且需要定义一个请求处理函数process_request和一个响应处理函数process_response。
-
如果 process_request 方法中没有返回值(其实是返回None),继续向后走 若有返回值(HttpResponse/render/redirect),执行该中间件开始及之前的响应处理函数
下面给出一个登录校验中间件:
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse, redirect, render
class AuthMiddleware(MiddlewareMixin):
"""登录校验中间件"""
def process_request(self, request):
# 0.排除不需要登录就能访问的页面
if request.path_info in ["/login/", "/image/code/"]:
return
# 1.读取当前访问用户的session信息,若能读取到代表已经登录
info_dict = request.session.get("info")
if info_dict:
return
# 2.此时未获取到登录信息,代表未登录
return redirect("/login/")
def process_response(self, request, response):
return response
定义的中间件需要在settings模块中的 MIDDLEWARE 中添加:
7.2 migrations模块为执行数据库迁移时自动生成的文件。
7.3 static模块下存储页面相关的资源,如css样式、font字体文件、imgs图片、js脚本、pluguns插件等。
7.4 templates下存储需要展示的html页面。
7.5 utils下存储常用工具包。
bs_modelform包中存储表单的初始化类,一个多继承modelform,另一个多继承form:
from django import forms
class BaseForm:
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# 循环ModelForm中的所有字段,给每个字段的插件设置
for _, field in self.fields.items():
# 字段中有属性,保留原来的属性,没有属性,才增加
if field.widget.attrs:
field.widget.attrs["class"] = "form-control"
else:
field.widget.attrs = {
"class": "form-control",
}
class BootStrapModelForm(BaseForm, forms.ModelForm):
pass
class BootStrapForm(BaseForm, forms.Form):
pass
encrypt包中存储密码加密的md5函数:
import hashlib
from django.conf import settings
def md5(data_str):
salt = settings.SECRET_KEY.encode("utf-8")
obj = hashlib.md5(salt)
obj.update(data_str.encode("utf-8"))
return obj.hexdigest()
form中存储需要提交表单时的的表单类,可以自定义数据库中没有的字段,自定义提交的字段,自定义表单输入框样式,自定义对应的钩子方法(clean_字段名):
class AdminModelForm(BootStrapModelForm):
confirm_pwd = forms.CharField(
label="确认密码", min_length=3, widget=forms.PasswordInput(render_value=True)
) # 不想让输入密码错误后清空:render_value=True
class Meta:
model = Admin
fields = ["name", "password", "confirm_pwd"]
widgets = {
"password": forms.PasswordInput(render_value=True),
# "confirm_pwd": forms.PasswordInput(attrs={"class": "form-control"})
}
def clean_password(self):
pwd = self.cleaned_data.get("password")
return md5(pwd)
def clean_confirm_pwd(self):
# form.cleaned_data:验证通过后的数据以字典形式返回
pwd = self.cleaned_data.get("password") # 此时已经是md5加密完的密码
confirm_pwd = md5(self.cleaned_data.get("confirm_pwd"))
print(pwd, confirm_pwd)
if pwd != confirm_pwd:
raise ValidationError("两次输入的密码不一致,请重新输入")
return confirm_pwd
pagination存储自定义的分页组件
"""
自定义的分页组件
"""
from django.utils.safestring import mark_safe
import copy
class Pagination(object):
def __init__(self, request, queryset, page_size=10, page_param="page", page_show=5):
"""
:param request: 请求的对象
:param queryset: 符合条件的数据(根据此数据进行分页处理)
:param page_size: 每页显示多少条数据
:param page_param: 获取在URL中传递的分页参数, 例如: /pretty/list/?page=21
:param page_show: 页码显示前几页后几页
"""
# 防止搜索出结果进行翻页时,URL参数没有了搜索参数
query_dict = copy.deepcopy(request.GET)
query_dict._mutable = True
self.query_dict = query_dict
self.page_param = page_param
page = int(request.GET.get(page_param, 1))
# 如果不是整数
if type(page) != int:
# 强制让页码为1
page = 1
self.page = page
self.start = (page - 1) * page_size
self.end = page * page_size
# 每页展示的数据行数
self.page_queryset = queryset[self.start:self.end]
total_data_count = queryset.count() # 数据行数
total_page_count, div = divmod(total_data_count, page_size)
if div:
total_page_count += 1
self.total_page_count = total_page_count # 总页码数量
self.page_show = page_show # 当前页前后展示的页码数量
self.request = request
def html(self):
# 如果总页码数量大于 11
if self.total_page_count > self.page_show * 2 + 1:
# 如果当前页面页码位置小于等于5
if self.page <= 5:
start_page = 1
end_page = self.page_show * 2 + 2
# 否则,当前页面页码位置大于5时
else:
# 防止页码超出范围
if self.page >= self.total_page_count - self.page_show:
start_page = self.total_page_count - self.page_show * 2
end_page = self.total_page_count + 1
else:
# 计算出当前页的前5页和后5页
start_page = self.page - self.page_show
end_page = self.page + self.page_show + 1
else:
start_page = 1
end_page = self.total_page_count + 1
######## 创建页码 ########
# 页码
page_str_list = []
# self.query_dict.setlist(self.page_param, [1])
# page_str_list.append('<li><a href="?page={}">{}</a></li>'.format(self.query_dict.urlencode()))
# 跳到首页
self.query_dict.setlist(self.page_param, [1])
self.head_page = '<li><a href="?{}" aria-label="Previous"><span aria-hidden="true">首页</span></a></li>'.format(self.query_dict.urlencode())
page_str_list.append(self.head_page)
# 跳到上10页
# 如果当前页面小于 11, 防止超过最小页数
if self.page < self.page_show * 2 + 1:
self.query_dict.setlist(self.page_param, [1])
prev = '<li><a href="?{}">{}</a></li>'.format(
self.query_dict.urlencode(), "<<")
page_str_list.append(prev)
else:
self.query_dict.setlist(self.page_param, [self.page - 10])
prev = '<li><a href="?{}">{}</a></li>'.format(
self.query_dict.urlencode(), "<<")
page_str_list.append(prev)
for i in range(start_page, end_page):
# 如果是当前页,高亮显示页码颜色
if self.page == i:
self.query_dict.setlist(self.page_param, [i])
ele = '<li class="active"><a href="?{}">{}</a></li>'.format(
self.query_dict.urlencode(), i)
else:
self.query_dict.setlist(self.page_param, [i])
ele = '<li><a href="?{}">{}</a></li>'.format(
self.query_dict.urlencode(), i)
page_str_list.append(ele)
# 跳到下10页
# 如果当前页面页数 大于 最大页面数量减去(page_show*2+1),则直接跳到最后一页,防止超过最大页数
if self.page >= self.total_page_count - self.page_show * 2 + 1:
self.query_dict.setlist(self.page_param, [self.total_page_count])
next = '<li><a href="?{}">{}</a></li>'.format(
self.query_dict.urlencode(), ">>")
page_str_list.append(next)
else:
self.query_dict.setlist(self.page_param, [self.page + 10])
next = '<li><a href="?page={}">{}</a></li>'.format(
self.query_dict.urlencode(), ">>")
page_str_list.append(next)
# 跳到尾页
self.query_dict.setlist(self.page_param, [self.total_page_count])
self.end_page = '<li><a href="?{}" aria-label="Next"><span aria-hidden="true">尾页</span></a></li>'.format(self.query_dict.urlencode())
page_str_list.append(self.end_page)
self.page_string = mark_safe("".join(page_str_list))
valid_code存储自定义验证码组件:
from PIL import Image, ImageDraw, ImageFilter, ImageFont
import random
def check_code(width=100, height=40, char_length=4, font_file='app01/static/font/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))
return str(random.randint(0, 9)) #生成随机数字
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')
7.6 views下存储视图函数,用于定义页面前后端的交互操作。