Django银角大王武沛齐配套视频笔记,python全栈开发、pythonWeb
Django
本套博客基于银角大王武沛齐的django全栈开发视频编写:传送门
如有错误或改进欢迎大家评论、私信交流指正
一、初识Django
1、Djang的安装
- 在windos命令窗口
win+r键,输入cmd
pip install django
- 效果:
2、Django项目
①创建Django项目
- 使用Pycham创建
Ⅰ、使用模板
- 主页面点击左上角File->newProject
Ⅱ、配置选项
Ⅲ、成功效果
②项目文件
Ⅰ、默认文件介绍
Demo1
├── manage.py 【项目的管理,启动项目、创建app、数据管理】【不需要修改】【***常常用***】
├── templates 【存放html静态页面,后期手动创建】
├── static 【图片、css、js、plugins(插件)等前端样式资源,后期手动创建】
└── Demo1├── __init__.py├── settings.py 【项目配置文件】 【***常常修改***】├── urls.py 【URL和函数的对应关系】【***常常修改***】├── asgi.py 【接收网络请求】【不要动】└── wsgi.py 【接收网络请求】【不要动】
③创建App文件
- 注意:我们开发比较简洁,用不到多app,一般情况下,项目下创建1个app即可。
Ⅰ、终端创建
- 语法
python manage.py startapp app文件名称
- 在当前项目目录下执行
manage.py
文件创建App
Ⅱ、app文件结构
Demo1
├── app01
│ ├── __init__.py
│ ├── admin.py 【固定,不用动】django默认提供了admin后台管理。
│ ├── apps.py 【固定,不用动】app启动类
│ ├── migrations 【固定,不用动】数据库变更记录
│ │ └── __init__.py
│ ├── models.py 【**重要**】,对数据库操作,里面的oim代替了原生的Pymysql来操作数据库。
│ ├── tests.py 【固定,不用动】单元测试
│ └── views.py 【最常用】,列:下面执行url就会调用该文件夹的函数。
├── manage.py
└── Demo1├── __init__.py├── asgi.py├── settings.py 【项目配置文件】├── urls.py 【URL->函数】└── wsgi.py
3、快速上手
①项目注册app
Ⅰ、在项目文件夹下Settings.py文件中
- app地址格式
'app文件名.apps.类名(apps.py文件中)'
- 类名
- 填写信息
②urls.py编写url和函数信息
③views.py编写视图函数
- 服务器输出层
④启动项目
Ⅰ、命令行启动
- 端口号可以省略默认8000
python manage.py runserver 8080
- 关闭
ctrl+c
Ⅱ、PyCham启动
⑤访问页面
在浏览器访问,前面127.0.0.1.8080 是默认的,而index是要访问的页面和执行函数路径,具体见配置
4、访问静态页面
- 与快速上手步骤无异只是修改了几处位置
①创建html静态页面
在app文件目录下创建一个文件夹templates,里面放置html静态页面
选中templates文件夹,右击new—File—Html,然后取文件名user_list
效果:
②编写视图函数
- app文件夹下views.py文件
④编写url配置文件
- Demo1项目文件夹下urls.py文件
⑤访问页面
启动
访问效果:
⑥总结
- 访问静态页面返回方法要使用:
render()
并且要导包
# 调用函数访问静态页面
def user_list(request):return render(request,"user_list.html")
- 普通的直接使用
HttpResponse()
方法
def index(request):return HttpResponse("欢迎使用Django")
⑥拓展templates
页面是默认到App文件目录templates文件夹中找html文件的,但是可以配置让其到项目目录找
添加方法:
os.path.jion()
5、项目文件管理
①静态页面
Ⅰ、存放路径
- app文件—templates文件夹
- 文件夹名称必须为templates不可以修改
Ⅱ、拓展(修改存放路径)
页面是默认到App文件目录templates文件夹中找html文件的,但是可以配置让其到项目目录找,可以查看
添加方法
os.path.jion()
②静态文件
App目录下,名称必须为static文件
图片、css、js、plugins(插件)等前端样式资源
6、Django模板语法
①引用文件
Django独特资源路径
- 通过项目配置文件Settings.py指定文件查找路径,占位符引用资源
- 作用:
防止以后做项目需要改文件路径,可以直接通过配置文件修改
- 语法:
<img src="{% 配置文件指定的路径 '文件路径' %}">
- 效果:
<img src="{% static 'img/img.pong' %}">
文件所在路径:
配置文件:
②返回数据
Ⅰ、render对象
说明
导包
from django.shortcuts import render
- 使用
def user_list(request):return render(request,"user_list.html")
Ⅱ、HttpResponse对象
说明
导包
from django.shortcuts import HttpResponse
- 使用
def index(request):return HttpResponse("欢迎使用Django") # 结果输出到访问的页面
③占位符开发
- 使用占位符让python代码可以在html文件中使用
{% python代码 %}
- views.py文件
from django.shortcuts import render,HttpResponse"""
视图函数
"""
def index(request):return HttpResponse("欢迎使用Django")# 调用函数访问静态页面
def user_list(request):return render(request,"user_list.html")def tpl(request):name = "胡图图" # strroles = ["大胖子","小学生","萝卜头"] # listuser_info={"name":"胡图图","age":3}return render(request,'tpl.html',{"n1":name,"n2":roles,"n3":user_info}) # 转化
- html文件
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<!--输出tpl函数中变量和列表-->
<div>{{ n1 }}}</div>
<div>{{ n2 }}}</div>
<!--使用索引访问列表-->
<div>{{ n2.0 }}</div>
<div>{{ n2.2 }}</div>
<!--for循环列表-->
<div>{% for aaa in n2 %}<span>aaa</span>{% endfor %}
</div>
<!--显示字典-->
{{ n3 }}
{{ n3.name }}
{% for foo in n3.foo %}<li>{{ foo }}</li>
{% endfor %}
<!--条件判断语句-->
{% if n1 == "大胖子" %}<h1>对</h1>
{% else %}<h1>错</h1>
{% endif %}</body>
</html>
④案例:把python程序的数据输出到页面上
7、请求和响应
①请求
Ⅰ、获取请求方式
获取前端的请求方式
request.method
Ⅱ、获取get请求传递的值
返回值是字典
# 获取在url上传递的值,get请求 url: http://127.0.0.1:8080/UrlDate/?n=1 传递了n=1
request.GET # 返回值: <QueryDict: {'n': ['1']}> 返回的是字典
Ⅲ、获取post请求
request.POST
②响应
- HttpResponse()
- render()
Ⅰ、返回字符串
# [响应]将字符串返回给请求者return HttpResponse("返回内容")
Ⅱ、返回一个页面,并返回模板变量
return render(request, 'url_date.html', {"uuu": "大胖子"})
- html文件
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
{{ uuu }} <!--浏览器效果:大胖子-->
</body>
</html>
Ⅲ、重定向
- 跳转页面
# 重定项,访问次函数方法就会跳转页面return redirect("https://blog.csdn.net/tyx2985491138?type=blog")
8、用户登录案例
- views.py文件
from django.shortcuts import render, HttpResponse, redirect
"""
登录页面
"""
def login_a(request):# 用户第一次访问是以get请求,然后通过前端from表单提交是post请求,从第二次就是post请求if request.method == "GET":return render(request,'login.html')else:username = request.POST.get("user")password = request.POST.get("pwd")if username == 'root' and password == '123456':# return HttpResponse("登录成功")return redirect("https://blog.csdn.net/tyx2985491138?type=blog") # 登录成功重定向跳转页面else:# return HttpResponse("登录失败")return render(request,'login.html',{"loginaaa":"用户名密码错误"}) # 使用模板语言让登录失败可以返回到前端
- urls.py文件
from django.urls import path
from app01 import views # 导入app01中views.py文件(书写函数的文件夹)
urlpatterns = [# 用户登录案例path('login/', views.login_a),
]
- html文件
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>用户登录</title>
</head>
<body><h1>用户登录</h1>
<form method="post" action="/login/">{% csrf_token %} <!--403报错使用--><input type="text" name="user" placeholder="用户名"><input type="password" name="pwd" placeholder="密码"><input type="submit" value="提交"><span style="color: red">{{ loginaaa }}</span> <!--用于登录失败后从后端返回显示语句->
</form></body>
</html>
9、总结
二、操作数据库
- 实现技术使用的是orm操作数据库
1、快速入门
①py原生代码连接数据库
- pymysql连接数据库
import pymysql# 1.连接MySQL
conn = pymysql.connect(host="127.0.0.1", port=3306, user='root', passwd="root123", charset='utf8', db='unicom')
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)# 2.发送指令
cursor.execute("insert into admin(username,password,mobile) values('wupeiqi','qwe123','15155555555')")
conn.commit()# 3.关闭
cursor.close()
conn.close()
②ORM连接数据库
- django的内部框架,用来简化pymsql连接数据库
- 可以帮我们:
- 创建、修改、删除数据库中的表 【无法创建数据库】
- 操作数据库不用写sql语句
Ⅰ、安装第三方软件包
- 安装mysqlclient
pip install mysqlclient
报错解决方法
文件地址:https://wwt.lanzouy.com/ieVdA0es8rad 密码:evzg
mysqlclient安装失败解决方法](http://t.csdn.cn/UetPe)
Ⅱ、创建数据库
Ⅰ、登录mysql
- 打开总结电脑的终端
- 登录到mysql
mysql -u -root -p 或者:mysql -h localhost -u root -p
Ⅱ、创建数据库
CREATE DATABASE django;
效果
Ⅲ、修改setting.py配置文件
第78行
DATABASES = {'default': {'ENGINE': 'django.db.backends.mysql','NAME': 'db1', # 数据库名字'USER': 'root', # 用户名'PASSWORD': 'root123', # 密码'HOST': '127.0.0.1', # 安装了MySQL那台机器的host,本地照写'PORT': 3306, }
}
③操作数据库
Ⅰ、创建表
- models.py文件中:
from django.db import models
# django创建数据库表,django会给翻译为sql语句
class UserInfo(models.Model):name = models.CharField(max_length=32)password = models.CharField(max_length=64)age = models.IntegerField()class Role(models.Model):caption = models.CharField(max_length=16)
- 自动生成的sql语句
"""生成的sql语句
"""# 写了如上的类dajngo会自动生成如下sql语句,表面是app名+类名
create table app01_userinfo(id bigint auto_increment primary key,name VARCHAR(32),password VARCHAR(64)age int
)
执行命令
生成sql
python manage.py makemigrations
python manage.py migrate
- 效果
Ⅱ、删除表
将Role表删掉
在创建表的基础上把models.py文件中,要删除的表的类注释或删除掉即可
from django.db import models
# django创建数据库表,django会给翻译为sql语句
class UserInfo(models.Model):name = models.CharField(max_length=32)password = models.CharField(max_length=64)age = models.IntegerField()# class Role(models.Model):
# caption = models.CharField(max_length=16)
- 执行代码
python manage.py makemigrations
python manage.py migrate
Ⅲ、修改表
- 在创建表的基础上把models.py文件修改即可
class UserInfo(models.Model):name = models.CharField(max_length=32)password = models.CharField(max_length=64) # varchar字段# 新增列需要设置默认值age = models.IntegerField(default=2) # 设置默认值为2data = models.IntegerField(null=True,blank=True) # int类型,字段名data,可以为空
- 然后再执行代码
python manage.py makemigrations
python manage.py migrate
2、增删改查
①添加数据
Ⅰ、控制台添加
语法
- create()方法
- 在models.py文件中
类名或表名.objects.create(字段名='数据')
列:
Department.objects.create(title='销售部')
UserInfo.objects.create(name="大胖子",password="110110110",age=3,data=172)
- 执行代码:
python manage.py makemigrations
python manage.py migrate
Ⅱ、整合前端添加数据
- views.py文件
from app01 import models
def orm(request):# 在Department文件中执行models.Department.objects.create(title="大胖子")models.Department.objects.create(title="胡图图")return HttpResponse("成功")
- urls.py文件
# 测试orm添加数据,访问orm后端执行sqlpath('orm/',views.orm())
②删除数据
Ⅰ、控制台删除
- 语法delete()
# 删除数据
UserInfo.objects.all(id=3).delete() # 删除UserInof表中id为3的数据
Department.objects.all().delete() # 删除全部
③获取数据
语法
类名或表名.objects.all() # 返回值是列表里面封装了对象,每行的对象。每一行数据都是一个对象
- 获取全部 all()
# 获得数据
data_list = UserInfo.objects.all() # 返回值是个列表,封装了每一行的对象
for obj in data_list: # 使用for循环遍历,每行的对象并取出每行表的数据print(obj.id,obj.name,obj.password,obj.age,obj.data)
- 指定条件获取filter()
- first():获取列表第一个对象
obj = UserInfo.objects.filter(id=1).first() # 直接返回一个对象
print(obj.id,obj.name,obj.password,obj.age,obj.data)
④修改数据
- update()
UserInfo.objects.filter(name="大胖子").update(age=999)
3、综合案例:用户管理
- 创建app
python manage.py startapp app1
三、Django开发
- 员工管理系统,基础
- Demo2
1、项目初始化
①、删除多余的代码
②、创建app
pycharm项目终端中
python manage.py startapp app1
③、注册app
填写的是路径
'app01.apps.App01Config'
2、编写数据库
①、设计表结构
②、创建表
from django.db import models"""
部门表
"""
class Department(models.Model):# 设置自增的,注释掉是因为pycharm创建项目会默认自动创建id# models.BigAutoField(verbose_name='标题',primar=True) title = models.CharField(verbose_name='标题', max_length=32) # verbose_name='标题',著名此表头的作用"""
员工表"""
class UserInfo(models.Model):name = models.CharField(verbose_name='姓名', max_length=16)password = models.CharField(verbose_name='密码', max_length=64) # 字符age = models.IntegerField(verbose_name="年龄") # 整型# max_digits:数字长度10,decimal_places:小数有两位,default默认初始值为0account = models.DecimalField(verbose_name='账户余额', max_digits=10, decimal_places=2, default=0)create_time = models.DateTimeField(verbose_name='入职时间')"""外键部门表"""# 无约束# depart_id = models.BigIntegerField(verbose_name='部门表ID') # 有约束# - to :表与哪张表关联 , to_fields :表与哪个字段关联# on_delete=models.CASCADE():表示级联删除,部门表的IT部门被删除了,所属IT部门的员工表的员工会连带删除# 表头名:depart_id django会根据to_fields自动生成列名depart = models.ForeignKey(to=Department, to_field="id",on_delete=models.CASCADE # 置空# blank=True:可以为空值,# on_delete=models.SET_NULL():部门表的IT部门被删除了,所属IT部门的员工的部门字段会变为null空值,即无所属部门# depart = models.ForeignKey(to=Department, to_fields="id", blank=True,on_delete=models.SET_NULL())"""在django中约束。在数据库存储的是1和2,约束只能选择哪一部分"""gender_choices= ((1, '男'),(2, '女'))gender = models.SmallIntegerField(verbose_name='性别',choices=gender_choices)
③、创建数据库
- 打开命令终端
win+r ,输入cmd
- 登录到mysql
mysql -h localhost -u root -p
- 创建数据库djangoDemo2,并设置编码UTF-8
create database djangoDemo2 DEFAULT CHARSET utf8 COLLATE utf8_general_ci;
- 查看数据库
show databases;
④、修改Settings.py配置文件
- 将原有的DATABSES全部注释掉,77行左右直接更换如下:注意修改数据库名、用户名、密码
DATABASES = {'default': {'ENGINE': 'django.db.backends.mysql','NAME': 'djangoDemo2', # 数据库名字'USER': 'root','PASSWORD': '1234','HOST': '127.0.0.1', # 哪台机器安装了MySQL'PORT': 3306, }
}
⑤、django命令生成表
python manage.py makemigrations
python manage.py migrate
⑥、添加数据
控制台添加
- 选择数据库
USE djangodemo2
- 添加数据
insert into app_01 app1_department(title) values("销售部"),("IT部");
3、导入静态文件
解压放入app01目录下
static文件:https://wwt.lanzouy.com/iFXts0eu1vre
templates:https://wwt.lanzouy.com/ikXAv0eu1vtg
4、部门管理功能
注意导包,这个项目后面添加的功能不会把导包写出来,只会书写前端没导过的包,从而循循渐进
①、查询
- views.py文件
from django.shortcuts import render
from app1 import modelsdef depart_list(request):"""部门列表"""# 从数据库中获取全部部门信息query_set = models.Department.objects.all()return render(request, 'depart_list.html', {'queryset': query_set}) # 把数据库信息返回给前端遍历显示
- urls.py
from django.urls import path
from app1 import viewsurlpatterns = [# path('admin/', admin.site.urls),path('depart/list/', views.depart_list),
]
- depart_list.html文件
②、新增
- views.py
from django.shortcuts import redirectdef depart_add(request):if request.method == 'GET':return render(request, 'depart_add.html')# 获取用户提交过来的数据title = request.POST.get("title")# 保存到数据库# create(数据库的列名 = 前端提交的数据)models.Department.objects.create(title=title)# 重定向,显示所有部门return redirect('/depart/list/')
- urls.py
# 新增页面path('depart/add/', views.depart_add),
- depart_add.html
无修改,使用即可
③、删除
- vuews.py
def depart_delete(request):# 获取ID# http://127.0.0.1:8000/depart/delete/?nid=1nid = request.GET.get('nid')# 删除models.Department.objects.filter(id=nid).delete()# 重定向return redirect('/depart/list/') # 重定向路径需要在前面也加个 / 千万要注意
- urls.py
# 删除部门path('depart/delete/', views.depart_delete),
- depart_list.html
④、编辑
- views.py
def depart_edit(request, nid):if request.method == 'GET':row_update = models.Department.objects.filter(id=nid).first()print(f"被修改的部门id和名称:{row_update.id, row_update.title}")return render(request, 'depart_edit.html', {'row_update': row_update.title})# 获取用户提交的标题title = request.POST.get("title")# 根据id找到数据库中的数据并进行更新models.Department.objects.filter(id=nid).update(title=title)# 重定向返回主页面return redirect("/depart/list/")
- urls.py
# 编辑部门# http://127.0.0.1:8000/depart/4/edit 中间的数字用来分辨是哪个部门path('depart/<int:nid>/edit/', views.depart_edit),
depart.html
depart_list.html
5、django的html继承
- 继承语法
{% extends 'layout.html' %} <!--继承 页面-->
{% block content %}这里写html页面样式,子类自己独有的
{% endblock %}
- 作用
可以显示父类的所有页面,并在其基础上进行修改,从而实现自己独特的页面,避免了重复的代码
- 父类.html
<h1>这个是父类的,子类继承后也会有</h1>
<div>{% block content %}{% endblock %} <!--父类给子类自己编写的地方,标签对应着-->
</div>
- 子类.html
{% extends '父类.html' %}
{% block content %}{% endblock %}
四、员工表的管理功能
①、执行sql让数据库有数据
登录数据库: win+r ,cmd 。mysql -u root -p
选择数据库:USE dangodemo2
- 执行sql添加数据
insert into app1_userinfo(name,password,age,account,create_time.grdner,depart_id) values("胡图图","110110110",7,100.64,"2022-11-1",2,1);
insert into app1_userinfo(name,password,age,account,create_time.grdner,depart_id) values("大胖子","110110110",7,100.64,"2022-11-1",2,1);
②、查询
- views.py
def user_list(request):# 获取用户全部值user_info_list = models.UserInfo.objects.all()# """用python语法,这里是后端的获取数据,加深理解代码 ,把对象传入前端在前端获取值 """# for obj in user_info_list:# print(obj.id, obj.name, obj.account, obj.create_time.strftime("%Y-%m-%d"), obj.get_gender_display(),# obj.depart_id, obj.depart.title)# """重点"""# obj.create_time.strftime("%Y-%m-%d") # strftime("%Y-%m-%d"):表显示年月日# obj.get_gender_display() # 创建员工表时给其定义了,存储数据库1代表是男,2代表是女。这个方法意思是获取规则# obj.depart.title # 根据id获取,链表的title字段的数据,depart:是models.py文件创建员工表的字段返回值,title则是外键部门表的部门名称字段return render(request, 'user_list.html', {'user_info_list': user_info_list})
- urls.py
# 员工管理path('user/list/', views.user_list),
user_list.html
obj.get_gender_display()
创建员工表时给其定义了,存储数据库1代表是男,2代表是女。这个方法意思是获取规则,从而更好的显示在数据库
员工表:
因为存储在数据库的数据是1和2
**obj.depart.title **
因为外键去获取另一个表的值,title是部门表的部门名称,通过外键查询
员工表:
效果:
员工表在数据库的样子
③、添加(原始方法)
- 原始方法:麻烦
- 用户提交数据没有校验
- 错误,页面上不能显示错误提示
- 页面上每一个字段都需要我们写一遍
- 关联的数据,需要我们手动循环一个一个获取
- views.py
def user_add(request):# 访问页面是get请求,提交数据是post请求if request.method == "GET":context = { 'gender_choices': models.UserInfo.gender_choices, # 获取所有性别对应的中文'depart_list': models.Department.objects.all() # 获取所有部门}return render(request, 'user_add.html', context) # 将字典返回到前端# post请求,通过前端表单name值获取每个表单数据user = request.POST.get("ruser")pwd = request.POST.get("pwd")age = request.POST.get("age")ac = request.POST.get("ac")ctime = request.POST.get("ctime")gender = request.POST.get("gd")dp = request.POST.get("dp")# 将数据添加到数据库中models.UserInfo.objects.create(name=user, password=pwd, age=age, account=ac, create_time=ctime, gender=gender,depart_id=dp)# 添加成功返回用户列表页面return redirect("/user/list")
- urls.py
# 添加path('user/add/', views.user_add),
- user_add.html
{% extends 'layout.html' %}
{% 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 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 %}
- 效果:
④、组件
- Form组件(小简便)
- ModelForm组件(最简便)
Ⅰ、From组件
简化重复书写表单
- views.py
class MyForm(Form):user = forms.CharField(widget=forms.Input)pwd = form.CharFiled(widget=forms.Input)email = form.CharFiled(widget=forms.Input)account = form.CharFiled(widget=forms.Input)create_time = form.CharFiled(widget=forms.Input)depart = form.CharFiled(widget=forms.Input)gender = form.CharFiled(widget=forms.Input)def user_add(request):if request.method == "GET":form = MyForm()return render(request, 'user_add.html',{"form":form})
- user_add.html
<form method="post"><!--通过form自动生成表单-->{{ form.user }}{{ form.pwd }}{{ form.email }}<!-- <input type="text" placeholder="姓名" name="user" /> -->
</form>
使用循环加工
<form method="post">{% for field in form%}{{ field }}{% endfor %}<!-- <input type="text" placeholder="姓名" name="user" /> -->
</form>
Ⅱ、ModeForm组件(推荐)
再Form组件的基础上进一步简化
- views.py
class MyForm(ModelForm): # 只有这里有区别xxx = form.CharField*("...") # 自定义字段,也支持自定义生成一个字段class Meta:model = UserInfo # UserInfo是创建员工表的类名fields = ["name","password","age","account","create_time","depart","gender","xxx"] # 列表内写的是字段返回值,字段名def user_add(request):if request.method == "GET":form = MyForm()return render(request, 'user_add.html',{"form":form})
- models.py
class UserInfo(models.Model):""" 员工表 """name = models.CharField(verbose_name="姓名", max_length=16)password = models.CharField(verbose_name="密码", max_length=64)age = models.IntegerField(verbose_name="年龄")account = models.DecimalField(verbose_name="账户余额", max_digits=10, decimal_places=2, default=0)create_time = models.DateTimeField(verbose_name="入职时间")depart = models.ForeignKey(to="Department", to_field="id", on_delete=models.CASCADE)gender_choices = ((1, "男"),(2, "女"),)gender = models.SmallIntegerField(verbose_name="性别", choices=gender_choices)
- user_add.html
<form method="post">{% for field in form%}{{ field }}{% endfor %}<!-- <input type="text" placeholder="姓名" name="user" /> -->
</form>
⑤、ModelForm组件实现添加
- views.py
"""
组件实现添加用户
"""from django import forms# 使用组件
class UserModelForm(forms.ModelForm):name = forms.CharField(min_length=3, label="用户名") # 设置name表单接收数据最小值为3class Meta:model = models.UserInfofields = ["name", "password", "age", "account", "create_time", "gender", "depart"]# 定义表单的class属性# widgets = {# "name": forms.TextInput(attrs={"class": "form-control"}),# "password": forms.TextInput(attrs={"class": "form-control"}),# }# 简化上面注释的代码# 批量生成,让字段加样式def __init__(self, *args, **kwargs):super().__init__(*args, **kwargs)# 循环获取所有插件for name, field in self.fields.items(): # 这里的name是字段名# if name == "password": # 让password这个字段不加class# continuefield.widgets.attrs = {"class": "form-control", "placeholder": field.labels}def user_model_form_add(request):if request.method == "GET":form = UserModelForm()return render(request, 'user_model_form_add.html', {'form': form})# 用户使用post提交数据,数据校验form = UserModelForm(data=request.POST)if form.is_valid():# 逐一校验,数据合法存储入数据库# print(form.changed_data)form.save()return redirect('/user/list/')else:print(form.errors) # 将错误信息打印出来return render(request, 'user_model_form_add.html', {'form': form})
- urls.py
# 组件实现添加path('user/model/form/add', views.user_model_form_add)
setting.py设置中文
LANGUAGE_CODE = 'zh-hans'
user_model_form_add.html
{% extends 'layout.html' %}{% 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 %}<!--通过label方法取字段中文名,在models.py中设置字段的时候,verbose_name='姓名'设置的值--><!-- {{ form.name.label }}: {{ form.name }}--><!-- {{ form.password.label }}: {{ form.password }}--><!--使用循环简化如上代码-->{% for field in form %}<div class="form-group"><label>{{ field.label }}</label>{{ field }}<!--如果有错误信息在页面中显示出来,默认是显示的英文,但上一步在Setting设置成中文了--><span style="color: red;">{{ field.errors.0 }}</span> </div>{% endfor %}<button type="submit" class="btn btn-primary">提 交</button></form></div></div></div>
{% endblock %}
效果:
models.py
from django.db import models# Create your models here.
class Department(models.Model):"""部门表"""# models.BigAutoField(verbose_name='标题',primar=True) # 设置自增的,注释掉是因为pycharm创建项目会默认自动创建title = models.CharField(verbose_name='标题', max_length=32) # verbose_name='标题',著名此表头的作用# 类似于to.string方法def __str__(self):return self.titleclass UserInfo(models.Model):"""员工表"""name = models.CharField(verbose_name='姓名', max_length=16)password = models.CharField(verbose_name='密码', max_length=64) # 字符age = models.IntegerField(verbose_name="年龄") # 整型account = models.DecimalField(verbose_name='账户余额', max_digits=10, decimal_places=2, default=0)create_time = models.DateTimeField(verbose_name='入职时间')depart = models.ForeignKey(verbose_name='部门', to=Department, to_field="id", on_delete=models.CASCADE)gender_choices = ((1, '男'),(2, '女'))gender = models.SmallIntegerField(verbose_name='性别', choices=gender_choices)
⑥编辑
使用组件
Ⅰ、思路
- 点击编辑用户,跳转页面并携带需要编辑的那一行的id get
- 根据携带过来的id显示一些默认信息(从数据库获取) get
- 提交:post
- 错误提示、数据校验
- 数据库更新数据
Ⅱ、实现
- views.py
def user_edit(request, nid):row_object = models.UserInfo.objects.filter(id=nid).first() # 用于告诉ModelForm是要修改哪一行数据,而不是添加# 根据id获取要编辑的那一行数据,从而将原来的值显示在页面上if request.method == 'GET':# row_object = models.UserInfo.objects.filter(id=nid).first()form = UserModelForm(instance=row_object)name = row_object.namereturn render(request, 'user_edit.html', {'form': form, 'name': name}) # 因为form是字典所以可以直接返回,不用大括号# post提交表单请求,并数据校验# row_object = models.UserInfo.objects.filter(id=nid).first() # 用于告诉ModelForm是要修改哪一行数据,而不是添加form = UserModelForm(data=request.POST, instance=row_object)if form.is_valid():form.save() # 数据合法存储入数据库return redirect('/user/list/')else:return render(request, 'user_edit.html', {'form': form})
- urls.py
# 编辑path('user/<int:nid>/edit/', views.user_edit),
- user_edit.html
需要自己创建
{% extends 'layout.html' %}{% block content %}<div class="container"><div class="panel panel-default"><div class="panel-heading"><h3 class="panel-title" > 编辑<font color="#1e90ff">{{ name }}</font>用户 </h3></div><div class="panel-body"><form method="post" novalidate>{% csrf_token %}<!--通过label方法取字段中文名,在models.py中设置字段的时候,verbose_name='姓名'设置的值--><!-- {{ form.name.label }}: {{ form.name }}--><!-- {{ form.password.label }}: {{ form.password }}-->{% for field in form %}<div class="form-group"><label>{{ field.label }}</label>{{ field }}<!--如果有错误信息在页面中显示出来,默认是显示的英文,但上一步在Setting设置成中文了--><span style="color: red;">{{ field.errors.0 }}</span></div>{% endfor %}<button type="submit" class="btn btn-primary">提 交</button></form></div></div></div>
{% endblock %}
user_list.html
修改一些内容
效果
⑦删除
- views.py
"""
删除用户
"""def user_delete(request):# 获取ID# http://127.0.0.1:8000/depart/delete/?nid=1nid = request.GET.get('nid') # 获取删除按钮通过表单传达过来的nid值print(nid)models.UserInfo.objects.filter(id=nid).delete()return redirect('/user/list/')
- urls.py
# 删除path('user/delete/', views.user_delete),
- user_list.html
五、靓号管理
①创建表
class PrettyNum(models.Model):mobile = models.CharField(verbose_name="手机号", max_length=11)# 想要允许为空 null=True ,blank = Trueprice = models.IntegerField(verbose_name="价格")# 级别level_choice = ((1, '1级'),(2, '2级'),(3, '3级'),(4, '4级'),)level = models.SmallIntegerField(verbose_name="级别", choices=level_choice, default=1) # 小整型status_choices = ((1, '已占用'),(2, '未占用'),)status = models.SmallIntegerField(verbose_name="级别", choices=status_choices, default=2)
②靓号列表
将ID、号码、价格、级别(中文)、状态(中文)、操作(编辑和删除)展现出来
views.py
def admin_list(request):# order_by()设置排序,select * from 表名 order by level descqueryset = models.PrettyNum.objects.all().order_by("-level") # 加-则表示desc,不加-则表示levelreturn render(requesret, 'admin_list.html', {'queryset': queryset})
- urls.py
# 靓号列表主页面path('admin/list/', views.admin_list),
- admin_list.html
{% extends 'layout.html ' %}{% block content %}<div class="container"><div style="margin-bottom: 10px"><a class="btn btn-success" href="/admin/add/"><span class="glyphicon glyphicon-plus-sign" aria-hidden="true"></span>添加靓号</a></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><th>操作</th></tr></thead><tbody>{% for obj in queryset %}<tr><th>{{ obj.id }}</th><td>{{ obj.mobile }}</td><td>{{ obj.price }}</td><td>{{ obj.get_level_display }}</td><td>{{ obj.get_status_display }}</td><td><a class="btn btn-primary btn-xs" href="/admin/{{ obj.id }}/edit/">编辑</a><a class="btn btn-danger btn-xs" href="/admin/delete/?nid={{ obj.id }}">删除</a></td></tr>{% endfor %}</tbody></table></div></div>
{% endblock %}
④添加
通过正则表达式校验数据
views.py
from django.core.validators import RegexValidator
from django.core.exceptions import ValidationErrorclass UserModForm2(forms.ModelForm):# 验证:方法1# mobile = forms.CharField(# label="手机号",# validators=[RegexValidator(r'^\d{11}$', '手机号必须为11位数')] # 使用正则表达式对其加强校验# )class Meta:model = models.PrettyNum # 选择表fields = ["mobile", "price", "level", "status"] # 这个是自己选哪些字段# fields = "__all__" # 这个是所有字段# exclude = ['level'] # 这个是排除哪个字段"""加载样式"""# def __init__(self, *args, **kwargs):# super().__init__(*args, **kwargs)# # 循环获取所有插件# for name, field in self.fields.items(): # 这里的name是字段名# # if name == "password": # 让password这个字段不加class# # continue# # 设置生成的表单class值为"form-control"# field.widgets.attrs = {"class": "form-control", "placeholder": field.labels}# 验证:方法2def clean_mobile(self):txt_mobile = self.cleaned_data["mobile"] # 获取"mobile"字段用户输入的值if len(txt_mobile) != 11:# 验证不通过raise ValidationError("格式错误")# 验证通过,用户输入的值返回return txt_mobiledef admin_add(request):if request.method == 'GET':form = UserModForm2()return render(request, 'admin_add.html', {'form': form})# post请求form = UserModForm2(data=request.POST)if form.is_valid(): # 一个一个校验数据form.save() # 添加进入数据库return redirect('/admin/list/')else:print(form.errors) # 打印错误信息return render(request, 'admin_add.html', {'form': form})
- urls.py
# 添加path('admin/add/', views.admin_add),
- admin_add.html
{% extends 'layout.html' %}{% 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 }}<!--如果有错误信息在页面中显示出来,默认是显示的英文,但上一步在Setting设置成中文了--><span style="color: red;">{{ field.errors.0 }}</span></div>{% endfor %}<button type="submit" class="btn btn-primary">提 交</button></form></div></div></div>{% endblock %}
⑤编辑
电话号码不可编辑,但还是要显示到页面上
点击编辑后会携带靓号的id到后端从而修改
views.py
def admin_edit(request, nid):row_object = models.PrettyNum.objects.filter(id=nid).first()if request.method == "GET":form = UserModForm2(instance=row_object)return render(request, 'admin_edit.html', {'form': form})form = UserModForm2(data=request.POST, instance=row_object)if form.is_valid():form.save()return redirect('/admin/list')else:return render(request, 'admin_edit.html', {'form': form})
- urls.py
# 编辑path('admin/<int:nid>/edit/', views.admin_edit),
- admin_edit.html
{% extends 'layout.html' %}{% 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 }}<!--如果有错误信息在页面中显示出来,默认是显示的英文,但上一步在Setting设置成中文了--><span style="color: red;">{{ field.errors.0 }}</span></div>{% endfor %}<button type="submit" class="btn btn-primary">提 交</button></form></div></div></div>
{% endblock %}
⑥删除
- views.py
def admin_delete(request):nid = request.GET.get('nid') # 前端的?nid = {{obj.id}} ,?是占位符代表给nid赋值models.PrettyNum.objects.filter(id=nid).delete()return redirect('/admin/list')
- urls.py
# 删除path('admin/delete/', views.admin_delete)
- admin_list.html
⑦搜索查询
- 手机号搜索
Ⅰ、views.py
- 修改原主页函数文件
def admin_list(request):"""查询所有"""# order_by()设置排序,select * from 表名 order by level desc# queryset = models.PrettyNum.objects.all().order_by("-price") # 加-则表示正序,不加-则表示倒叙,按价格从高到低# return render(request, 'admin_list.html', {'queryset': queryset})"""搜索查询"""data_dict = {}search_data = request.GET.get('q', "")if search_data:data_dict["mobile__contains"] = search_dataqueryset = models.PrettyNum.objects.filter(**data_dict).order_by("-price") # 按条件查询return render(request, 'admin_list.html', {'queryset': queryset, 'search_data': search_data})
Ⅱ、urls.py
- 不改变
# 靓号列表主页面path('admin/list/', views.admin_list),
Ⅲ、admin_list.html
将原主页修改
搜索框样式是bootstrap:官网https://v3.bootcss.com/ 样式包(bootstrap-3.4.1):https://wwt.lanzouy.com/iYMpj0f7fgze
导入样式包(bootstrap-3.4.1)
<script src="{% static 'plugins/bootstrap-3.4.1/js/bootstrap.js' %}"></script>
- 代码
<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 }}"><!--设置表单名字为q,方便url拼接--><span class="input-group-btn"><button class="btn b tn-default" type="submit">Go!</button></span></form>
</div>
⑧分页查询
- 给数据库添加300条数据
写在views.py的admin_list函数中,访问即可给数据库添加300条数据
# 添加300条数据for i in range(300):models.PrettyNum.objects.create(mobile="16656678912", price=10, level=1, status=1)
Ⅰ、sql语法:
queryset = models.PrettyNum.objects.filter(**data_dict).order_by("-price")[初始分页索引:结尾id]
Ⅱ、views.py
def admin_list(request):"""查询所有"""# order_by()设置排序,select * from 表名 order by level desc# queryset = models.PrettyNum.objects.all().order_by("-price") # 加-则表示正序,不加-则表示倒叙,按价格从高到低# return render(request, 'admin_list.html', {'queryset': queryset})"""搜索查询"""data_dict = {}search_data = request.GET.get('q', "")if search_data:data_dict["mobile__contains"] = search_data"""分页"""# 获取get请求传递的值,page默认值为1,当前页码x = int(request.GET.get('p', 1)) # 搜索页码的值if x > 1:page = xpage = int(request.GET.get('page', 1)) # 页码输入的当前页码# 当前页码,根据用户想要访问的页面,计算出起止位置page_size = 10 # 显示10条数据start = (page - 1) * page_sizeend = page * page_size# 按条件查询queryset = models.PrettyNum.objects.filter(**data_dict).order_by("-price")[start:end]# 数据总条数total_count = models.PrettyNum.objects.filter(**data_dict).order_by("-price").count()"""页码"""# 总页码 = 数据总条数/每页显示数据条数total_page_count, div = divmod(total_count, page_size)# if div:# total_page_count += 1# 计算,显示出当前页的前五页和后五页plus = 5 # 显示前后页码条数if total_page_count <= 2 * plus + 1: # 小于11页# 数据库数据较少没有超过十一页,把所有页码显示start_page = 1end_page = total_page_countelse:# 数据库数据大于11页数据# 当前页小于5(小极值)if page <= plus: # page是前端用户传入要访问的页数start_page = 1end_page = 2 * plus + 1else:# 当前页+显示条数>总页码if (page + plus) > total_page_count:start_page = total_page_count - 2 * plusend_page = total_page_countelse:start_page = page - plus # 当前页减5end_page = page + plus # 后五页# 自动生成页码(前端样式)page_str_list = []# 上一页if page > 1:prev = '<li><a href="?page={}">上一页</a></li>'.format(page - 1) # 当前页减一else:prev = '<li><a href="?page={}">上一页</a></li>'.format(1)page_str_list.append(prev)# for i in range(1, total_page_count + 1): # 初始页面和总页码for i in range(start_page, end_page + 1): # +1 因为数据库搜索出来数据总数会少1if i == page: # 判断是当前页的话给其添加样式elc = '<li class="active"><a href="?page={}">{}</a></li>'.format(i, i)else:elc = '<li><a href="?page={}">{}</a></li>'.format(i, i)page_str_list.append(elc) # 将添加进列表中# 下一页if page < total_page_count:prev = '<li><a href="?page={}">下一页</a></li>'.format(page + 1) # 当前页加1else:prev = '<li><a href="?page={}">下一页</a></li>'.format(total_page_count) # 总页码page_str_list.append(prev)# 尾页one = '<li><a href="?page={}">尾页</a></li>'.format(total_page_count)page_str_list.append(one)# 使用mark_safe包裹就可以将字符串转化成html,在导包的前提下from django.utils.safestring import mark_safepage_string = mark_safe("".join(page_str_list))return render(request, 'admin_list.html',{'queryset': queryset, 'search_data': search_data, "page_string": page_string})
- urls.py
不做更改
Ⅲ、admin_list.html
<!--分页按钮--><ul class="pagination">{# <li><a href="?page=1">1</a></li>#}{# <li><a href="?page=2">2</a></li>#}{# <li><a href="?page=3">3</a></li>#}{# <li><a href="?page=4">4</a></li>#}{# <li><a href="?page=5">5</a></li>#}{{ page_string }} <!--页码--><!--分页搜索页码--><li><form method="get"><div class="input-group"><input type="text" name="p" class="form-control" placeholder="搜索号码"value="{{ search_data }}"><!--设置表单名字为q,方便url拼接--><span class="input-group-btn"><button class="btn b tn-default" type="submit">Go!</button></span></div></form></li></ul>
Ⅳ、效果:
⑨、使用封装简化分页代码(封装分页)
Ⅰ、views.py
def admin_list(request):"""查询所有"""# order_by()设置排序,select * from 表名 order by level desc# queryset = models.PrettyNum.objects.all().order_by("-price") # 加-则表示正序,不加-则表示倒叙,按价格从高到低# return render(request, 'admin_list.html', {'queryset': queryset})"""搜索查询"""data_dict = {}search_data = request.GET.get('q', "")if search_data:data_dict["mobile__contains"] = search_data"""分页"""from app1.utils.pagination import Pagination# 按条件查询# queryset = models.PrettyNum.objects.filter(**data_dict).order_by("-price")[page_object.start: page_object.end]queryset = models.PrettyNum.objects.filter(**data_dict).order_by("-price")page_object = Pagination(request, queryset) # 获取自定义组件类page_queryset = page_object.page_queryset # 获取分页完的数据page_string = page_object.html() # 生成的页码context = {"queryset": page_queryset,"search_date": search_data, # 分完页的数据"page_string": page_string # 生成的页码}return render(request, 'admin_list.html', context) # 使用组件后
Ⅱ、pagination.py
在app1中创建utils文件夹里面创建paginaion.py
将页码生成、数据获取、前端页码生成封装到pagination.py文件中Pagination类中
"""
自定义分页组件
"""
from django.utils.safestring import mark_safe
from django import formsclass Pagination(object):def __init__(self, request, queryset, page_size=10, page_param="page", plus=5):""":param request: 请求的对象:param queryset:查询的数据,符合条件的数据对这个进行分页处理:param page_size:每页显示多条数据:param page_param:在URL中传递获取分页的参数,列如:/etty/list/?page=12:param plus:显示当前页的,前、后几页(页码)"""import copyquery_dict = copy.deepcopy(request.GET)query_dict._mutable = Trueself.query_dict = query_dictself.page_param = page_parampage = request.GET.get(page_param, "1") # 把request获取前端get请求的方法,封装到page中,页码if page.isdecimal(): # 处理页码,判断页码是否是正常传入数字,而不是字符串page = int(page)else:page = 1 # 前端传入页码不规范,则默认为1self.page = pageself.page_size = page_size# 计算分页页码,sql值self.start = (page - 1) * page_sizeself.end = page * page_sizeself.page_queryset = queryset[self.start: self.end] # 分完页的数据# total_count = models.PrettyNum.objects.filter(**data_dict).order_by("-price").count()total_count = queryset.count() # 数据总条数total_page_count, div = divmod(total_count, page_size) # 总页码 = 数据总条数/每页显示数据条数if div:total_page_count += 1self.total_page_count = total_page_countself.plus = plus # 显示前后页码条数def html(self):"""页码、页码搜索"""# 计算出,显示当前页的前5页、后5页if self.total_page_count <= 2 * self.plus + 1:# 数据库中的数据比较少,都没有达到11页。start_page = 1end_page = self.total_page_countelse:# 数据库中的数据比较多 > 11页。# 当前页<5时(小极值)if self.page <= self.plus:start_page = 1end_page = 2 * self.plus + 1else:# 当前页 > 5# 当前页+5 > 总页面if (self.page + self.plus) > self.total_page_count:start_page = self.total_page_count - 2 * self.plusend_page = self.total_page_countelse:start_page = self.page - self.plusend_page = self.page + self.plus# 页码page_str_list = []self.query_dict.setlist(self.page_param, [1])page_str_list.append('<li><a href="?{}">首页</a></li>'.format(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 + 1):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)# 下一页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 name="page"style="position: relative;float:left;display: inline-block;width: 80px;border-radius: 0;"type="text" 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
Ⅲ、效果
六、拓展功能(1)
1、时间插件
插件链接:https://wwt.lanzouy.com/imuOd0fe3opc
用于美化、简化入职时间填写,可以直接通过点击xuan’ze
2、分模块开发
将views.py中用户管理、部门管理、靓号管理分为三个py文件,代码不用改,只需改urls.py中函数路径
views文件夹
urls.py
重点在导包,和函数路径
from django.contrib import admin
from django.urls import path
from app1 import viewsfrom app1.views import admin, list, user # 导入views文件urlpatterns = [# path('admin/', admin.site.urls),# 部门管理# 主页面、列表页面path('depart/list/',list.depart_list),# 新增部门path('depart/add/', list.depart_add),# 删除部门path('depart/delete/', list.depart_delete),# 编辑部门# http://127.0.0.1:8000/depart/4/edit 中间的数字用来分辨是哪个部门path('depart/<int:nid>/edit/', list.depart_edit),# 员工管理path('user/list/', user.user_list),# 添加path('user/add/', user.user_add),# 组件实现添加path('user/model/form/add', user.user_model_form_add),# 编辑path('user/<int:nid>/edit/', user.user_edit),# 删除path('user/delete/', user.user_delete),# 靓号管理# 靓号列表主页面path('admin/list/', admin.admin_list),# 添加path('admin/add/', admin.admin_add),# 编辑path('admin/<int:nid>/edit/', admin.admin_edit),# 删除path('admin/delete/', admin.admin_delete)]
七、管理员
1、创建数据库
- models.py
class VIP(models.Model):username = models.CharField(verbose_name="用户名", max_length=32)password = models.CharField(verbose_name="密码", max_length=64)
- 执行代码
python manage.py makemigrations
python manage.py migrate
2、管理员列表
- VIP.py
在views文件夹中创建VIP.py文件
from django.shortcuts import render, redirect
from app1 import models
# 分页自定义模块
from app1.utils.pagination import Pagination"""
管理员列表
"""
def VIP_list(request):# 搜索功能# 构造搜索条件data_dict = {}search_data = request.GET.get('q', "")if search_data:data_dict["username__contains"] = search_data# 根据条件去数据库获取queryset = models.VIP.objects.filter(**data_dict)# 分页page_object = Pagination(request, queryset)queryset = {'queryset': queryset,'page_string': page_object.html(),'search_data': search_data,}return render(request, 'VIP_list.html', queryset)
- urls.py
# 主页面
path('VIP/list', VIP.VIP_list),
- VIP.html
{% extends 'layout.html ' %}{% block content %}<div class="container"><div style="margin-bottom: 10px" class="clearfix"><a class="btn btn-success" href="/VIP/add"><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 }}"> <!--将搜索的字显示在input框中--><!--设置表单名字为q,方便url拼接--><span class="input-group-btn"><button class="btn b tn-default" type="submit">搜索查询</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><!-- /input-group --><!-- 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="/VIP/{{obj.id}}/reset/">重置密码</a></td><td><a class="btn btn-primary btn-xs" href="/VIP/{{ obj.id }}/edit">编辑</a><a class="btn btn-danger btn-xs" href="/VIP/delete/?nid={{ obj.id }}">删除</a></td></tr>{% endfor %}</tbody></table></div><!--分页按钮--><ul class="pagination">{{ page_string }} <!--页码、分页搜索--></ul></div>
{% endblock %}
3、添加
重点:密码校验
VIP.py
views文件夹下
from django import forms
from django.core.exceptions import ValidationError
from app1.utils.bootstrap import BootStrapModeForm # 创建input框
from app1.utils.encrypt import md5 # 加密# 使用组件创建input框
class VIPModelForm(BootStrapModeForm): # 或者继承forms.Modelform# 额外生成一个确认密码表单confirm_password = forms.CharField(label="确认密码",widget=forms.PasswordInput(render_value=True) # 输入密码时候不会显示密码,render_value=True表示密码错了密码不需要重新输入)class Meta:model = models.VIPfields = ["username", "password", "confirm_password"]# 给原有字段,生成的表单添加额外修饰widgets = {"password": forms.PasswordInput(render_value=True)}# 加密def clean_password(self):pwd = self.cleaned_data.get("password")return md5(pwd) # 调用加密函数给input框的数据加密,并将加完密的函数返回,则下面方法获取该表单都是加密了的# 钩子函数,获取指定字段用户输入的值def clean_confirm_password(self):# form.cleaned_data 获取校验成功后所有数据,具体看上面定义的clean_confirm_password钩子函数password = self.cleaned_data.get("password") # 因为上面给表单加密了,所以这里获取的值是加密的值confirm = md5(self.cleaned_data.get("confirm_password")) # 获取确认用户表单,用户输入的值,并使其加密从而可以使密文和密文进行比较if confirm != password:raise ValidationError("密码不一致") # 抛出异常到前端,需要导包return confirm # 这里返回的值就是存储入数据库的值def VIP_add(request):title = "添加管理员"if request.method == "GET":form = VIPModelForm()return render(request, 'change.html', {"title": title, "form": form})# post请求校验数据,并跳转主页面form = VIPModelForm(data=request.POST)if form.is_valid():# 上面的钩子函数也是校验数据form.save()return redirect('/VIP/list')# 有错误信息,则还是在添加页面,并可以看到错误信息return render(request, 'change.html', {"title": title, "form": form})
- urls.py
# 添加管理员path('VIP/add', VIP.VIP_add),
- 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 }}<!--如果有错误信息在页面中显示出来,默认是显示的英文,但上一步在Setting设置成中文了--><span style="color: red;">{{ field.errors.0 }}</span></div>{% endfor %}<button type="submit" class="btn btn-primary">提 交</button></form></div></div></div>{% endblock %}
- encrypt.py
- 自定义的密码校验工具类,放在app01/utils/下
- 密码和确认密码比较也是使用加密后的密码进行比较
- 原理是将密码嵌入到django配置文件随机生成的字符串中,具体见第8行代码
import hashlib
from django.conf import settings"""
给字符串加密
"""
def md5(data_string):obj = hashlib.md5(settings.SECRET_KEY.encode('utf-8')) # SECRET_KEY是django的配置文件Setting随机生成的一个字符串obj.update(data_string.encode('utf-8'))return obj.hexdigest()
4、编辑
- VIP.py
views文件夹子文件
class VIPEditModelForm(BootStrapModeForm):class Meta:model = models.VIPfields = ["username"] # 只允许修改用户名def VIP_edit(request, nid):title = "编辑管理员"row_object = models.VIP.objects.filter(id=nid).first()if not row_object: # 判断是否有这个用户,没有就证明id为错误的return redirect('/VIP/list')if request.method == "GET":form = VIPEditModelForm(instance=row_object) # 将原来的值显示在页面上return render(request, 'change.html', {"title": title, "form": form})# 提交数据form = VIPEditModelForm(data=request.POST, instance=row_object)if form.is_valid():form.save()return redirect('/VIP/list')return render(request, 'change.html', {"title": title, "form": form})
- urls.py
# 编辑path('VIP/<int:nid>/edit/', VIP.VIP_edit),
- change.html
- 和如上添加管理员使用同一个html,只是有一些区别在views.py文件(VIP.py)中
5、删除
- VIP.py
def VIP_delete(request):nid = request.GET.get('nid')models.VIP.objects.filter(id=nid).delete()return redirect('/VIP/list')
- urls.py
# 删除path('VIP/delete/', VIP.VIP_delete),
- 注意把管理员的主页面按钮路径改一下
6、重置密码
- views.py
# 使用组件创建input框
class VIPresetModelForm(BootStrapModeForm): # 或者继承forms.Modelform# 额外生成一个确认密码表单confirm_password = forms.CharField(label="确认密码",widget=forms.PasswordInput(render_value=True) # 输入密码时候不会显示密码,render_value=True表示密码错了密码不需要重新输入)class Meta:model = models.VIPfields = ["password", "confirm_password"]# 给原有字段,生成的表单添加额外修饰widgets = {"password": forms.PasswordInput(render_value=True)}# 加密def clean_password(self):pwd = self.cleaned_data.get("password")md5_pwd = md5(pwd) # 调用加密函数给input框的数据加密,并将加完密的函数返回,则下面方法获取该表单都是加密了的# 去数据库校验之前密码和新输入的密码是否一致exists = models.VIP.objects.filter(id=self.instance.pk, password=md5_pwd) # 返回的是布尔值if exists:raise ValidationError("密码使用过,请尝试重新输入密码")return md5_pwd# 钩子函数,获取指定字段用户输入的值def clean_confirm_password(self):# form.cleaned_data 获取校验成功后所有数据,具体看上面定义的clean_confirm_password钩子函数password = self.cleaned_data.get("password") # 因为上面给表单加密了,所以这里获取的值是加密的值confirm = md5(self.cleaned_data.get("confirm_password")) # 获取确认用户表单,用户输入的值,并使其加密从而可以使密文和密文进行比较if confirm != password:raise ValidationError("密码不一致") # 抛出异常到前端,需要导包return confirm # 这里返回的值就是存储入数据库的值def VIP_reset(request, nid):row_object = models.VIP.objects.filter(id=nid).first()if not row_object:return redirect('/VIP/list')title = "重置用户:{} 密码".format(row_object.username)if request.method == 'GET':form = VIPresetModelForm()return render(request, 'change.html', {"title": title, "form": form})# 提交数据form = VIPresetModelForm(data=request.POST, instance=row_object)if form.is_valid():form.save()return redirect('/VIP/list')return render(request, 'change.html', {"title": title, "form": form})
- urls.py
# 重置密码path('VIP/<int:nid>/reset/', VIP.VIP_reset),
- BootStrap.py
自定义的工具包,因为重置密码使用的是form而不是ModelForm所以使用继承改装一下
from django import forms"""
添加样式,实际是给每个表单创建class属性
"""class BootStrap:def __int__(self, *args, **kwargs):super().__init__(*args, **kwargs)# 循环Modelform中所有字段,给每个字段的插件设置for name, field in self.field.items():# 字段中有属性,保留原来的属性,没有属性才增加if field.widget.attrs:field.widget.attrs["class"] = "form-control"field.widget.attrs["placeholder"] = field.labelelse:field.widget.attrs = {"class": "form-control","placeholder": field.label}class BootStrapModeForm(BootStrap, forms.ModelForm):passclass BootStrapForm(BootStrap, forms.Form):pass
- change.html
八、拓展功能(2)
1、管理员登录
- views.py
from django.shortcuts import render, redirect, HttpResponse
from app1.utils.encrypt import md5
from app1 import models"""
登录
"""
# 使用form做
from django import forms
from app1.utils.bootstrap import BootStrapFormclass LoginForm(BootStrapForm): # Form需要自定义字段,username = forms.CharField(label="用户名",widget=forms.PasswordInput(attrs={"class": "form-control"}) # 定义标签)password = forms.CharField(label="密码",widget=forms.PasswordInput(attrs={"class": "form-control"}, render_value=True) # 密码标签)# 钩子函数,给密码加密,从而可以使数据与后端密码比较def clean_password(self):pwd = self.cleaned_data.get("password")return md5(pwd)# # ModelForm则是从数据库中拿字段,去数据库拿安全性差些
# class LoginModelForm(forms.ModelForm):
# class Meta:
# model = models.VIP
# fields = ['username', 'password']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():# form.cleaned_data获取前端用户输入的值(用户名和密码)# print(form.cleaned_data) # 验证成功,获取到的用户名和密码,因为form与modelForm不同,form不与数据库关联不可以直接写入数据库# 去数据库校验用户名和密码是否正确# 因为上面有个钩子函数,给form.cleaned_data方法加密了,所以这个获取的也是加密的密码first = models.VIP.objects.filter(**form.cleaned_data).first()# first = models.VIP.objects.filter(username="xxx", password="xxx").first() ,如上代替具体见搜索手机号详解,只有字典可以这么用if not first:form.add_error("password", "用户密码错误") # 给password字段主动添加错误,password从上面18行创建字段表单获取的# 存储session到数据库django_session表中自动创建的,也就是用户cookie的凭证,使用cookie的时候得用session来辨别用户# request.session["info"] = {'id': filter.id, 'username': first.username} # 获取用户id和username存储到session中,来当用户凭证request.session["info"] = first.username # 这里只存储个usernamereturn redirect("/VIP/list/")return render(request, 'login.html', {'form': form})
- urls.py
# 登录path('login/', login.login),
- login.html
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><link rel="stylesheet" href="{% static 'plugins/bootstrap-3.4.1/css/bootstrap.min.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><input type="submit" value="登 录" class="btn btn-primary"></form>
</div></body>
</html>
- cookie和session
request.session["info"] = {'id': filter.id, 'username': first.username} # 获取用户id和username存储到session中,来当用户凭证request.session["info"] = first.username # 这里只存储个username
2、校验用户登录
①校验登录
原理是通过session来获取cookie,如果没有cookie就没有登录过
# 校验是否登录,没登陆跳转登录页面info = request.session.get("info") # 获取session的info字典的用户cookie凭证if not info:return redirect('/login/')
②中间件校验
因为中间键的使用所以,不需要每个views.py中都使用如上代码校验登录。只需要定义一个中间件即可,函数文件中代码不需要改变
- 创建中间件
在app1下创建个文件夹middleware,再创建个auth.py。里面代码如下
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# 读取当前访问的用户session信息,如若读到证明登录过,则继续执行info_dict = request.session.get("info")if info_dict:return# 没有登录信息return redirect('/login/')
- 注册中间件
setting.py文件中,每个类是一个中间件
3、注销
- 原理
删除cookie即可,因为没有cookie需要重新登录
- login.py
def logout(request):request.session.clear() # 将当前用户的session删除掉,等于将用户cookie删除return redirect('/login/')
- urls.py
# 注销path('logout/', login.logout),
- layout.html
将html的注销标签的执行函数地址改一下
<li><a href="/logout/">注销</a></li>
4、显示当前用户名
随着用户改变用户名也会跟着自动改变
- 获取当前用户的账号和密码
# 通过session来获取当前用户的账号和密码info = request.session.get("info") # 获取session的info字典的用户cookie凭证# 取值,存储在session中用户输入的账号和密码info["id"] info["username"]
- 应用在前端
{{ request.session.info.username }}
- 效果:
- 获取的是login.py文件夹存储入session的值:
5、图片验证码
①pillow插件
自动生成验证码图片插件
Ⅰ、安装插件
pip install pillow
或者到pycham设置中项目-python解释器中安装
Ⅱ、使用
参考文献:https://www.cnblogs.com/wupeiqi/articles/5812291.html
Ⅲ、字体文件
生成验证码的字体:
Ⅳ、验证码的生成与校验
- code.py
自定义的工具包文件,注意修改第4行的字体路径,这个字体是和app1在同一个目录下
import random
from PIL import Image, ImageDraw, ImageFont, ImageFilterdef 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 str(random.randint(0, 9)) # 生成数字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)
- login.html
<div class="form-group"><label for="id_code">图片验证码</label><div class="row"><div class="col-xs-7">
{# <input type="text" name="code" class="form-control" placeholder="请输入图片验证码"required="" id="id_code">#}
{# <span style="color: red;"></span>#}{{ form.code }}<span style="color: red">{{ form.code.errors.0 }}</span></div><div class="col-xs-5"><img id="image_code" src="data:image/code/" style="width: 125px;"></div></div></div>
auth.py中间件
login.py
核心代码53-58
from django.shortcuts import render, redirect, HttpResponse
from app1.utils.encrypt import md5
from app1 import models
from app1.utils.code import check_code
from io import BytesIO# 使用form做
from django import forms
from app1.utils.bootstrap import BootStrapFormclass LoginForm(BootStrapForm): # Form需要自定义字段,username = forms.CharField(label="用户名",widget=forms.TextInput(attrs={"class": "form-control"}) # 定义标签)password = forms.CharField(label="密码",widget=forms.PasswordInput(attrs={"class": "form-control"}, render_value=True) # 密码标签)code = forms.CharField(label="验证码",widget=forms.TextInput,required=True)# 钩子函数,给密码加密,从而可以使数据与后端密码比较def clean_password(self):pwd = self.cleaned_data.get("password")return md5(pwd)# # ModelForm则是从数据库中拿字段,去数据库拿安全性差些
# class LoginModelForm(forms.ModelForm):
# class Meta:
# model = models.VIP
# fields = ['username', 'password']"""
登录
"""
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():# form.cleaned_data获取前端用户输入的值(用户名和密码、验证码)# print(form.cleaned_data) # 验证成功,获取到的用户名和密码,因为form与modelForm不同,form不与数据库关联不可以直接写入数据库# 验证码校验,并使用pop()把code验证码的值剔除掉,从而保证其不会被存储入数据库user_input_code = form.cleaned_data['code'] # 用户填写的验证码code = request.session.get('image_code', "")if code == user_input_code:form.add_error("code", "验证码错误")return render(request, 'login.html', {'form': form})# 去数据库校验用户名和密码是否正确# 因为上面有个钩子函数,给form.cleaned_data方法加密了,所以这个获取的也是加密的密码first = models.VIP.objects.filter(**form.cleaned_data).first()# first = models.VIP.objects.filter(username="xxx", password="xxx").first() ,如上代替具体见搜索手机号详解,只有字典可以这么用if not first:form.add_error("password", "用户密码错误") # 给password字段主动添加错误,password从上面18行创建字段表单获取的# 存储session到数据库django_session表中自动创建的,也就是用户cookie的凭证,使用cookie的时候得用session来辨别用户request.session["info"] = {'username': first.username} # 获取用户id和username存储到session中,来当用户凭证,这里只存储username# 设置session存活时间,7天内免登录request.session.set_expiry(60 * 60 * 24 * 7)return redirect("/VIP/list/")return render(request, 'login.html', {'form': form})"""
验证码
"""
def image(request):# 调用pillow函数,生成图片img, code_string = check_code()# 将生成的验证码写入session中,方便后续用于校验request.session['image_code'] = code_string# 给Session设置60秒超时,即验证码有效时间只有60srequest.session.set_expiry(60)stream = BytesIO() # 在内存中创建一个文件img.save(stream, 'png') # 将生成的img文件写入,文件中return HttpResponse(stream.getvalue())
九、Ajax异步请求
发送局部请求
1、ajax发送get请求
- 前端页面
{% extends 'layout.html' %}{% block content %}<div class="container"><h1>任务管理</h1><h3>示例1</h3><input id="btn1" type="button" class="btn btn-prima ry" value="点击" onclick="clickMe();"/></div>
{% endblock %}
{% block js %}
<script type="text/javascript">function clikMe(){$.ajax({url: '/task/ajax/', // 发送的地址type: "get",data: {n1: 123,n2: 456},success: function (res) {console.log(res);}})}</script>{% endblock %}
$.ajax({url: '/task/ajax/', // 发送的地址type: "get",data: {n1: 123,n2: 456},success: function (res) {console.log(res);}
}){% endblock %}
- 后端接收请求
from django.shortcuts import render, HttpResponsedef task_ajax(request):print(request.GET)return HttpResponse("成功了")
- urls.py
# ajax请求path('ajax/task/', ajax.task_ajax)
2、ajax发送post请求
- 前端页面
{% extends 'layout.html' %}{% block content %}<div class="container"><h1>任务管理</h1><h3>示例1</h3><input id="btn1" type="button" class="btn btn-prima ry" value="点击" onclick="clickMe();"/></div>
{% endblock %}
{% block js %}
<script type="text/javascript">function clikMe(){$.ajax({url: '/task/ajax/', //发送的地址type: "get",data: {n1: 123,n2: 456},success: function (res) {console.log(res);}})}</script>{% endblock %}
- 后端
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("成功了")
- urls.py
# ajax请求path('ajax/task/', ajax.task_ajax)
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 () { // btn1是表单id$.ajax({url: '/task/ajax/',type: "post",data: {n1: 123,n2: 456},success: function (res) {console.log(res);}})})}</script>
{% endblock %}
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", // 将后端返回数据转换成json对象格式,json数据在python中是字典(键值对)success: function (res) {console.log(res);console.log(res.status); //通过json数据对象键获取值console.log(res.data);}})})}</script>
{% endblock %}
- 后端
from django.shortcuts import render, redirect, HttpResponse
from django.views.decorators.csrf import csrf_exempt
import json
from django.http import JsonResponsedef 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)) # 将数据返回去前端页面# return JsonResponse(data_dict) # django带的方法可以简化如上返回代码,需要导包
- urls.py
# ajax请求path('ajax/task/', ajax.task_ajax)
5、测试代码
- task.html
{% extends 'layout.html' %}{% block content %}<hr/><h1>Ajax学习</h1><h3>示例2</h3><input type="text" id="txtUser" placeholder="姓名"><input type="text" id="txtAge" placeholder="年龄"><input id="btn2" type="button" class="btn btn-primary" value="点击"/><h3>示例3</h3><form id="form3"><input type="text" name="user" placeholder="姓名"><input type="text" name="age" placeholder="年龄"><input type="text" name="email" placeholder="邮箱"><input type="text" name="more" placeholder="介绍"></form><input id="btn3" type="button" class="btn btn-primary" value="点击"/></div>
{% endblock %}{% block js %}<script type="text/javascript">$(function () {// 页面框架加载完成之后代码自动执行bindBtn1Event2();bindBtn1Event3();})function bindBtn1Event2() {$("#btn1").click(function () {$.ajax({url: '/task/ajax/',type: "post",data: {user: $("#textUser").val(), //jquery获取表单的值age: $("textAge").val()},dataType: "JSON", // 将后端返回数据转换成json对象格式,json数据在python中是字典(键值对)success: function (res) {console.log(res);console.log(res.status); //通过json数据对象键获取值console.log(res.data);}})})}function bindBtn1Event3() {$("#btn3").click(function () {$.ajax({url: '/task/ajax/',type: "post",data: $("#from3").serialize(), //serialize()将表单所以值传入后端dataType: "JSON", // 将后端返回数据转换成json对象格式,json数据在python中是字典(键值对)success: function (res) {console.log(res);console.log(res.status); //通过json数据对象键获取值console.log(res.data);}})})}</script>
{% endblock %}
- ajax.py
from django.shortcuts import render, redirect, HttpResponse
from django.views.decorators.csrf import csrf_exempt
import json
from django.http import JsonResponsedef 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)) # 将数据返回去前端页面# return JsonResponse(data_dict) # django带的方法可以简化如上返回代码,需要导包
- urls.py
# ajax请求,注意导入ajax.py包,views文件夹中path('ajax/task/', ajax.task_ajax),path('ajax/list/', ajax.task_list),
十、回顾与梳理
知识点的回顾:
安装Djangox
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目录下)。
- static、templates、utils
配置数据库相关操作(MySQL)
第三方模块(django3版本)
pip install mysqlclient
自己先去MySQL创建一个数据库。
mysql -u root -p CREATE DATABASE djangodemo3 CHARACTER SET utf8 COLLATE utf8_general_ci; utf-8后面是排列规则
配置数据库连接settings.py
DATABASES = {'default': {'ENGINE': 'django.db.backends.mysql','NAME': 'djangoDemo3', # 数据库名字'USER': 'root','PASSWORD': '1234','HOST': '127.0.0.1', # 哪台机器安装了MySQL'PORT': 3306,} }
在app下的models.py中编写
from django.db import modelsclass Admin(models.Model):""" 管理员 """username = models.CharField(verbose_name="用户名", max_length=32)password = models.CharField(verbose_name="密码", max_length=64)def __str__(self):return self.usernameclass 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")
分页组件。
Django银角大王武沛齐配套视频笔记,python全栈开发、pythonWeb相关推荐
- python 全栈开发,Day87(ajax登录示例,CSRF跨站请求伪造,Django的中间件,自定义分页)...
python 全栈开发,Day87(ajax登录示例,CSRF跨站请求伪造,Django的中间件,自定义分页) 一.ajax登录示例 新建项目login_ajax 修改urls.py,增加路径 fro ...
- python视频网站项目_价值2400元的python全栈开发系列Flask Python Web 网站编程视频
2 e/ b4 F1 c' H$ D! X 价值2400元的python全栈开发系列Flask Python Web 网站编程视频-优品课堂' z3 _1 Y7 ]6 j4 z # p# r# g* ...
- python全栈开发百度云_Python全栈开发9期视频
Python全栈开发9期视频 获取教程链接的步骤 2. 用微博或QQ登录编程资源库网站 3.点击兑换按钮,兑换百度云链接 教程要积分! 声明 教程由粉丝投稿,仅供学习和交流,侵删 以下凑字数!请自行忽 ...
- 路飞学城python全栈开发_python 全栈开发,Day98(路飞学城背景,django ContentType组件,表结构讲解)...
昨日内容回顾 1. 为什么要做前后端分离?-前后端交给不同的人来编写,职责划分明确.-API (IOS,安卓,PC,微信小程序...)-vue.js等框架编写前端时,会比之前写jQuery更简单快捷. ...
- python 全栈开发,Day84(django请求生命周期,FBV和CBV,ORM拾遗,Git)
一.django 请求生命周期 流程图: 1. 当用户在浏览器中输入url时,浏览器会生成请求头和请求体发给服务端 请求头和请求体中会包含浏览器的动作(action),这个动作通常为get或者post ...
- python全栈开发网络_Python全栈开发:django网络框架(二)
Model 到目前为止,当我们的程序涉及到数据库相关操作时,我们一般都会这么搞: 创建数据库,设计表结构和字段 使用 MySQLdb 来连接数据库,并编写数据访问层代码 业务逻辑层去调用数据访问层执行 ...
- python全栈人工智能192集视频_黑马程序员分享:python全栈开发环境构建
Sublime简介 Sublime Text是一个代码编辑器.也是HTML和散文先进的文本编辑器.漂亮的用户界面和非凡的功能,例如:多选择,Python插件,代码段等等.完全可自定义键绑定,菜单和工具 ...
- python学习(三):web网页框架Django,成就python全栈开发
1.Django安装 框架很完美,组件非常多,但文件太多,过于臃肿(1.. Django是一个高级的Python Web框架,它鼓励快速开发和清洁,务实的设计.· 由经验丰富的开发人员构建,它负责We ...
- python 全栈开发,Day36(作业讲解(大文件下载以及进度条展示),socket的更多方法介绍,验证客户端链接的合法性hmac,socketserver)...
先来回顾一下昨天的内容 黏包现象 粘包现象的成因 : tcp协议的特点 面向流的 为了保证可靠传输 所以有很多优化的机制 无边界 所有在连接建立的基础上传递的数据之间没有界限 收发消息很有可能不完全 ...
最新文章
- Opencv2.4.4示例程序说明
- 使用 SQL Server 2012 Analysis Services Tabular Mode 表格建模 图文教程
- 巧用Windows 7命令,修复系统故障!
- ntoskrnl损坏
- WS-Addressing 了解
- 【Python】青少年蓝桥杯_每日一题_1.03_输出字符串
- react当中子组件改变父组件的状态
- RocketMQ消息的事务架构设计
- 文献学习(part47)--A novel consensus learning approach to incomplete multi-view clustering
- 常规sql读取CLOB
- MongoDB之Java测试代码(DAO层)
- 【javascript】对原型对象、原型链的理解
- Lanenet论文解读
- 安装tensorflow出现的问题
- python 定时任务 web管理_Selenium+WebDriver+Python 定时控制任务
- 什么是图像上的频率?
- aspose.words生成pdf字体乱码为方框
- FL studio 20简易入门教程 -- 第三篇 -- 菜单栏讲解(下)
- 二、 防火墙中使用的核心技术
- 程序人生 - 游戏帧数很高,为什么还是会卡顿?