Django学习
1、项目创建
pycharm:
import pymysql
pymysql.install_as_MySQLdb()
2、默认项目介绍
djangostudy
manage.py 【项目的管理,启动项目、创建app、数据管理】【不要动】
djangostudy
__init__.py
settings.py 【项目配置】 【**常常操作**】
urls.py 【url和函数的对应关系】【**常常操作**】
asgi.py 【接收网络请求】【不要动】
wsgi.py 【接收网络请求】【不要动】
3、app的创建和说明
说明
-项目
-app,用户管理【表结构、函数、html模板、css】
-app,订单管理【表结构、函数、html模板、css】
-app,后台管理【表结构、函数、html模板、css】
-app,网站【表结构、函数、html模板、css】
-app,api【表结构、函数、html模板、css】
。。。
创建:
app01
__init__.py
admin.py 【固定,不用动】Django默认提供了admin后台管理
apps.py 【固定,不用动】app启动类
migrations 【固定,不用动】数据库变更记录
__init__.py
models.py 【**重要**】对数据库操作
tests.py 【固定,不用动】单元测试
views.py 【**重要**】,函数
4、启动运行Django
4.1确保app已注册
4.2 编写URL和视图函数的对应关系【urls.py】
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Z8jJ9pAL-1654077355201)(https://gitee.com/cool-dada/blog_img/raw/master/tree/master/img_markdown/202206011745585.png)]
4.3编写视图函数【views.py】
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iR3AT8Nb-1654077355201)(https://gitee.com/cool-dada/blog_img/raw/master/tree/master/img_markdown/202206011745336.png)]
4.4启动Django项目
4.5、templates模板
4.6、静态文件
在开发过程中一般将 图片、css、js都会当做静态文件处理
static文件夹下存放静态文件
插件使用+引入
{% static ‘路径’ %}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XXMKjNKJ-1654077355204)(https://gitee.com/cool-dada/blog_img/raw/master/tree/master/img_markdown/202206011746076.png)]
5、模板语法
本质上:在html中写一些占位符,由数据对这些占位符进行替换和处理。
views
def tpl(request):
name = '李锦彪'
roles = ['李锦彪', '黄欣宇', '锦欣宇']
user_info = {'name': '李锦彪', 'salary': 26000, 'role': 'ceo'}
data_list = [
{'name': '李锦彪', 'salary': 26000, 'role': 'ceo'},
{'name': '李锦彪', 'salary': 26000, 'role': 'ceo'},
{'name': '李锦彪', 'salary': 26000, 'role': 'ceo'}
]
return render(request,
'tpl.html',
{
'n1': name,
'n2': roles,
'n3': user_info,
'n4': data_list,
}
)
html
{# 获取传入的值 #}
<p>{{ n1 }}</p>
============================================
{# 获取传入的列表值 #}
{# 一个一个拿 #}
<p>{{ n2.0 }}</p>
<p>{{ n2.1 }}</p>
<p>{{ n2.2 }}</p>
{# 循环拿 #}
<div>
{% for item in n2 %}
<p>{{ item }}</p>
{% endfor %}
</div>
<hr/> {# 加条线 #}
==============================================
{# 获取字典的值 #}
{{ n3 }}
{# 根据字典的键获取值 #}
{{ n3.name }}
{{ n3.salary }}
{{ n3.role }}
{# 循环获取 #}
<div>
{# 第一种 #}
{# {% for item in n3 %}#}
{# <li>{{ item }}</li>#}
{# {% endfor %}#}
{# 第二种 #}
{% for k, v in n3.items %}
<li>{{ k }}={{ v }}</li>
{% endfor %}
</div>
<hr>
===============================================
{% if n1 == '李锦彪' %}
<h1>哈哈哈哈</h1>
{% else %}
<h1>黑恶hi诶嘿二哈IE</h1>
{% endif %}
视图函数的render内部:
- 读取含有模板语法的html文件
- 内部进行渲染(模板语法执行并替换数据),最终得到只包含html标签的字符串
- 将渲染(替换)完成的字符串返还给用户浏览器
案例:伪联通新闻中心
**第一步:**urls.py中创建路径
第二步:views.py中创建函数news
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tvSZ7kfc-1654077355206)(https://gitee.com/cool-dada/blog_img/raw/master/tree/master/img_markdown/202206011746481.png)]
第三步:编写html文件
<h1>联通新闻中心</h1>
<ul>
{% for item in news_list %}
<li>{{ item.news_title }}</li>
{% endfor %}
</ul>
6、请求和响应
关于重定向:当前的页面请求访问其他的页面。其他的页面不同意并且会返回一个值,告诉当前的页面去访问这个值
print(request.method)
print(request.GET)
print(request.POST)
return redirect('https://www.baidu.com')
案例:用户登录
问题:安全机制校验
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cKuj760e-1654077355207)(https://gitee.com/cool-dada/blog_img/raw/master/tree/master/img_markdown/202206011752654.png)]
解决办法:form表单里加 {% csrf_token %}
第一步:views.py
def login(request):
if request.method == 'GET':
return render(request, 'login.html')
usr = request.POST.get('username')
pwd = request.POST.get('password')
if usr == '15751083927' and pwd == '123':
return redirect('https://www.baidu.com')
else:
return render(request, 'login.html', {'error_msg': '登录失败'})
第二步:html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>用户登录</h1>
<form action="/login/" method="post">
{% csrf_token %}
<input type="text" name="username" placeholder="用户名">
<input type="password" name="password" placeholder="密码">
<input type="submit">
<span style="color: red">{{ error_msg }}</span>
</form>
</body>
</html>
7、数据库操作
Django开发操作数据库,内部提供了orm框架
7.1、安装mysqlclient
7.2、orm创建数据库
orm可以帮助我们做两件事:
- 创建、修改、删除数据库中的表(不用写SQL语句)(无法创建数据库)
- 操作表中的数据(不用写SQL语句)
1、创建数据库
2、Django连接数据库
在setting.py文件中,进行配置和修改
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'ljb',
'USER': 'root',
'PASSWORD': '187365',
'HOST': '127.0.0.1',
'PORT': 3306,
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-18oVfvWK-1654077355208)(https://gitee.com/cool-dada/blog_img/raw/master/tree/master/img_markdown/202206011746040.png)]
3、Django操作表
3.1、创建表
在models.py文件中
class Userinfo(models.Model):
name = models.CharField(max_length=32)
password = models.CharField(max_length=64)
age = models.IntegerField()
==相当于
3.2、执行命令
在终端执行:
python manage.py makemigrations
python manage.py migrate
注意:app先注册(settings)
新增列的时候,由于已经在列中可能已有数据,所以新增列必须要指定新增列对应的数据
age = models.IntegerField(default=2)
age = models.IntegerField(null=True, blank=True)
以后在开发中如果想要操作对表结构进行调整
3.3、操作表中的数据
在views.py中
def orm(request):
from app01 import models
models.Userinfo.objects.filter(name='黄欣宇').update(age=28)
return HttpResponse('成功!')
案例:用户管理
1.、展示用户列表
def info_list(request):
from app01.models import Userinfo
data_list = Userinfo.objects.all()
print(data_list)
return render(request, 'info_list.html', {'data_list': data_list})
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>info_list</h1>
<table border="1">
<thead>
<tr>
<th>ID</th>
<th>姓名</th>
<th>性别</th>
<th>年龄</th>
</tr>
</thead>
<tbody>
{% for obj in data_list %}
<tr>
<td>{{ obj.id }}</td>
<td>{{ obj.name }}</td>
<td>{{ obj.password }}</td>
<td>{{ obj.age }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</body>
</html>
2、添加用户
- url
- 函数
- get ,看到页面,输入内容
- post,提交->写入到数据库
def info_add(request):
if request.method == "GET":
return render(request, 'info_add.html')
user = request.POST.get("user")
pwd = request.POST.get("pwd")
age = request.POST.get("age")
from app01.models import Userinfo
Userinfo.objects.create(name=user, password=pwd, age=age)
return redirect('/info/list')
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>添加用户</h1>
<form action="" method="post">
{% csrf_token %}
<input type="text" name="user" placeholder="用户名">
<input type="password" name="pwd" placeholder="密码">
<input type="text" name="age" placeholder="年龄">
<input type="submit">
</form>
</body>
</html>
3、删除用户
def info_delete(request):
nid = request.GET.get('nid')
from app01.models import Userinfo
Userinfo.objects.filter(id=nid).delete()
return redirect('/info/list')
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>info_list</h1>
<a href="/info/add">添加</a>
<table border="1">
<thead>
<tr>
<th>ID</th>
<th>姓名</th>
<th>性别</th>
<th>年龄</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for obj in data_list %}
<tr>
<td>{{ obj.id }}</td>
<td>{{ obj.name }}</td>
<td>{{ obj.password }}</td>
<td>{{ obj.age }}</td>
<td><a href="/info/delete/?nid={{ obj.id }}">删除</a></td>
</tr>
{% endfor %}
</tbody>
</table>
</body>
</html>
8、员工管理系统
8.1、创建项目
删除templates文件夹,删除
8.2、创建app,终端运行 python manage.py startapp xxx
8.3、注册app
8.4、设计表结构
from django.db import models
class Department(models.Model):
"""部门表"""
title = models.CharField(verbose_name='标题', max_length=32)
class Userinfo(models.Model):
"""员工表"""
name = models.CharField(verbose_name='姓名', max_length=32)
password = models.CharField(verbose_name='密码', max_length=64)
age = models.IntegerField(verbose_name='密码')
sex_choice = (
(True, '男'),
(False, '女')
)
sex = models.BooleanField(verbose_name='性别', choices=sex_choice)
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",
null=True, blank=True, on_delete=models.CASCADE)
8.5、配置数据库
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'ljb',
'USER': 'root',
'PASSWORD': '187365',
'HOST': '127.0.0.1',
'PORT': 3306,
}
}
8.6、生成表
python manage.py makemigrations
python manage.py migrate
注意:
报错:
解决:
原因:PyMySQL 是在 Python3.x 版本中用于连接 MySQL 服务器的一个库,Python2中则使用mysqldb。 MySQLdb并不支持Python3.
8.7、创建静态文件和模板文件
8.8、部门管理
8.8.1、urls
urlpatterns = [
path('depart/list/', views.depart_list),
path('depart/delete/', views.depart_delete),
path('depart/<int:nid>/edit/', views.depart_edit),
]
8.8.2、views
重定向:要引入 redirect
from django.shortcuts import render, redirect
from Employee import models
def depart_list(request):
if request.method == "GET":
data_list = models.Department.objects.all()
return render(request, 'depart_list.html', {'data_list': data_list})
data_department = request.POST.get('department')
models.Department.objects.create(title=data_department)
return redirect('/depart/list/')
def depart_delete(request):
"""删除部门"""
nid = request.GET.get('nid')
models.Department.objects.filter(id=nid).delete()
return redirect('/depart/list/')
def depart_edit(request, nid):
"""编辑部门"""
if request.method == "GET":
row_data = models.Department.objects.filter(id=nid).first()
return render(request, 'depart_edit.html', {'row_data': row_data})
title = request.POST.get('department')
models.Department.objects.filter(id=nid).update(title=title)
return redirect('/depart/list/')
9、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-dist/css/bootstrap.css' %}">
{% block css %}{% endblock %}
</head>
<body>
<div>
<div class="container">
{% block content %}{% endblock %}
</div>
</div>
</body>
<script src="{% static 'js/jquery-3.6.0.js' %}"></script>
<script src="{% static 'plugins/bootstrap-3.4.1-dist/js/bootstrap.js' %}"></script>
{% block js %}{% endblock %}
</html>
继承母版:
{% extends 'layout.html' %}
{% block css %}
{% endblock %}
<link rel="stylesheet" href="{% static 'plugins/bootstrap-3.4.1-dist/css/bootstrap.css' %}">
<body>
{% block content %}
{% endblock %}
</body>
<script src="{% static 'js/jquery-3.6.0.js' %}"></script>
<script src="{% static 'plugins/bootstrap-3.4.1-dist/js/bootstrap.js' %}"></script>
{% block js %}
{% endblock %}
10、用户管理
Django中对于一些选项的元组存元组形式获取元组中的值:对象.get_属性_display()
例:
sex_choice = (
(0, '男'),
(1, '女')
)
sex = models.SmallIntegerField(verbose_name='性别', choices=sex_choice)
取法:
obj.get_sex_display()
html中
外键获取另一个表的值
{% for obj in user_lists %}
<tr>
<td>{{ obj.id }}</td>
<td>{{ obj.name }}</td>
<td>{{ obj.password }}</td>
<td>{{ obj.get_sex_display }}</td>
<td>{{ obj.age }}</td>
<td>{{ obj.depart.title }}</td> # 外键获取另一个表的值
<td>{{ obj.account }}</td>
<td>{{ obj.create_time }}</td>
</tr>
{% endfor %}
10.2、用户列表
时间输出格式
{% for obj in user_lists %}
<tr>
<td>{{ obj.id }}</td>
<td>{{ obj.name }}</td>
<td>{{ obj.password }}</td>
<td>{{ obj.get_sex_display }}</td>
<td>{{ obj.age }}</td>
<td>{{ obj.depart.title }}</td>
<td>{{ obj.account }}</td>
<td>{{ obj.create_time|date:"Y-m-d" }}</td> # 时间输出格式
<td>
{# 编辑#}
<a href="/user/{{ obj.id }}/edit/" class="btn btn-primary btn-xs">
<span class="glyphicon glyphicon-cog"></span>
</a>
{# 删除#}
<a href="/user/delete/?nid={{ obj.id }}" class="btn btn-danger btn-xs">
<span class="glyphicon glyphicon-trash"></span>
</a>
</td>
</tr>
{% endfor %}
10.3、添加用户
- 用户提交数据没有校验
- 错误,页面应该有提示
- 页面上每一个字段都需要重新写
- 关联的数据,手动去获取并展示在页面
- Django组件
- Form组件(小简便)
- ModelForm组件(最简便)
10.3.1、初识Form
1、views.py
class MyForm(Form):
user = forms.CharFiled(widget=forms.Input)
pwd = forms.CharFiled(widget=forms.Input)
email = forms.CharFiled(widget=forms.Input)
def user_list(request):
if request.method == "GET":
form = MyForm()
return render(request, 'user_list.html', {'form': form})
2、user_add.html
<form method="post">
{{form.user}} # 自动生成html input标签
{{form.pwd}}
{{form.email}}
# <input type="text" class="form-control" name="name" placeholder="姓名">
</form>
或:
<form method="post">
{% for field in form %}
{{ field }}
{% endfor %}
</form>
10.3.2、ModelForm(最简便)
1、models.py
class Userinfo(models.Model):
"""员工表"""
name = models.CharField(verbose_name='姓名', max_length=32)
password = models.CharField(verbose_name='密码', max_length=64)
age = models.IntegerField(verbose_name='密码')
sex_choice = (
(0, '男'),
(1, '女')
)
sex = models.SmallIntegerField(verbose_name='性别', choices=sex_choice)
account = models.DecimalField(verbose_name='账户余额', max_digits=10, decimal_places=2, default=0)
create_time = models.DateField(verbose_name='入职时间')
depart = models.ForeignKey(to="Department", to_field="id", on_delete=models.CASCADE)
2、views.py
class MyForm(ModelForm):
class Meta:
model = UserInfo
fields = ["name", "password", "age"]
def user_list(request):
if request.method == "GET":
form = MyForm()
return render(request, 'user_list.html', {'form': form})
10.3.3、添加用户
1、views.py
from django import forms
class UserModelForm(forms.ModelForm):
name = forms.CharField(min_length=2, max_length=12, label="用户名")
class Meta:
model = models.Userinfo
fields = ["name", "password", "age", "sex", "account", "depart", "create_time"]
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for name, field in self.fields.items():
field.widget.attrs = {"class": "form-control", "placeholder": field.label}
def user_add(request):
"""添加用户 ModelForm版本"""
if request.method == "GET":
form = UserModelForm()
return render(request, 'user_modelform.html', {"form": form})
form = UserModelForm(data=request.POST)
if form.is_valid():
form.save()
return redirect('/user/list/')
return render(request, 'user_modelform.html', {"form": form})
2、html
<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>
10.4、编辑用户
-
点击编辑,跳转到编辑页面(将编辑的id携带过去) -
编辑页面(默认数据,根据id获取并设置到页面中) -
提交:
def user_edit(request, nid):
"""编辑用户"""
row_object = models.Userinfo.objects.get(id=nid)
if request.method == 'GET':
form = UserModelForm(instance=row_object)
return render(request, 'user_edit.html', {'form': form})
form = UserModelForm(data=request.POST, instance=row_object)
if form.is_valid():
form.save()
return redirect('/user/list/')
return render(request, 'user_edit.html', {'form': form})
html和添加一样
11、总结-1
ModelForm 针对数据库中的某个表
Form
12、 靓号管理
搜索
data_dict = {'id': 12}
row_data = models.Mobile.objects.filter(**data_dict)
models.Mobile.objects.filter(id=12)
models.Mobile.objects.filter(id__gt=12)
models.Mobile.objects.filter(id__gte=12)
models.Mobile.objects.filter(id__lt=12)
models.Mobile.objects.filter(id__lte=12)
data_dict = {'id__lte': 12}
row_data = models.Mobile.objects.filter(**data_dict)
models.Mobile.objects.filter(mobile__startwith='12')
models.Mobile.objects.filter(mobile__endwith='12')
models.Mobile.objects.filter(mobile__contains='12')
models.Mobile.objects.filter(mobile='12')
分页
page = int(request.GET.get('page', 1))
page_size = 8
start = (page - 1) * page_size
end = page * page_size
data_count = models.Mobile.objects.filter(**data_dict).count()
total_page_count, div = divmod(data_count, page_size)
if div:
total_page_count += 1
plus = 2
if total_page_count <= 2 * plus + 1:
start_page = 1
end_page = total_page_count
else:
if page <= plus:
start_page = 1
end_page = 2 * plus + 1
else:
if (page + plus) > total_page_count:
start_page = total_page_count - 2 * plus
end_page = total_page_count
else:
start_page = page - plus
end_page = page + plus
page_str_list = []
if page > 1:
prev = '<li><a href="?page={}" ' \
'aria-label="Previous"><span aria-hidden="true">?</span></a></li>'.format(page-1)
else:
prev = '<li><a href="?page={}" ' \
'aria-label="Previous"><span aria-hidden="true">?</span></a></li>'.format(page)
page_str_list.append(prev)
for i in range(start_page, end_page+1):
if i == page:
ele = '<li class="active"><a href="?page={}">{}</a></li>'.format(i, i)
else:
ele = '<li><a href="?page={}">{}</a></li>'.format(i, i)
page_str_list.append(ele)
"""
<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>
"""
if page < total_page_count:
next_page = '<li><a href="?page={}" aria-label="Next">' \
'<span aria-hidden="true">?</span></a></li>'.format(page+1)
else:
next_page = '<li><a href="?page={}" aria-label="Next">' \
'<span aria-hidden="true">?</span></a></li>'.format(total_page_count)
page_str_list.append(next_page)
page_string = mark_safe("".join(page_str_list))
data_list = models.Mobile.objects.filter(**data_dict).order_by('level')[start:end]
13、管理员操作
admin.py
from django.shortcuts import render, redirect
from Employee import models
from Employee.utils.form import AdminModel, AdminEditModel
from Employee.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
data_list = models.Admin.objects.filter(**data_dict)
queryset_object = Pagination(request, data_list)
dic_context = {
"data_list": queryset_object.page_queryset,
"page_string": queryset_object.html(),
"search_data": search_data,
}
if search_data and not queryset_object.page_queryset:
dic_context.update({'error': '对不起,号码不存在'})
return render(request, 'mobile_list.html', dic_context)
return render(request, 'admin_list.html', dic_context)
def admin_add(request):
"""添加管理员"""
title = '新建管理员'
if request.method == 'GET':
form = AdminModel()
dic_context = {
'form': form,
'title': title,
}
return render(request, 'add.html', dic_context)
form = AdminModel(data=request.POST)
if form.is_valid():
form.save()
return redirect('/admin/list/')
dic_context = {
'form': form,
'title': title,
}
return render(request, 'add.html', dic_context)
def admin_edit(request, nid):
"""编辑管理员"""
row_data = models.Admin.objects.filter(id=nid).first()
if not row_data:
return redirect('/admin/list/')
title = '修改密码'
if request.method == "GET":
form = AdminEditModel(instance=row_data, pwd=row_data.password)
username = row_data.username
return render(request, "add.html", {'form': form, 'title': title, 'username': username, 'user_name': '用户名:'})
form = AdminEditModel(instance=row_data, data=request.POST, pwd=row_data.password)
if form.is_valid():
form.save()
return redirect('/admin/list/')
return render(request, "add.html", {'form': form, 'title': title})
def admin_delete(request):
nid = request.GET.get('nid')
models.Admin.objects.filter(id=nid).delete()
return redirect('/admin/list/')
form.py
class AdminModel(BootStrapModelForm):
confirm_password = forms.CharField(
label="确认密码",
widget=forms.PasswordInput
)
class Meta:
model = models.Admin
fields = ["username", "password", "confirm_password"]
widgets = {
'password': forms.PasswordInput
}
def clean_password(self):
password = self.cleaned_data.get('password')
return md5(password)
def clean_confirm_password(self):
password = self.cleaned_data.get('password')
confirm_password = self.cleaned_data.get('confirm_password')
if password != md5(confirm_password):
raise ValidationError('密码不一致,请重新输入!')
return confirm_password
class AdminEditModel(AdminModel):
edit_password = forms.CharField(label='新密码', widget=forms.PasswordInput)
class Meta:
model = models.Admin
fields = ["password", 'edit_password', "confirm_password"]
widgets = {
'password': forms.PasswordInput
}
def clean_password(self):
password = self.cleaned_data.get('password')
if self.pwd != md5(password):
raise ValidationError('密码输入错误')
return md5(password)
def clean_edit_password(self):
edit_password = self.cleaned_data.get('edit_password')
return md5(edit_password)
def clean_confirm_password(self):
edit_password = self.cleaned_data.get('edit_password')
confirm_password = self.cleaned_data.get('confirm_password')
if edit_password != md5(confirm_password):
raise ValidationError('密码不一致,请重新输入!')
return confirm_password
def __init__(self, pwd, *args, **kwargs):
super().__init__(*args, **kwargs)
for name, field in self.fields.items():
if field.widget.attrs:
field.widget.attrs["class"] = "form-control"
field.widget.attrs["placeholder"] = field.label
else:
field.widget.attrs = {"class": "form-control", "placeholder": field.label}
self.pwd = pwd
14、用户登录
什么是cookie和session?
http、https
session存储在数据库或Redis或文件
14.1、session登录
在其他需要登录才能访问的页面中,都需要加入:
def index(request):
info = request.session.get('info')
if not info:
return redirect('/login/')
......
目标:在所有视图前面加上 上面判断
14.2、Django的中间件
中间件存方在 django_session 数据库中
from django.utils.deprecation import MiddlewareMixin
class M1(MiddlewareMixin):
"""中间件1"""
def process_request(self, request):
print('m1, 进来了')
def process_response(self, request, response):
print('m1.走了')
return response
class M2(MiddlewareMixin):
"""中间件2"""
def process_request(self, request):
print('m2, 进来了')
def process_response(self, request, response):
print('m2.走了')
return response
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-I6nggq39-1654077355213)(https://gitee.com/cool-dada/blog_img/raw/master/tree/master/img_markdown/202206011747008.png)]
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',
'Employee.middleware.auth.M1',
'Employee.middleware.auth.M2',
]
- 在中间件中的process_request()方法
14.3、编写登录中间件
from django.shortcuts import redirect
from django.utils.deprecation import MiddlewareMixin
class AuthMiddlewareMixin(MiddlewareMixin):
"""登录"""
def process_request(self, request):
if request.path_info == '/login/':
return
info_dict = request.session.get('info')
if info_dict:
return
return redirect('/login/')
14.4、注销
def logout(request):
"""注销"""
request.session.clear()
return redirect('/login/')
14.5、模板登录信息
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-imF7gHiL-1654077355213)(https://gitee.com/cool-dada/blog_img/raw/master/tree/master/img_markdown/202206011747603.png)]
14.5、图片验证码
5.1、生成图片
pip install pillow
5.2、函数
from PIL import Image, ImageDraw, ImageFont, ImageFilter
import random
def check_code(width=100, height=32, char_length=5, font_file=r'Employee/static/plugins/font-text/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))
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(30):
draw.point([random.randint(0, width), random.randint(0, height)], fill=rndColor())
for i in range(30):
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(3):
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)
5.3、urls路径
path('image/code/', account.image_code),
5.4、视图
BytesIO介绍:https://blog.csdn.net/Victor2code/article/details/105637945
def image_code(request):
"""生成图片验证码"""
img, code_str = check_code()
request.session['code_str'] = code_str
request.session.set_expiry(60)
from io import BytesIO
stream = BytesIO()
img.save(stream, 'png')
return HttpResponse(stream.getvalue())
5.5、前端
{# 验证码 #}
<div class="checkImg">
<label>图片验证码</label><br>
{{ form.code }}
<img style="width: 100px;height: 32px;border-radius: 6px;" src="/image/code/" alt="">
<span style="width: 130px;height: 32px;position: absolute;margin-left: -240px;margin-top: 30px">
{{ form.code.errors.0 }}
</span>
</div>
14.6、完整的登录
6.1 urls
path('login/', account.login),
path('logout/', account.logout),
path('image/code/', account.image_code),
6.2 视图
from django.shortcuts import render, redirect, HttpResponse
from django import forms
from Employee import models
from Employee.utils.createImg import check_code
from Employee.utils.encrypt import md5
class LoginForm(forms.Form):
username = forms.CharField(label='用户名',
widget=forms.TextInput,
required=True,
)
password = forms.CharField(label='密码', widget=forms.PasswordInput, required=True)
code = forms.CharField(label='验证码', widget=forms.TextInput, required=True)
def clean_password(self):
password = self.cleaned_data.get('password')
return md5(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():
user_input_code = form.cleaned_data.pop('code')
auth_image_code = request.session.get('code_str', '')
if auth_image_code.upper() != user_input_code.upper():
form.add_error('code', '验证码错误')
return render(request, 'login.html', {'form': form})
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})
request.session['info'] = {'id': admin_object.id, 'username': admin_object.username}
request.session.set_expiry(60 * 60 * 24 * 7)
return redirect('/admin/list/')
return render(request, 'login.html', {'form': form})
def logout(request):
"""注销"""
request.session.clear()
return redirect('/login/')
def image_code(request):
"""生成图片验证码"""
img, code_str = check_code()
request.session['code_str'] = code_str
request.session.set_expiry(60)
from io import BytesIO
stream = BytesIO()
img.save(stream, 'png')
return HttpResponse(stream.getvalue())
6.3、页面
{% load static%}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>login</title>
<link rel="stylesheet" href="{% static 'plugins/bootstrap-3.4.1-dist/css/bootstrap.css' %}">
<style>
* {
margin: 0;
padding: 0;
}
body {
display: flex;
align-items: center;
justify-content: center;
background: url('../static/img/A-黑.jpg') no-repeat 0px 0px;
height: 100%;
}
#loginDiv {
width: 400px;
display: flex;
justify-content: center;
align-items: center;
height: 400px;
margin-top: 100px;
background-color: rgba(75, 81, 95, 0.3);
box-shadow: 7px 7px 17px rgba(52, 56, 66, 0.5);
border-radius: 250px;
}
label {
margin-top: 30px;
margin-left: 20px;
color: azure;
}
span{
color: red;
margin-top: 55px;
margin-left: -140px;
position: absolute
}
input {
margin-left: 15px;
border-radius: 5px;
border-style: hidden;
height: 30px;
width: 140px;
background-color: rgba(216, 191, 216, 0.5);
outline: none;
color: #f0edf3;
padding-left: 10px;
}
.checkImg{
position: absolute;
margin-top: -5px;
}
.checkInput::placeholder {
color: rgba(255, 255, 255, 0.93);
opacity: 0.6;
}
.button {
border-color: cornsilk;
background-color: rgba(100, 149, 237, .7);
color: aliceblue;
border-style: hidden;
border-radius: 5px;
width: 100px;
height: 31px;
font-size: 16px;
margin-top: 20px;
}
</style>
<style type="text/css">
input::-ms-input-placeholder{text-align: center;}
input::-webkit-input-placeholder{text-align: center;}
</style>
</head>
<body>
<div id="loginDiv">
<form action="" id="form" method="post" novalidate>
{% csrf_token %}
<h1 style="text-align: center;color: aliceblue;">用户登录</h1>
<label>用户名: </label>
{{ form.username }}
<span>{{ form.username.errors.0 }}</span>
<br>
<label>密   码:</label>
{{ form.password }}
<span>{{ form.password.errors.0 }}</span>
{# 验证码 #}
<div class="checkImg">
<label>图片验证码</label><br>
{{ form.code }}
<img style="width: 100px;height: 32px;border-radius: 6px;" src="/image/code/" alt="">
<span style="width: 130px;height: 32px;position: absolute;margin-left: -240px;margin-top: 30px">
{{ form.code.errors.0 }}
</span>
</div>
<br><br><br><br>
<div style="text-align: center;margin-top: 30px;">
<input type="submit" class="button" value="登录">
</div>
</form>
</div>
</body>
</html>
15、Ajax
浏览器向网站发送请求时:URL和表单的形式提交
特点:页面刷新
除此之外,基础Ajax向后台请求
$.ajax({
url:"发送得地址",
type:"get",
data:{
n1:123,
n2:456
},
success:function(res){
console.log(res);
}
})
15.1、get请求
{% extends 'layout.html' %}
{% block content %}
<h1>任务管理</h1>
<h3>实例1</h3>
<input type="button" class="btn btn-primary" value="点击" onclick="clickMe()" >
{% endblock %}
{% block js %}
<script type="text/javascript">
function clickMe() {
$.ajax({
url: '/task/ajax/',
type: 'get',
data: {
n1: 123,
n2: 456
},
{# 成功之后,res是返回的值 #}
success: function (res) {
console.log(res)
}
})
}
</script>
{% endblock %}
from django.http import HttpResponse
from django.shortcuts import render
def task_list(request):
"""任务列表"""
return render(request, 'task_list.html')
def task_ajax(request):
print(request.GET)
return HttpResponse('成功')
path('task/list/', task.task_list),
path('task/ajax/', task.task_ajax),
15.2、post请求
from django.http import HttpResponse
from django.shortcuts import render
from django.views.decorators.csrf import csrf_exempt
def task_list(request):
"""任务列表"""
return render(request, 'task_list.html')
@csrf_exempt
def task_ajax(request):
print(request.GET)
print(request.POST)
return HttpResponse('成功')
15.3、关闭绑定事件
{% extends 'layout.html' %}
{% block content %}
<h1>任务管理</h1>
<h3>实例1</h3>
<input type="button" class="btn btn-primary" value="点击" id="btn1" >
{% 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
},
{# 成功之后,res是返回的值 #}
success: function (res) {
console.log(res)
}
})
})
}
</script>
{% endblock %}
15.4、Ajax请求的返回值
一般都会返回json格式
前端:
{% extends 'layout.html' %}
{% block content %}
<h1>任务管理</h1>
<h3>实例1</h3>
<input type="button" id="btn1" class="btn btn-primary" value="点击">
<h3>实例2</h3>
<input type="text" id="txtUser" placeholder="姓名">
<input type="text" id="txtAge" placeholder="年龄">
<input type="button" id="btn2" class="btn btn-primary" value="点击">
<h3>实例3</h3>
<form action="" id="form3">
<input type="text" name="user" placeholder="姓名">
<input type="text" name="age" placeholder="年龄">
<input type="text" name="address" placeholder="地址">
<input type="text" name="email" placeholder="邮箱">
<input type="button" id="btn2" class="btn btn-primary" value="点击">
</form>
{% endblock %}
{% block js %}
<script type="text/javascript">
$(function () {
bindBtn1Event();
bindBtn2Event();
bindBtn3Event();
})
function bindBtn1Event() {
$("#btn1").click(function () {
$.ajax({
url: '/task/ajax/',
type: 'post',
data: {
n1: 123,
n2: 456
},
dataType: 'JSON',
{# 成功之后,res是返回的值 #}
success: function (res) {
console.log(res);
console.log(res.status);
console.log(res.name);
}
})
})
}
function bindBtn2Event() {
$("#btn2").click(function () {
$.ajax({
url: '/task/ajax/',
type: 'post',
data: {
name: $('#txtUser').val(),
age: $('#txtAge').val()
},
dataType: 'JSON',
{# 成功之后,res是返回的值 #}
success: function (res) {
console.log(res);
console.log(res.status);
console.log(res.name);
}
})
})
}
function bindBtn3Event() {
$("#form3").click(function () {
$.ajax({
url: '/task/ajax/',
type: 'post',
data: $('#form3').serialize(),
dataType: 'JSON',
{# 成功之后,res是返回的值 #}
success: function (res) {
console.log(res);
console.log(res.status);
console.log(res.name);
}
})
})
}
</script>
{% endblock %}
后端:
from django.http import HttpResponse, JsonResponse
from django.shortcuts import render
from django.views.decorators.csrf import csrf_exempt
def 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, 'name': '李锦彪'}
return JsonResponse(data_dict)
16、订单
html
{% extends 'layout.html' %}
{% block content %}
<div>
<input type="button" value="新建订单1" class="btn btn-primary" data-toggle="modal" data-target="#myModal">
<input id="btnAdd" type="button" value="新建订单2" class="btn btn-primary">
</div>
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
aria-hidden="true">×</span></button>
<h4 class="modal-title" id="myModalLabel"></h4>
</div>
<div class="modal-body">
<div class="panel-body">
<form id="formAdd">
<div class="clearfix">
{% for field in form %}
<div class="form-group col-xs-6" style="position: relative;margin-bottom: 20px">
<label>{{ field.label }}</label>
{{ field }}
<span class="error-msg"
style="color: red;position: absolute">{{ field.errors.0 }}</span>
</div>
{% endfor %}
</div>
</form>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
<button id="btnSave" type="button" class="btn btn-primary">保存</button>
</div>
</div>
</div>
</div>
<br>
{# 删除对话框 #}
<div class="modal fade" id="deleteModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
<div class="alert alert-danger alert-dismissible fade in" role="alert">
<h4>是否确定删除?</h4>
<p>删除后,所有关联的数据都会被删除!!!</p>
<p style="text-align: right">
<button type="button" class="btn btn-danger" id="confirm-delete">确定</button>
<button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
</p>
</div>
</div>
</div>
<div class="panel panel-default">
<div class="panel-heading">
<span class="glyphicon glyphicon-th-list"></span>
订单列表
</div>
<table class="table table-bordered">
<thead>
<tr>
<th>ID</th>
<th>订单号</th>
<th>商品名</th>
<th>价格</th>
<th>状态</th>
<th>用户</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for obj in queryset %}
<tr uid="{{ obj.id }}">
<td>{{ obj.id }}</td>
<td>{{ obj.oid }}</td>
<td>{{ obj.title }}</td>
<td>{{ obj.price }}</td>
<td>{{ obj.get_status_display }}</td>
<td>{{ obj.admin }}</td>
<td>
{# 编辑#}
<button eid="{{ obj.id }}" class="btn btn-primary btn-xs btn-edit">
<span class="glyphicon glyphicon-cog"></span>
</button>
{# 删除 #}
<button uid="{{ obj.id }}" class="btn btn-danger btn-xs btn-delete">
<span class="glyphicon glyphicon-trash"></span>
</button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<ul class="pagination" style="text-align: center">
{{ page_string }}
</ul>
{% endblock %}
{% block js %}
<script type="text/javascript">
var DELETE_ID;
var EDIT_ID;
$(function () {
bindBtnAdd();
bindBtnSave();
bindBtnDelete();
bindConfirmDelete();
bindBtnEdit();
})
function bindBtnAdd() {
$('#btnAdd').click(function () {
EDIT_ID = undefined;
{# 置空 #}
$('#formAdd')[0].reset();
{# 修改对话框标题 #}
$('.modal-title').text('新建订单')
$('#myModal').modal('show');
});
}
function bindBtnSave() {
$('#btnSave').click(function () {
$('.error-msg').empty();
if (EDIT_ID) {
$.ajax({
url: '/order/edit/' + '?eid=' + EDIT_ID,
type: 'post',
data: $('#formAdd').serialize(),
dataType: 'JSON',
success: function (res) {
if (res.status) {
$('#formAdd')[0].reset();
$('#myModal').modal('hide');
location.reload();
} else {
if (res.tips) {
alert(res.tips)
} else {
$.each(res.error, function (name, data) {
$("#id_" + name).next().text(data[0]);
});
}
}
}
});
} else {
$.ajax({
url: '/order/add/',
type: 'post',
data: $('#formAdd').serialize(),
dataType: 'JSON',
success: function (res) {
if (res.status) {
$('#formAdd')[0].reset();
$('#myModal').modal('hide');
location.reload();
} else {
$.each(res.error, function (name, data) {
$("#id_" + name).next().text(data[0]);
});
}
}
});
}
});
}
function bindBtnDelete() {
$('.btn-delete').click(function () {
$('#deleteModal').modal('show');
DELETE_ID = $(this).attr('uid');
});
}
function bindConfirmDelete() {
$('#confirm-delete').click(function () {
$.ajax({
url: '/order/delete/',
type: 'GET',
data: {
uid: DELETE_ID
},
dataType: 'JSON',
success: function (res) {
if (res.status) {
{#
{#$('.deleteModal').modal('hide');#}
{#
{#$("tr[uid='" + DELETE_ID + "']").remove();#}
{#
{#DELETE_ID = 0;#}
location.reload();
} else {
alert(res.error)
}
}
});
});
}
function bindBtnEdit() {
$('.btn-edit').click(function () {
{# 拿到要编辑的id #}
EDIT_ID = $(this).attr('eid')
{# 发送Ajax 去后端获取当前行的相关内容 #}
$.ajax({
url: '/order/edit/',
type: 'get',
data: {
eid: EDIT_ID,
},
dataType: 'JSON',
success: function (res) {
{# 置空 #}
$('#formAdd')[0].reset();
if (res) {
$.each(res.data, function (key, value) {
$('#id_' + key).val(value);
});
{# 修改对话框标题 #}
$('.modal-title').text('编辑订单')
{# 显示对话框 #}
$('#myModal').modal('show');
} else {
alert(res.error);
}
}
});
});
}
</script>
{% endblock %}
视图
import random
from datetime import datetime
from django.http import JsonResponse
from django.shortcuts import render, redirect
from django.views.decorators.csrf import csrf_exempt
from Employee import models
from Employee.utils.form import OrderModelForm
from Employee.utils.pagination import Pagination
random_oid = datetime.now().strftime('%Y%m%d%H%M%S') + str(random.randint(1000, 9999))
def order_list(request):
form = OrderModelForm()
queryset = models.Order.objects.all()
page_object = Pagination(request, queryset)
dic_context = {
'queryset': page_object.page_queryset,
'page_string': page_object.html(),
'form': form,
}
return render(request, 'order_list.html', dic_context)
@csrf_exempt
def order_add(request):
"""新建订单(Ajax)"""
form = OrderModelForm(request.POST)
if form.is_valid():
form.instance.oid = random_oid
form.instance.admin_id = request.session['info']['id']
form.save()
context = {
'status': True
}
return JsonResponse(context)
return JsonResponse({'status': False, 'error': form.errors})
def order_delete(request):
"""删除订单"""
uid = request.GET.get('uid')
if models.Order.objects.filter(id=uid).exists():
models.Order.objects.filter(id=uid).delete()
return JsonResponse({'status': True})
return JsonResponse({'status': False, 'error': '删除错误,数据不存在'})
@csrf_exempt
def order_edit(request):
if request.method == 'GET':
"""根据id获取订单信息 get 请求"""
eid = request.GET.get('eid')
if models.Order.objects.filter(id=eid).filter():
row_dict = models.Order.objects.filter(id=eid).values('title', 'price', 'status').first()
return JsonResponse({'status': True, 'data': row_dict})
return JsonResponse({'status': False, 'error': '数据不存在'})
"""编辑订单 POST请求"""
eid = request.GET.get('eid')
row_object = models.Order.objects.filter(id=eid).first()
if not models.Order.objects.filter(id=eid).filter():
return JsonResponse({'status': False, 'tips': '数据不存在,请刷新重试'})
form = OrderModelForm(data=request.POST, instance=row_object)
if form.is_valid():
form.save()
return JsonResponse({'status': True})
return JsonResponse({'status': False, 'error': form.errors})
17、文件上传
17.1、基本操作
{# enctype="multipart/form-data" 支持上传文件 #}
<form action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
<input type="text" name="username">
<input type="file" name="avater">
<input type="submit">
</form>
from django.shortcuts import render, HttpResponse
def upload_list(request):
if request.method == 'GET':
return render(request, 'upload_list.html')
file_object = request.FILES.get('avater')
print(file_object.name)
f = open('a1.png', 'wb')
for chunk in file_object.chunks():
f.write(chunk)
f.close()
return HttpResponse('...')
17.2、Excel批量上传
def depart_multi(request):
"""批量添加"""
from django.core.files.uploadedfile import InMemoryUploadedFile
from openpyxl import load_workbook
file_object = request.FILES.get('exc')
wb = load_workbook(file_object)
sheet = wb.worksheets[0]
for row in sheet.iter_rows(min_row=2):
text = row[0].value
if not models.Department.objects.filter(title=text).exists():
models.Department.objects.create(title=text)
return redirect('/depart/list/')
<form method="post" enctype="multipart/form-data" action="/depart/multi/">
{% csrf_token %}
<input type="file" name="exc">
<br>
<input type="submit" value="上传" class="btn-info btn btn-sm">
</form>
17.3、混合数据(form)
提交页面时:用户输入的数据+文件(输入不能为空、报错)。
- form生成的html标签:type=file
- 表单的验证
- form.clean_data 获取数据 + 文件对象
{% extends 'layout.html' %}
{% block content %}
<h1>{{ title }}</h1>
<form method="post" enctype="multipart/form-data" 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>
{% endblock %}
后端:
class UpForm(forms.Form):
name = forms.CharField(label='姓名')
age = forms.IntegerField(label='年龄')
img = forms.FileField(label='头像')
def upload_form(request):
"""获取混合数据"""
title = 'Form上传'
if request.method == "GET":
form = UpForm()
return render(request, 'upload_form.html', {'form': form, 'title': title})
form = UpForm(data=request.POST, files=request.FILES)
if form.is_valid():
img_object = form.cleaned_data.get('img')
db_file_path = os.path.join('static', 'img', img_object.name)
file_path = os.path.join('Employee', db_file_path)
f = open(file_path, 'wb')
for chunk in img_object.chunks():
f.write(chunk)
f.close()
models.Boss.objects.create(
name=form.cleaned_data['name'],
age=form.cleaned_data['age'],
img=db_file_path
)
return redirect('/upload/form/')
return render(request, 'upload_form.html', {'form': form, 'title': title})
注意:就目前而言,所有的静态文件都只能放在static目录
在Django的开发过程中两个特殊的文件夹
- static。存放静态文件
- media:用户上传的数据目录
17.4、启用media,存数据
存储用户传来的数据
在urls.py中进行配置:
from django.conf import settings
from django.urls import path, re_path
from django.views.static import serve
urlpatterns = [
re_path(r'^media/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT}, name='media')
]
在settings.py中进行配置:
import os
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'
media目录所在位置:
在浏览器中直接访问:
后端存储
def upload_form(request):
"""获取混合数据"""
title = 'Form上传'
if request.method == "GET":
form = UpForm()
return render(request, 'upload_form.html', {'form': form, 'title': title})
form = UpForm(data=request.POST, files=request.FILES)
if form.is_valid():
img_object = form.cleaned_data.get('img')
media_path = os.path.join('media', img_object.name)
f = open(media_path, 'wb')
for chunk in img_object.chunks():
f.write(chunk)
f.close()
models.Boss.objects.create(
name=form.cleaned_data['name'],
age=form.cleaned_data['age'],
img=media_path
)
return redirect('/upload/form/')
return render(request, 'upload_form.html', {'form': form, 'title': title})
17.5、混合数据(ModelForm)
models.py
class City(models.Model):
""""城市"""
title = models.CharField(verbose_name='城市', max_length=32)
count = models.IntegerField(verbose_name='人口')
img = models.FileField(verbose_name='logo', max_length=128, upload_to='city/')
定义ModelForm:
class CityModelForm(forms.ModelForm):
class Meta:
model = models.City
fields = '__all__'
视图
def upload_modelform(request):
"""获取混合数据modelform"""
title = 'ModelForm'
if request.method == 'GET':
form = CityModelForm()
queryset = models.City.objects.all()
return render(request, 'upload_modelform.html', {'form': form, 'title': title, 'queryset': queryset})
form = CityModelForm(data=request.POST, files=request.FILES)
if form.is_valid():
form.save()
return redirect('/upload/modelform/')
return render(request, 'upload_modelform.html', {'form': form, 'title': title})
前段
包括显示内容
{% extends 'layout.html' %}
{% block content %}
<h1>{{ title }}</h1>
<form method="post" enctype="multipart/form-data" 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 class="panel panel-default">
<div class="panel-heading">
<span class="glyphicon glyphicon-th-list"></span>
管理员列表
</div>
<table class="table table-bordered">
<thead>
<tr>
<th>ID</th>
<th>城市名</th>
<th>人口</th>
<th>logo</th>
</tr>
</thead>
<tbody>
{% for obj in queryset %}
<tr>
<td>{{ obj.id }}</td>
<td>{{ obj.title }}</td>
<td>{{ obj.count }}</td>
<td>
<img src="/media/{{ obj.img }}" style="height: 100px;width: 100px">
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endblock %}
Django 函数+知识点
Django转义总结:escape、autoescape、safe、mark_safe
https://blog.csdn.net/bbwangj/article/details/79992863
分页 --类
"""
自定义分页组件, 以后想使用这个分页组件,做一下几步
后端:
def mobile_list(request):
1、根据自己的情况去筛选自己的数据
queryset = models.Mobile.objects.all() # 获得所有数据
2,、实例化分页对象
page_object = Pagination(request, queryset)
dic_context = {
'data_list': page_object.page_queryset, # 分完页的数据
'page_string': page_object.html(), # 生成页码
}
return render(request, 'mobile_list.html', dic_context)
前段:
<div class="panel panel-default">
<div class="panel-heading">
<span class="glyphicon glyphicon-th-list"></span>
靓号列表
</div>
<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>
<td>{{ obj.id }}</td>
<td>{{ obj.mobile }}</td>
<td>{{ obj.price }}</td>
<td>{{ obj.get_level_display }}</td>
<td>{{ obj.get_status_display }}</td>
<td>
{# 编辑#}
<a href="/mobile/{{ obj.id }}/edit/" class="btn btn-primary btn-xs">
<span class="glyphicon glyphicon-cog"></span>
</a>
{# 删除#}
<a href="/mobile/{{ obj.id }}/delete/" class="btn btn-danger btn-xs">
<span class="glyphicon glyphicon-trash"></span>
</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<ul class="pagination" style="text-align: center">
{{ page_string }}
</ul>
"""
from django.utils.safestring import mark_safe
import copy
class Pagination(object):
def __init__(self, request, queryset, page_size=8, page_param="page", plus=2):
"""
:param request: 请求的对象
:param queryset: 符合条件的数据
:param page_size: 每页的数量
:param page_param: 在URL中传递的获取分页的参数,例如:/mobile/list/?page=12
:param plus: 导航页码
"""
page = request.GET.get(page_param, "1")
query_dict = copy.deepcopy(request.GET)
query_dict._mutable = True
self.query_dict = query_dict
if page.isdecimal():
page = int(page)
else:
page = 1
self.page = page
self.page_size = page_size
self.page_param = page_param
self.start = (page - 1) * page_size
self.end = page * page_size
self.page_queryset = queryset[self.start:self.end]
data_count = queryset.count()
total_page_count, div = divmod(data_count, self.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:
start_page = 1
end_page = self.total_page_count
else:
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:
start_page = self.page - self.plus
end_page = self.page + self.plus
page_str_list = []
self.query_dict.setlist(self.page_param, [1])
head_page = '<li><a href="?{}">首页</a></li>'.format(self.query_dict.urlencode())
page_str_list.append(head_page)
if self.page > 1:
self.query_dict.setlist(self.page_param, [self.page - 1])
prev = '<li><a href="?{}" ' \
'aria-label="Previous"><span aria-hidden="true">?</span></a>' \
'</li>'.format(self.query_dict.urlencode())
else:
self.query_dict.setlist(self.page_param, [self.page])
prev = '<li><a href="?{}" ' \
'aria-label="Previous"><span aria-hidden="true">?</span></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)
"""
<li><a href="?page=1">1</a></li>
<li><a href="?page=2">2</a></li>
<li><a href="?page=3">3</a></li>
"""
if self.page < self.total_page_count:
self.query_dict.setlist(self.page_param, [self.page + 1])
next_page = '<li><a href="?{}" aria-label="Next">' \
'<span aria-hidden="true">?</span></a></li>'.format(self.query_dict.urlencode())
else:
self.query_dict.setlist(self.page_param, [self.total_page_count])
next_page = '<li><a href="?{}" aria-label="Next">' \
'<span aria-hidden="true">?</span></a></li>'.format(self.query_dict.urlencode())
page_str_list.append(next_page)
self.query_dict.setlist(self.page_param, [self.total_page_count])
tail_page = '<li><a href="?{}">尾页</a></li>'.format(self.query_dict.urlencode())
page_str_list.append(tail_page)
page_string = mark_safe("".join(page_str_list))
return page_string
bootstrap样式-父类
from django import forms
class BootStrapModelForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for name, field in self.fields.items():
if field.widget.attrs:
field.widget.attrs["class"] = "form-control"
field.widget.attrs["placeholder"] = field.label
else:
field.widget.attrs = {"class": "form-control", "placeholder": field.label}
封装
md5加密
from django.conf import settings
import hashlib
def md5(data_string):
obj = hashlib.md5(settings.SECRET_KEY.encode('utf-8'))
obj.update(data_string.encode('utf-8'))
return obj.hexdigest()
数据库中获取数据
对象/字典
row_object = models.Order.objects.filter(id=eid).filter()
row_dict = models.Order.objects.filter(id=eid).values('title', 'price', 'status').first()
queryset = models.Order.objects.all()
queryset = models.Order.objects.all().values('xx', 'xx')
queryset = models.Order.objects.all().values_list('id', 'title')
柱状图
{% extends 'layout.html' %}
{% load static %}
{% block content %}
<h2>数据统计</h2>
<div class="col-sm-8">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">柱状图</h3>
</div>
<div class="panel-body">
<div id="m2" style="height: 400px; width: 100%">
</div>
</div>
</div>
</div>
{% endblock %}
{% block js %}
<script src="{% static 'js/echarts.js' %}"></script>
<script type="text/javascript">
$(function () {
initBar();
});
function initBar() {
var myChart = echarts.init(document.getElementById('m2'));
var option = {
title: {
text: '业绩'
},
tooltip: {},
legend: {
data: [],
bottom: 0,
},
xAxis: {
data: []
},
yAxis: {},
series: []
};
$.ajax({
url: '/chart/bar/',
type: 'get',
dataType: 'JSON',
success: function (res) {
if (res.status) {
option.legend.data = res.data.legend;
option.xAxis.data = res.data.x_axis;
option.series = res.data.series_list;
myChart.setOption(option);
}
}
});
}
</script>
{% endblock %}
https://echarts.apache.org/zh/index.html
总结
- 创建Django项目
- 修改__ init __.py
import pymysql
pymysql.install_as_MySQLdb()
- settings.py中的DIR templates删除
- 创建app和注册app
python manage.py startapp xxx
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'Employee.apps.EmployeeConfig',
]
-
配置静态文件路径 & 模板路径(放在app目录下) -
配置数据库相关操作
- 第三方模块 mysqlclient
- 自己先去数据库创建一个数据库
- 配置数据库连接settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'ljb',
'USER': 'root',
'PASSWORD': '187365',
'HOST': '127.0.0.1',
'PORT': 3306,
}
}
from django.db import models
class Department(models.Model):
"""部门表"""
title = models.CharField(verbose_name='标题', max_length=32)
def __str__(self):
return self.title
python manage.py makemigrations
python manage.py migrate
-
在urls.py,路由(url和函数的对应关系) -
在views,试图函数,编写业务逻辑 -
templates目录下编写html文件 -
ModelForm & Form组件,在我们开发增删改查功能
- 生成html标签(生成默认值)
- 请求数据进行校验
- 保存到数据库(ModelForm)
- 获取错误信息
-
Cookie和session用户信息保存起来 -
中间件,基于中间件实现用户认证,基于:process_request -
ORM操作
models.User.objects.filter(id="")
{% endblock %}
https://echarts.apache.org/zh/index.html
## 总结
- 创建Django项目
- 修改__ init __.py
```python
import pymysql
pymysql.install_as_MySQLdb()
- settings.py中的DIR templates删除
- 创建app和注册app
python manage.py startapp xxx
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'Employee.apps.EmployeeConfig',
]
-
配置静态文件路径 & 模板路径(放在app目录下) -
配置数据库相关操作
- 第三方模块 mysqlclient
- 自己先去数据库创建一个数据库
- 配置数据库连接settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'ljb',
'USER': 'root',
'PASSWORD': '187365',
'HOST': '127.0.0.1',
'PORT': 3306,
}
}
from django.db import models
class Department(models.Model):
"""部门表"""
title = models.CharField(verbose_name='标题', max_length=32)
def __str__(self):
return self.title
python manage.py makemigrations
python manage.py migrate
-
在urls.py,路由(url和函数的对应关系) -
在views,试图函数,编写业务逻辑 -
templates目录下编写html文件 -
ModelForm & Form组件,在我们开发增删改查功能
- 生成html标签(生成默认值)
- 请求数据进行校验
- 保存到数据库(ModelForm)
- 获取错误信息
-
Cookie和session用户信息保存起来 -
中间件,基于中间件实现用户认证,基于:process_request -
ORM操作
models.User.objects.filter(id="")
|