Django的基础学习
django的安装
在终端目录输入 django-admin startproject 项目名称
创建虚拟环境,安装django
通过终端命令行安装,通过pycharm专业版进行安装
manage.py项目管理的脚本
asgi.py wsgi.py接收网络请求
settings.py配置文件
urls.py 路由配置文件
django的app
app 用户管理
app 订单管理
app api
创建app
python manage.py startapp app名字
注册与启动项目
在settings.py中的INSTALLED_APPS中注册名字.apps.名字config在视图中编写视图函数,并在urls.py中导入用户请求的连接模板和静态文件
模板会默认存放在templates
静态文件:默认放在static中,因为在settings.py中默认设置了静态文件static的目录
Django的模板语法
本质:在html中写一些占位符,由数据对这些占位符进行替换和处理{% %}
请求和响应
通过render读取html的内容,在进行替换
redirect重定向
scrf安全验证
其中scrfmiddlewaretoken是关于django自带的请求,在提交数据时拿到数据后可以进行校验
数据库的操作
orm框架 mysqlclient操作数据库
在models.py中定义模型 orm翻译过程,将代码翻译成sql语句pip install mysqlclient
报错的话下载 mysqlclient wheel
功能:创建和修改数据库的表
django创建表
注册app
创建orm模型
使用命令迁移数据库: python manage.py makemigrations python manage.py migrate在对表新增字段的时候可以django默认提供了两个选项 options1 : 输入一个值来填充该字段,在执行迁移命令
option2:使用default属性填充默认值,或者使用null和blank = True设置字段允许为空,再执行迁移命令
如上图的终端提示中所示
orm的增删改查
增加数据:
# 添加操作如果存在默认值,没有添加字段数据,会默认填充default属性中的值# models.Depratment.objects.create(title="新增数据1")
# models.Depratment.objects.create(title="新增数据2")
# models.Depratment.objects.create(title="新增数据3")
# models.Depratment.objects.create(title="新增数据4")
# print(Depratment.objects.all().values())
# return HttpResponse("新增数据成功")
删除数据:
filter方法进行匹配数据库数据查找,使用delete()方法进行删除
# 删除操作
Depratment.objects.filter(id=7).delete() # 删除表中id=7的数据Depratment.objects.all().delete() # 删除全部数据
returnHttpResponse("删除成功")
获取数据:
# 获取数据
data_list=Depratment.objects.all() # 获取表中所有数据,返回的是QuerySet类型,可以理解成列表
fordataindata_list:
print(data.title)
returnHttpResponse("数据获取成功")
filter().first()得到对象,如果只拿到一条数据
data=Depratment.objects.filter(id=1).first()
print(data) # 获取的是一个列表对象
print(data.title)
更新数据
# 更新数据
Depratment.objects.all().update(title="更新数据")
Depratment.objects.filter(id=1).update(title="第一条数据更新")
案例:用户管理
1.展示数据列表
url
获取所有信息
渲染到页面
2.添加数据到数据库
如果向当前的请求发送,则可以省略action
3.删除用户
url
函数
通过id进行删除,通过页面传递回来的id参数进行删除
因为删除是get请求,需要携带参数
definfo_delete(request):
# 通过get请求拿到页面传递过来的参数
nid=request.GET.get("nid")
# 删除操作
Depratment.objects.filter(id=nid).delete()
returnredirect("/info/")
通过表单传递过来的参数进行id的匹配,然后进行删除操作,直接对数据库进行操作
django的项目
1.创建项目
2.创建app
python manage.py startapp app名字
3.设计表结构
1.部门信息
2.员工信息
在models.py编写orm表结构
deciaml字段:其中最大数位是十个,小数位占两个,默认为0
外键存储:一般存储ID,可以节省存储的开销
级联删除 on_delete=models.CASECADE
classDepartment(models.Model):
""" 部门表 """
# id = models.AutoField() 自增id
title=models.CharField(max_length=32, verbose_name="部门名称")
# def __str__(self):
# return self.title # 返回部门名称
classUserinfo(models.Model):
""" 员工表 """
name=models.CharField(max_length=32, verbose_name="员工姓名") password=models.CharField(max_length=64, verbose_name="密码") age=models.IntegerField(verbose_name="年龄")
salary=models.DecimalField(verbose_name="账户余额", max_digits=10, decimal_places=2, default=0)
create_time=models.DateTimeField(verbose_name="入职时间")
# 1. 关联表,存储部门id 具有约束力
# to表示与部门表关联,
# to_fields 表示与哪一列关联
# 生成数据列叫做 depart_id
# 如果部门删除了,关联的用户解决方案
# 1. 级联删除员工加上 on_delete = models.CASECADE
# 2. 不删除,将关联的变成空的,则要允许为空 null=True, blank=True, on_delete=models.SET_NULL
depart=models.ForeignKey(to=Department, to_fields="id", on_delete=models.CASCADE) # 级联删除
# 在Django中做的约束
# 性别,小整数
gender_choices= (
(1, "男"),
(2, "女")
)
gender=models.SmallIntegerField(verbose_name="性别", choices=gender_choices)
4.在mysql中生成表
DATABASES= {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': "app01",
"PASSWORD": "123456789",
"USER": "root",
"HOST": "127.0.0.1",
"PORT": 3306
}
}
在工具中输入迁移命令
5.静态文件的管理
6.部门管理
Django提供Form和ModelForm组件(表单)
6.1部门列表
首先获取部门表的全部信息,使用模板字符串,动态渲染到页面上
6.2添加部门
使用post请求获取到页面传递过来的数据
直接操作数据库进行数据的增加
6.3删除部门
获取页面传递过来的id信息,操作数据库进行删除
6.4编辑部门
get请求获取到页面,将数据渲染到页面,使用post请求获取到表单中用户输入的数据,操作数据库进行修改
7.模板继承
将公共部分放在一个模板
使用模板语言 {% extends "" %} 继承基础模板
模板语言 {% block css(content/js) %} {% endblock %}等等
8.用户管理
8.1用户列表
对于django在models中添加的字段
datetimeField: 使用python提供的 strftime() 进行时间的格式处理
ForeignKey: 外键,关联的表,Django提供了一个组件,通过表的字段直接获取到关联表的字段数据对于封装的选择元组,使用choices字段进行选择,Django提供组件 get字段 display() 方法来进行展示对应的数据
注意:在模板语法中不允许在方法后面添加括号,因为模板语法会自动补充括号
且对时间的处理也不同,如上图所示
8.2用户添加
原始方法(本质)
将form表单的东西依次用视图函数的POST请求依次获取,然后对数据库进行操作,重复的代码量比较的多
验证数据是否为空,进行判断校验,不舍大型的开发工作
关联的数据需要手动获取再进行关联
Django组件
Form组件
1.views.py视图函数中
# 创建form表单,引入Django提供的form
classMyForm(form):
user=forms.CharField(widget=forms.Input) # widget是Django提供的插件,可以将这个内容再html页面中渲染成input输入框等
defuser_add(request):
ifrequest.method=="GET":
form=MyForm() # 实例化form表单
returnrender(request, "user_add.html", {"form": form})
2.在user_add.html中
<form>
{{ form.user }}
</form>
<!== 方法2 循环==>
<form>
{% form form in form %}
{{ form }}
{% endfor %}
</form>
使用form的话会手动写入models.py中的字段,也比较麻烦
ModelForm组件
使用ModelForm直接继承models的orm模型
models.py
views.py
# 创建form表单,引入Django提供的form
classMyForm(form):
# 也可以自定义
classMeta:
model=Userinfo
fields="__all__"
defuser_add(request):
ifrequest.method=="GET":
form=MyForm() # 实例化form表单
returnrender(request, "user_add.html", {"form": form})
创建的表单中:
使用Meta内置类进行继承models中的类,进行表单的构造
在views.py中先实例化表单对象,封装成字典,使用模板语言进行前端页面的数据渲染
使用Django的插件 widget 为表单中的对象添加操作等
这里返回的是元组类型的数据
def__init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# 循环找到所有的插件,添加属性
forname, fieldinself.fields.items():
field.widget.attrs= {"class": "form-control", "placeholder": field.label}
使用Django的ModelForm表单规则进行数据的验证,is_valid()方法等,可以返回clean_data,通过验证后的数据,
验证不通过返回错误信息使用表单的 errors,通过模板语言可以展示在页面上
验证通过后使用 save() ,表单的验证方法后,通过save进行保存到数据库
注意:可以通过在表单中添加验证规则等更多的操作
在表单中,可以关闭浏览器自带的验证方法,使用 novalidate
8.3编辑用户
点击编辑跳转到编辑页面(将编辑行的id进行传递)
提交也得做错误校验
# ModelForm 的子类可接受一个现有的模型实例作为关键字参数 instance ;如果提供了,则 save() 会更新这个实例。如果没有,则 save() 会创建一个对应模型的新实例。
instance属性
8.4删除用户
9.靓号管理
9.1数据库表结构
9.2靓号列表
url, 函数
获取所有靓号
order_by方法对得到的数据排序
9.3新建靓号
函数,url
使用表单 modelform创建表单对象,继承models
使用小组件widget给输入框添加属性等操作
添加校验规则
方式1:在form表单中对mobile字段进行格式等操作的验证(字段+正则)
方式2:(钩子方法)
具体代码写法
9.4编辑靓号
根据id获取编辑的对象
url:num//edit>
视图函数
符合现实的逻辑,在编辑靓号信息时,排除自身以外,可以进行修改
9.5l删除靓号
根据get到的id操作数据库进行删除
9.6搜索手机号
通过filter()方法进行查询,在里面添加数据库的属性
通过字典,在filter(* *dict) 里面查找字典里的数据
通过 mobile_contains进行对手机号的模糊查询,将其放在字典里,返回的时 true或者flase,通过 * *data_dict传递字典参数进行对数据库表的搜索
如果不输入任何值,显示全部
9.7分页
切片:
num_list=PrettyNum.objects.filter(**data_dict).order_by("id")[0:10] # 第一页num_list=PrettyNum.objects.filter(**data_dict).order_by("id")[10:20] # 第二页
计算总的页码数,因为页码数可能除不尽,所以使用韩式divmod()进行在商加一的操作
因为Django带有页面的安全验证,所以得使用 mark_safe()方法将该元素标记成安全
fromdjango.utils.safestringimportmark_safe
page_string=mark_safe("".join(page_str_list))
原理:
# 分页展示数据
# 分页计算出想要展示的数据起始位置等
page=int(request.GET.get("page", 1))
page_size=20
start_data= (page-1) *page_size
end_data=page*page_size
# 计算出总的页码数量
page_total=PrettyNum.objects.all().count() # 得到总共得数据个数all_pages, div=divmod(page_total, page_size)
# 如果有余数,则对商加一
ifdiv:
all_pages+=1
# 只显示前五页和后五页, 但是这样写有bug,页码会出现极值情况下得负数
show_page=5
# 处理极值情况:
# 如果数据库总的页码数小于要显示的
ifall_pages<=2*show_page:
start_page=1
end_page=all_pages
else:
# 数据库数据大于 2 * show_page + 1:
- ifpage<=show_page:
•start_page=1
•end_page=2*show_page
•else:
# 最后一页
- start_page=page-show_page
•end_page=page+show_page
# 页码展示
page_str_list= []
# 上一页
ifpage>1:
prev=f'<li><a href="?page={page-1}" aria-label="Previous"><span aria-hidden="true">«</span></a></li>'
page_str_list.append(prev)
else:
page=1
foriinrange(start_page, end_page+1):
ifi==page:
ele=f' <li class="active"><a href="?page={i}">{i}</a></li>'
else:
ele=f' <li><a href="?page={i}">{i}</a></li>'
page_str_list.append(ele)
# 下一页
ifpage>1:
prev=f'<li><a href="?page={page+1}" aria-label="Next"><span aria-hidden="true">»</span></a></li>'
page_str_list.append(prev)
# 展示到html文档
page_string=mark_safe("".join(page_str_list)) # 转换成字符串
# 发起get请求,获取数据(queryset对象)
num_list=PrettyNum.objects.filter(**data_dict).order_by("id") [start_data:end_data] # 按照级别排序
9.8时间组件
请选择日期
<!DOCTYPE
html>
<html>
<head>
<meta
charset="utf-8"/>
<title>bootstrap-datepicker例子</title>
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no, minimal-ui">
<script
src="https://www.itxst.com/package/jquery-3.5.1/jquery.min.js"></ script>
<script
src="https://www.itxst.com/package/bootstrap-4.5.0/js/bootstrap.min.js"> </script>
<link
href="https://www.itxst.com/package/bootstrap-4.5.0/css/bootstrap.css" rel="stylesheet">
<script
src="https://www.itxst.com/package/bootstrap-datepicker-
1.9.0/js/bootstrap-datepicker.min.js"></script>
<script
src="https://www.itxst.com/package/bootstrap-datepicker-
1.9.0/locales/bootstrap-datepicker.zh-CN.min.js"></script>
<link
href="https://www.itxst.com/package/bootstrap-datepicker-
1.9.0/css/bootstrap-datepicker.min.css"
rel="stylesheet">
</head>
<body
style="padding:10px;">
<div
class="container ">
<input
type="text"
id="inputDate"
class="form-control"placeholder="请选择日期">
</div>
<script>
$("#inputDate").datepicker({
language: 'zh-CN', //语言autoclose: true, //选择后自动关闭
clearBtn: true, //清除按钮
format: "yyyy-mm-dd"//日期格式
});
</script>
</body>
</html>
10.管理员操作
创建管理员表字段
10.1管理员列表
10.2 添加管理员
验证密码:
创建表单:在表单中添加字典确认密码
钩子方法:比较表单post提交的数据cleaned_data的一致性
MD5:加密密码,使用MD5结合django设置的安全匙,随机生成MD5加密,通过对密文进行比较来存储密码数据(值一样生成的密文也一样)
表单:
MD5
importhashlib
fromdjango.confimportsettings
defmd5(data):
# 导入django随机生成的值
obj=hashlib.md5(settings.SECRET_KEY.encode("utf-8")) obj.update(data.encode("utf-8"))
returnobj.hexdigest()
10.3 管理员编辑
创建表单,在表单中添加验证规则
10.4删除和重置密码
创建表单,对密码进行重新修改
获取post传递过来的数据,使用instance更新到数据库
11.用户登录
cookie和session?
保持用户的登录信息
http请求或者https请求,通过浏览器发送的请求:无状态短连接cookie:保存在浏览器中的键值对,发送请求时,自动携带
session:服务器存储,会话等
在浏览器会存储session的键值对
在django中会保存session字段
在登录成功后:
cookie随机字符串
session:用户信息
在每一个需要登录的权限中加入:
# 获取cookie中保存的账号信息,获取到了就进行页面的展示,未获取到就跳转到登录页面info=request.session.get("info")
print(info)
ifnotinfo:
returnredirect("/login/")
但是在每一个需要登录才能查看的功能,很麻烦
12.Django的中间件(类)
定义中间件(类)
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.M1.M1', # 中间件的注册
]
在这个中间件中继承
中间件定义
fromdjango.httpimportHttpResponse
fromdjango.utils.deprecationimportMiddlewareMixin
# 定义中间件的类
classM1(MiddlewareMixin):
# 请求
defprocess_request(self, request):
print("m1来了")
# 可以是一个页面,可以是重定向地址
# 返回请求
defprocess_response(self, request, response):
print("m1走了")
returnHttpResponse("无权访问")
对登录中间件进行操作
classAuthMIddleWare(MiddlewareMixin):
defprocess_request(self, request):
# 排除不需要登录就能访问的页面
ifrequest.path_info=="/login/":
return
# 获取cookie中的账号
info=request.session.get("info")
# 如果拿到
ifinfo:
return# 返货None
# 反之
print("未登录")
returnredirect("/login/")
注销登录:清除session
将用户的名字显示在页面上:
获取在session中保存的用户账号名,发起请求后会将账号名等保存在session中,以字典的形式
使用request.session.get到字典中的账号名,使用模板语言进行展示
13.图片验证码
defimgcode(request):
"""
实现图片验证码
:param request:
:return:
"""
img, code=check_code()
# with open('code.png','wb') as f:
# img.save(f, format='png')
# 3. 写入内存(Python3)
fromioimportBytesIO
# 将生成的图片验证码添加到session中
request.session["image_code"] =code
request.session.set_expiry(60) # 设置图片验证码的时长,超过时长就无效了
stream=BytesIO()
img.save(stream, 'png')
stream.getvalue()
returnHttpResponse(stream.getvalue())
14.ajax请求
get, post请求:页面会刷新(url和表单的形式提交)
除此之外:基于Ajax向后台发送请求
依赖jQuery
编写Ajax代码
$.ajax({
url:"发送的地址",
type:post, // 请求类型
data:{ // 请求参数
n1:123,
n2:456,
},
// 获取成功后,返回数据内容
success:function(res){
console.log(res);
}
})
14.1 get请求
<scripttype="text/javascript">
// 使用jquery的刀乐符进行匹配
$("#btn").click(function (){
clickme();
})
functionclickme(){
$.ajax({
url: "/task/ajax/",
type: "get",
data: {
n1: 123,
n2: 456
},
success:function (res) {
console.log(res)
}
})
{#console.log("dianjile ")#}
}
deftask_list(request):
returnrender(request, "task_list.html")
deftask_ajax(request):
print(request.GET)
returnJsonResponse("成功")
14.2 post请求
如果发起post请求:会存在csrf安全验证,可以在后端中进行关闭
<scripttype="text/javascript">
$("#btn").click(function (){
clickme();
})
functionclickme(){
$.ajax({
url: "/task/ajax/",
type: "post",
data: {
n1: 123,
n2: 456
},
success:function (res) {
console.log(res)
}
})
{#console.log("dianjile ")#}
}
</script>
关闭csrf验证
fromdjango.views.decorators.csrfimportcsrf_exempt @csrf_exempt
deftask_ajax(request):
print(request.POST)
returnHttpResponse("成功")
任务需求:
表单:ajax提交请求
15.Ajax订单
15.1.表结构创建
class Order(models.Model):
"""订单"""
oid = models.CharField(verbose_name="订单号", max_length=64)
# order = models.IntegerField(verbose_name="订单号", max_length=255), title = models.CharField(verbose_name="商品名", max_length=255), price = models.IntegerField(verbose_name="价格")
status_choices = (
(1, "待支付"),
(2, "已支付")
)
status = models.SmallIntegerField(verbose_name="状态", choices=status_choices)
admin = models.ForeignKey(Admin, verbose_name="管理员", on_delete=models.CASCADE)
新建订单:点击订单按钮,弹出对话框进行添加信息
16.画图
defchart_bar(request):
"""构造柱状图的数据"""
l1=Orders.objects.all() # queryset 列表数据
# 遍历列表,获取关联的数据库的admin的值
fordinl1:
legend=d.admin.username
print(legend)
# print()
legend= ["销量"] # 图列
x_axis= ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子'] # x轴 series= [
{
"name": '销量',
"type": 'bar',
"data": [5, 20, 36, 10, 10, 20]
}
]
# 获取成功返回数据
json_data= {
"status": True,
"legend": legend,
"x_axis": x_axis,
"series": series
}
# json序列化,返回json数据供前端使用
returnJsonResponse(json_data)
<scriptsrc="{% static 'echarts.min.js' %}"></script> <scripttype="text/javascript">
$(function () {
initbar();
})
functioninitbar() {
// 基于准备好的dom,初始化echarts实例
varmyChart=echarts.init(document.getElementById('pic1'));
// 指定图表的配置项和数据
varoption= {
title: {
text: '订单管理柱状图'
},
tooltip: {},
legend: {
data: []
},
xAxis: {
data: []
},
yAxis: {},
series: []
};
// 获取后台的数据
$.ajax({
url: "/chart/bar/",
type: "GET",
dataType: "JSON",
success: function (res) {
// 判断成功
if (res.status){
console.log(res);
option.legend.data=res.legend// 图列 option.series=res.series[0] // 数据 option.xAxis.data=res.x_axis//
// 使用刚指定的配置项和数据显示图表。
// 获取成功则开始绘图
myChart.setOption(option);
}
}
})
}
</script>
17.上传文件
17.1文件的基本操作
<formmethod="post"enctype="multipart/form-data">
enctype="multipart/form-data"
添加上述属性:获取到文件及文件的内容,后台通过 request.FILES进行数据的获取
不加该属性,就值获取到文件的名字
批量上传数据