Django 网页公共部分编写
前言:目前还在学习中,这是第一个尝试的项目,多有不足,感谢大家的观看与批评。
目标:
一. 前端页面
这次没找到前辈的模板,自行编写base.html和base.css
<!DOCTYPE html>
<html lang="zh-CN">
{% load static %}
<head>
<meta charset="UTF-8">
<title>用户界面</title>
<link rel="stylesheet" type="text/css" href="{% static 'base/scripts/svg_img/iconfont.css' %}">
<link rel="stylesheet" type="text/css" href="{% static 'base/css/base.css' %}">
</head>
<body>
{# 上方基本信息展示 #}
<nav class="nav_top">
<div class="leftNav iconfont"> 刷票管理平台</div>
<div class="rightSvg iconfont"></div>
<div class="rightNav">zcc</div>
</nav>
{# 下方主要内容部分 #}
<div class="main_content">
<div class="mainDiv">
{# 左边导航栏 #}
<div class="leftDiv">
<div class="iconfont"> 用户信息</div>
<ul class="user_info" style="margin-bottom: 0">
<a href="#"><li>个人资料</li></a>
<a href="#"><li>我的交易</li></a>
</ul>
<div class="iconfont"> 平台分类</div>
<ul class="plat_type">
<a href="#"><li>央视频</li></a>
<a href="#"><li>B站完播</li></a>
<a href="#"><li>B站播放量(30%~50%完播)</li></a>
</ul>
</div>
{# 右侧用户操作内容展示,这里是上方的小字导航栏和右侧、下侧的滑块部分 #}
<div class="rightDiv">
<div class="infor">
</div>
<div class="information">
</div>
</div>
</div>
</div>
</body>
</html>
* {
margin: 0;
padding: 0;
}
/*顶部基本信息展示部分*/
.nav_top {
background-color: #2f72ab;
width: 100%;
height: 60px;
border-top-left-radius: 12px;
border-top-right-radius: 12px;
position: fixed;
}
/*左部导航栏*/
.leftNav {
float: left;
height: 20px;
padding-left: 40px;
padding-top: 20px;
font-family: Microsoft YaHei;
color: white;
}
/*右侧用户操作内容部分*/
.rightNav {
float: right;
height: 20px;
padding-top: 20px;
font-family: Microsoft YaHei;
color: white;
}
.rightSvg {
float: right;
height: 40px;
line-height: 40px;
font-size: 36px;
padding-right: 40px;
padding-top: 10px;
color: white;
}
.main_content {
width: 100%;
height: calc(100vh - 60px);
display: flex;
flex-flow: column nowrap;
}
.mainDiv {
margin-top: 60px;
flex: 1;
}
/*去除左侧导航栏所有超链接的下划线*/
.main_content .mainDiv .leftDiv ul a:hover {
text-decoration: none;
}
.leftDiv {
float: left;
width: calc(20% - 6px);
height: calc(100vh - 60px);;
background-color: #eaedf1;
}
.leftDiv div {
background-color: #f5f5f5;
padding-left: 10px;
height: 40px;
line-height: 40px;
}
.leftDiv li {
background-color: #fff;
padding-left: 30px;
height: 30px;
line-height: 30px;
color: #2f72ab;
}
.rightDiv {
float: left;
width: 80%;
height: calc(100vh - 60px);
margin-left: 5px;
overflow: scroll;
border-left: #e8e8e8 solid 1px;
}
/*用户操作部分上方导航*/
.infor {
width: 100%;
height: 30px;
background-color: #f5f5f5;
padding-left: 20px;
line-height: 30px;
}
.infor ul li {
display: inline-block;
list-style-type: none;
}
.infor ul li a {
color: black;
}
.infor ul li a:hover {
text-decoration: none;
}
/*右侧上方小导航部分,最后一部分文字颜色不一样*/
.infor ul li a:last-child {
color: #828282;
}
.information {
width: 100%;
}
注意:
1. 矢量图下载与使用:iconfont-阿里巴巴矢量图标库,按照官网流程操作。
2. 注意margin的使用——相邻块元素合并与嵌套块元素塌陷。建议多用padding。
3. CSS各个单位的区别:px、pt、em、rem、vh、vw。参考前辈文章常见CSS单位总结_css 相对单位-CSDN博客
4. 自动填充页面剩余部分:使用Flex布局 - - > 参考前辈文章Flex布局详解-CSDN博客
二. Django前端调整
添加 {% block style %}{% endblock %} 用于其他页面添加CSS代码;使用 {{ title }} 用于不同的标题, {{ username }} 同理。
<head>
<meta charset="UTF-8">
<title>{{ title }}</title>
<link rel="stylesheet" type="text/css" href="{% static 'base/scripts/svg_img/iconfont.css' %}">
<link rel="stylesheet" type="text/css" href="{% static 'base/css/base.css' %}">
{% block style %}{% endblock %}
</head>
<body>
<nav class="nav_top">
<div class="leftNav iconfont"> 刷票管理平台</div>
<div class="rightSvg iconfont"></div>
<div class="rightNav">{{ username }}</div>
</nav>
用户操作部分:
{% block spans %}{% endblock %} 用于修改上方小导航;{% block information %}{% endblock %} 用于添加主题内容。
<div class="rightDiv">
<div class="infor">
{% block spans %}
{% endblock %}
</div>
<div class="information">
{% block information %}
{% endblock %}
</div>
</div>
至此结束。
Django 用户资料界面编写
目标:
一. 前端页面
引入公共部分 base.html
{% extends 'base_html/base.html' %}
引入CSS文件和Bootstrap
{% load static %}
{% block style %}
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.0/css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css">
<link rel="stylesheet" type="text/css" href="{% static 'user/css/user.css' %}">
{% endblock %}
右侧上方小导航部分:
{% block spans %}
<ul>
<li>
<a href="#"><span>用户信息</span></a>
<span>/</span>
</li>
<li>
<a href="#"><span>个人资料</span></a>
</li>
</ul>
{% endblock %}
右侧主体部分:
{% block information %}
{# 左侧用户资料 #}
<div class="myInfo">
<div class="iconfont"> 我的资料</div>
<div>
<table>
<tbody>
<tr>
<td>用户名</td>
<td>{{ username }}</td>
</tr>
<tr>
<td>账户余额</td>
<td>{{ balance }}</td>
</tr>
<tr>
<td>注册时间</td>
<td>{{ regTime }}</td>
</tr>
</tbody>
</table>
</div>
</div>
{# 右侧修改密码 #}
<div class="pwdChange">
<div class="iconfont"> 修改密码</div>
<div>
<form id="pwd-form" method="post" role="form" novalidate>
{% csrf_token %}
<table>
<tbody>
<tr>
<td>密码</td>
<td>{{ form.enterPwd }}</td>
</tr>
<tr>
<td>确认密码</td>
<td>{{ form.ensurePwd }}</td>
</tr>
<tr>
<td></td>
<td>
<button type="submit" class="form-control">提交</button>
<span class="error_massage">
{{ form.ensurePwd.errors }}
</span>
</td>
</tr>
</tbody>
</table>
</form>
</div>
</div>
{% endblock %}
CSS代码:
/*左侧导航栏左边装饰效果*/
.leftDiv .user_info > a:first-child li {
border-left: #2f72ab solid 5px;
padding-left: 25px;
}
/*Flex布局*/
.information{
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
}
.information .myInfo{
margin-left: 25px;
width: 47%;
margin-top: 25px;
height: 250px;
}
.information .pwdChange{
margin-right: 25px;
width: 47%;
margin-top: 25px;
height: 250px;
}
/*左侧用户资料*/
/*上面的名字*/
.information .myInfo div:first-child{
width: 100%;
height: 50px;
border: #eaedf1 solid 2px;
background-color: #f5f5f5;
line-height: 50px;
padding-left: 20px;
font-weight: bold;
}
.information .myInfo div:last-child{
width: 100%;
height: 200px;
border: #eaedf1 solid 2px;
border-top: #eaedf1 solid 0;
}
.information .myInfo div table{
padding-top: 20px;
padding-left: 36px;
border-collapse: initial;
}
.information .myInfo div table tr td{
padding: 10px;
}
.information .myInfo div table tr td:first-child{
text-align: right;
font-weight: bold;
}
/*右侧·修改密码*/
.information .pwdChange div:first-child{
width: 100%;
height: 50px;
border: #eaedf1 solid 2px;
background-color: #f5f5f5;
line-height: 50px;
padding-left: 20px;
font-weight: bold;
}
.information .pwdChange div:last-child{
width: 100%;
height: 200px;
border: #eaedf1 solid 2px;
border-top: #eaedf1 solid 0;
}
.information .pwdChange div table{
padding-top: 20px;
padding-left: 36px;
border-collapse: initial;
}
.information .pwdChange div table tr td{
padding: 10px;
}
.information .pwdChange div table tr td:first-child{
text-align: right;
font-weight: bold;
}
.information .pwdChange div table tr button{
width: 27%;
height: 30px;
line-height: 5px
}
.error_massage li{
color: red;
list-style-type: none;
padding-top: 5px;
}
二. Django后端各种py文件
urls.py:
int:id 用于传输登录用户的id,便于后续查询数据库。
name:"user_view" 方便后续跳转网页。
path('user/<int:id>/', user_views.user, name="user_view"),
views.py:
和上一篇博客的login差不多,但存在问题,即修改密码后刷新浏览器会出现警告“新密码不应该与旧密码相同”
class pwdForm(forms.Form):
# 输入新密码
enterPwd = forms.CharField(
required=True,
widget=forms.TextInput(attrs={'class': 'form-control', 'placeholder': "请输入密码", 'style': "width: 200%"}),
error_messages={"required": "该字段不能为空"},
label='输入密码'
)
# 确认密码
ensurePwd = forms.CharField(
required=True,
widget=forms.TextInput(attrs={'class': 'form-control', 'placeholder': "请确认密码", 'style': "width: 200%"}),
error_messages={"required": "该字段不能为空"},
label='确认密码'
)
def user(request, **kwargs):
# 获取数据库数据
user_id = kwargs.get('id')
user_info = User.objects.get(id=user_id)
username = user_info.name
oldPwd = user_info.pwd
balance = user_info.balance
regTime = user_info.regTime
if request.method == "GET":
form = pwdForm()
return render(request, 'user_html/user.html',
{"form": form, "title": "用户界面", "username": username, "balance": balance, "regTime": regTime,
"userId": user_id})
elif request.method == 'POST':
form = pwdForm(request.POST)
if form.is_valid():
# 输入新密码
enterPwd = form.cleaned_data['enterPwd']
# 确认密码
ensurePwd = form.cleaned_data['ensurePwd']
if enterPwd == ensurePwd and enterPwd != oldPwd:
User.objects.filter(id=user_id).update(pwd=enterPwd)
form.add_error("ensurePwd", "密码修改成功")
return render(request, "user_html/user.html",
{"form": form, id: user_id, "title": "用户界面", "username": username, "balance": balance,
"regTime": regTime, "userId": user_id})
# 浏览器刷新后自动提交表单导致出现"新密码不应该与旧密码相同"提醒
elif enterPwd == ensurePwd and enterPwd == oldPwd:
form.add_error("ensurePwd", "新密码不应该与旧密码相同")
return render(request, "user_html/user.html",
{"form": form, id: user_id, "title": "用户界面", "username": username, "balance": balance,
"regTime": regTime, "userId": user_id})
else:
form.add_error("ensurePwd", "两次密码不一致")
return render(request, "user_html/user.html",
{"form": form, id: user_id, "title": "用户界面", "username": username, "balance": balance,
"regTime": regTime, "userId": user_id})
else:
form = pwdForm()
return render(request, 'user_html/user.html',
{"form": form, "title": "用户界面", "username": username, "balance": balance, "regTime": regTime,
"userId": user_id})
Django交易界面编写
目标:
一. 前端页面
使用bootstrap即可,没什么注意点。
二. Django分页器Paginator
此处参考了这位前辈的文章:Django 使用Paginator分页器_django paginator-CSDN博客
from django.core.paginator import Paginator
2.0 创建数据库
class Transaction(models.Model):
ACTION_STATES = {
"Y": "已执行",
"N": "待执行"
}
username = models.CharField(verbose_name='用户名', max_length=32)
actionDate = models.DateField(verbose_name='交易日期', auto_now=True)
actionNumber = models.CharField(verbose_name='订单号', max_length=32, default="")
aimUrl = models.CharField(verbose_name='目标URL', max_length=256)
actionAmount = models.IntegerField(verbose_name='刷单数量', default=0)
# 最大数位为5,小数点后保留两位小数
originalPrice = models.DecimalField(verbose_name='原价', max_digits=5, decimal_places=2, default=0.00)
deductionPrice = models.DecimalField(verbose_name='折扣价', max_digits=5, decimal_places=2, default=0.00)
originalBroadcast = models.CharField(verbose_name="原播放量", max_length=32, default="0")
actionState = models.CharField(verbose_name="状态", max_length=1, choices=ACTION_STATES, default="N")
note = models.CharField(verbose_name="备注", max_length=128, default="测试")
注意点:
(1). choices
ACTION_STATES = {
"Y": "已执行",
"N": "待执行"
}
actionState = models.CharField(verbose_name="状态", max_length=1, choices=ACTION_STATES, default="N")
方便操作,后续使用时,object.actionState = "Y", object.get_actionState_display = "已执行"。
(2). 保留两位小数
originalPrice = models.DecimalField(verbose_name='原价', max_digits=5, decimal_places=2, default=0.00)
max_digits=5:最大数位为5;decimal_places=2:保留两位小数。
2.1 创建实例
order_info = Transaction.objects.filter(username=username)
paginator = Paginator(order_info, 10) # 数据来源为order_info,每页最多十行数据
page = request.GET.get('page', 1) # 获取当前请求的页码,默认为第一页
currentData = paginator.get_page(page) # 获取第一页的数据,传递到前端页面
前端代码:
<tbody>
{% for order in currentDate %}
<tr>
<td>{{ order.actionDate }}</td>
<td>{{ order.actionNumber }}</td>
<td>{{ order.aimUrl }}</td>
<td>{{ order.actionAmount }}</td>
<td>¥{{ order.originalPrice }}</td>
<td>¥{{ order.deductionPrice }}</td>
<td>{{ order.originalBroadcast }}</td>
<td>{{ order.get_actionState_display }}</td>
<td>{{ order.note }}</td>
</tr>
{% endfor %}
</tbody>
分页效果:
<ul class="pagination">
{% if order_list.has_previous %}
<li class="page-item"><a class="page-link" href="?id={{ currentData.previous_page_number }}">上一页</a></li>
{% else %}
<li class="page-item disabled"><a class="page-link" href="#">上一页</a></li>
{% endif %}
{# ... #}
</ul>
2.3 优化
def YSP(request, **kwargs):
user_id = kwargs.get('id')
user_info = User.objects.get(id=user_id)
username = user_info.name
# 获取分页数据
order_info = Transaction.objects.filter(username=username)
# 创建实例
orderPaginator = Paginator(order_info, 10)
currentPage = int(request.GET.get("id", 1))
# 当数据大于10页时,页面只显示10页
if orderPaginator.num_pages > 15:
if currentPage - 5 < 1:
pageRange = range(1, 11)
elif currentPage + 5 > orderPaginator.num_pages:
pageRange = range(currentPage - 5, orderPaginator.num_pages)
else:
pageRange = range(currentPage - 5, currentPage + 5)
else:
pageRange = orderPaginator.page_range
# 分页器id超出范围时返回第一面或最后一面
try:
order_list = orderPaginator.page(currentPage)
except PageNotAnInteger:
order_list = orderPaginator.page(1)
except EmptyPage:
order_list = orderPaginator.page(orderPaginator.num_pages)
return render(request, "user_html/YSP.html", {"userId": user_id,
"username": username,
"order_list": order_list,
"paginator": orderPaginator,
"page_range": pageRange,
"currentPage": currentPage,
"title": "平台分类"})
前端代码:
<table class="table table-bordered">
<thead>
<tr>
<th>日期</th>
<th>订单号</th>
<th>URL</th>
<th>数量</th>
<th>原价</th>
<th>折扣价</th>
<th>原播放量</th>
<th>状态</th>
<th>备注</th>
<th>删除</th>
</tr>
</thead>
<tbody>
{% for order in order_list %}
<tr>
<td>{{ order.actionDate }}</td>
<td>{{ order.actionNumber }}</td>
<td>{{ order.aimUrl }}</td>
<td>{{ order.actionAmount }}</td>
<td>¥{{ order.originalPrice }}</td>
<td>¥{{ order.deductionPrice }}</td>
<td>{{ order.originalBroadcast }}</td>
<td>{{ order.get_actionState_display }}</td>
<td>{{ order.note }}</td>
<td>
<form method="GET" action="./deleteOrder/">
{% csrf_token %}
<input type="hidden" name="order_actionNumber" value="{{ order.actionNumber }}">
<button type="submit" class="btn btn-danger btn-xs">删除</button>
</form>
</td>
</tr>
{% endfor %}
</tbody>
</table>
<nav class="d-flex justify-content-center" aria-label="Page navigation example">
<ul class="pagination">
{% if order_list.has_previous %}
<li class="page-item"><a class="page-link" href="?id={{ order_list.previous_page_number }}">上一页</a>
</li>
{% else %}
<li class="page-item disabled"><a class="page-link" href="#">上一页</a></li>
{% endif %}
{% for item in page_range %}
{% if item == currentPage %}
<li class="page-item active"><a class="page-link" href="?id={{ item }}">{{ item }}</a></li>
{% else %}
<li class="page-item"><a class="page-link" href="?id={{ item }}">{{ item }}</a></li>
{% endif %}
{% endfor %}
{% if order_list.has_next %}
<li class="page-item"><a class="page-link" href="?id={{ order_list.next_page_number }}">下一页</a></li>
{% else %}
<li class="page-item disabled"><a class="page-link" href="#">下一页</a></li>
{% endif %}
<li class="page-item">
<span class="page-link" id="stataData"
style="color: #828282">共 {{ paginator.count }} 条数据, 页码{{ currentPage }}/{{ paginator.num_pages }}页</span>
</li>
</ul>
</nav>
2.4 实际效果
三. 添加与删除订单
目标页面:
后端代码:
def createOrder(request, **kwargs):
user_id = kwargs.get('id')
user_info = User.objects.get(id=user_id)
username = user_info.name
if request.method == 'POST':
form = CORForm(request.POST)
if form.is_valid():
aimUrl = form.cleaned_data['aimUrl']
actionAmount = form.cleaned_data['actionAmount']
note = form.cleaned_data['note']
actionNumber = ''.join(str(random.randint(0, 9)) for _ in range(22))
originalPrice = 0.0004 * actionAmount
Transaction.objects.create(username=username, actionNumber=actionNumber, aimUrl=aimUrl,actionAmount=actionAmount, originalPrice=originalPrice, note=note)
return redirect("YSP", id=user_id)
else:
form = CORForm()
return render(request, "user_html/createOrder.html",
{"userId": user_id, "username": username, "form": form, "title": "平台分类"})
def deleteOrder(request, **kwargs):
user_id = kwargs.get('id')
user_info = User.objects.get(id=user_id)
username = user_info.name
if request.method == 'POST':
delete_actionNumber = request.POST.get("order_actionNumber")
order_info = Transaction.objects.get(actionNumber=delete_actionNumber)
order_info.delete()
return redirect("YSP", id=user_id)
else:
delete_actionNumber = request.GET.get("order_actionNumber")
order_info = Transaction.objects.get(actionNumber=delete_actionNumber)
return render(request, "user_html/deleteOrder.html",
{"userId": user_id, "username": username, "order": order_info, "title": "平台分类"})
普通的增加 Transaction.objects.create() 和
删除 Transaction.objects.get(actionNumber=delete_actionNumber).delete() 。
四. 交易记录页面
创建数据库
class Operation(models.Model):
OPERATIONS = {
"D": "删除订单",
"C": "创建订单",
"O": "执行订单",
}
NOTES = {
"Y": "央视频播放",
"B": "B站播放",
"T": "B站30%播放",
}
username = models.CharField(verbose_name='用户名', max_length=32, default="")
actionNumber = models.CharField(verbose_name='订单号', max_length=32, default="")
transactionAmountSign = models.CharField(verbose_name='交易金额正负', max_length=1, default="+")
transactionAmount = models.DecimalField(verbose_name='交易金额', max_digits=5, decimal_places=2, default=0.00)
operator = models.CharField(verbose_name='操作员', max_length=32, default="-")
actionDate = models.DateField(verbose_name='交易日期', auto_now=True)
operation = models.CharField(verbose_name='操作类型', max_length=1, choices=OPERATIONS)
note = models.CharField(verbose_name="备注", max_length=1, choices=NOTES)
后端代码编写:
由于分页器用得比较多,所以包装成函数
def makePagination(data_list, request):
from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage
Paginator = Paginator(data_list, 10)
currentPage = int(request.GET.get("id", 1))
if Paginator.num_pages > 15:
if currentPage - 5 < 1:
pageRange = range(1, 11)
elif currentPage + 5 > Paginator.num_pages:
pageRange = range(currentPage - 5, Paginator.num_pages)
else:
pageRange = range(currentPage - 5, currentPage + 5)
else:
pageRange = Paginator.page_range
try:
page_list = Paginator.page(currentPage)
except PageNotAnInteger:
page_list = Paginator.page(1)
except EmptyPage:
page_list = Paginator.page(Paginator.num_pages)
page_list = {"page_list": page_list, "Paginator": Paginator, "pageRange": pageRange, "currentPage": currentPage}
return page_list
def transaction(request, **kwargs):
user_id = kwargs.get('id')
user_info = User.objects.get(id=user_id)
username = user_info.name
operation_info = Operation.objects.filter(username=username)
page_list = makePagination(operation_info, request)
return render(request, "user_html/transaction.html", {"userId": user_id,"username": username,"operation_list": page_list['page_list'],"paginator": page_list['Paginator'],"page_range": page_list['pageRange'],"currentPage": page_list['currentPage'],"title": "交易记录"})
关于顶部快速筛选的button,先欠着,以后再补