python:django项目知识点02——搭建简易授权码核销系统
前言
如标题所述,本篇博客主要围绕快速搭建业务系统展开,旨在:快速、逻辑分明。
适用对象
django+mysql,实现一套授权码核销功能,包含用户登录和授权码核销两个方面内容
业务代码
前述
基础代码已在上篇博客中讲述,这里给出核心views代码和html代码
python:django项目知识点01——前期配置、用户管理、权限核验、django-orm-CSDN博客
最终效果
登录
login.py
from django.shortcuts import render, redirect
from django.contrib import messages
from django.contrib.auth import authenticate, login
def user_input_check(username, password):
message = ''
if len(username) > 16:
message = "用户名不得超过16位!"
elif len(password) < 6:
message = "密码不得少于6位!"
elif len(password) > 16:
message = "密码不得超过16位!"
if message:
return False, message
else:
return True, ''
def login_view(request):
if request.method == 'POST':
username = request.POST['username']
password = request.POST['password']
ret, msg = user_input_check(username, password)
if ret:
user = authenticate(request, username=username, password=password)
if user:
login(request, user)
return redirect('/welcome') # 替换 'welcome' 为你应用的主页视图名
else:
messages.error(request, "用户名或密码错误!")
else:
messages.error(request, msg)
return render(request, 'user/login.html')
login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登录</title>
<link rel="stylesheet" href="/static/css/form_add.css">
</head>
<body>
<div class="container">
<div class="form-wrapper">
<h2>用户登录</h2>
{% if messages %}
<ul class="messages">
{% for message in messages %}
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
{% if form.errors %}
<div class="errors">
<ul>
{% for field in form %}
{% for error in field.errors %}
<li>{{ error }}</li>
{% endfor %}
{% endfor %}
{% for error in form.non_field_errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
</div>
{% endif %}
<form method="post">
{% csrf_token %}
<div class="form-group">
<label for="username">用户名</label>
<input type="text" name="username" id="username" required>
</div>
<div class="form-group">
<label for="password">密码</label>
<input type="password" name="password" id="password" required>
</div>
<button type="submit">登录</button>
</form>
</div>
</div>
</body>
</html>
body {
font-family: Arial, sans-serif;
background-color: #f4f4f4;
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
.container {
background: #fff;
padding: 2rem;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
max-width: 500px;
width: 100%;
}
h1 {
margin-bottom: 1rem;
font-size: 24px;
color: #333;
}
.form-group {
margin-bottom: 1rem;
}
.form-group label {
display: block;
margin-bottom: 0.5rem;
font-weight: bold;
color: #555;
}
.form-group input,
.form-group select,
.form-group textarea {
width: 100%;
padding: 0.75rem;
border: 1px solid #ccc;
border-radius: 4px;
box-sizing: border-box;
}
.form-group input:focus,
.form-group select:focus,
.form-group textarea:focus {
border-color: #007bff;
outline: none;
}
.form-group .error {
color: #e74c3c;
font-size: 0.875rem;
margin-top: 0.25rem;
}
button {
background-color: #007bff;
color: #fff;
border: none;
padding: 0.75rem 1.5rem;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
transition: background-color 0.3s;
}
button:hover {
background-color: #0056b3;
}
授权码核销
permission.py
import datetime
import json
from django.http import JsonResponse
from django.shortcuts import render, redirect
from django.conf import settings
from myProject.models.mysql_models import TmLicense, TmAccount, TmAccountLog, raw_sql_select
def permission_view(request):
if not request.user.is_authenticated:
# 用户未登录,重定向到登录页面或显示提示
return redirect('login')
if request.method == 'GET':
username = request.user.username
# 将结果转换为字典列表
results = raw_sql_select("""
SELECT a.username as username, a.account_id as account_id, b.dict_value as user_state, c.account_money as account_money, c.lock_money as lock_money, d.dict_value as account_state
FROM tp_user a
LEFT JOIN tb_dict b ON a.state = b.dict_id AND b.dict_type = 'user_state'
LEFT JOIN tm_account c ON a.account_id = c.account_id
LEFT JOIN tb_dict d ON c.state = d.dict_id AND d.dict_type = 'account_state'
WHERE a.username = %s
""", [username])[0]
# 用户已登录,处理登录用户的逻辑
return render(request, 'user/permission.html',
context={'back_url': settings.WELCOME_URL, 'user': results})
elif request.method == 'POST':
# 解析 JSON 数据
comes = json.loads(request.body)
license_code = comes['license_code']
account_id = comes['account_id']
# 查询当前账户状态
account_msg = TmAccount.objects.filter(account_id=account_id).values('state', 'account_money').get()
account_state = account_msg['state']
account_money = account_msg['account_money']
# 当账户可用时
if account_state == 1:
# 查询该授权码是否正常在用
# 之后的代码都是按照约定状态默认值来的,没有借助字典表
# 因此这里借助字典表来判别验证码状态的情况 存在设计问题
# 这点留给自己做警醒:考虑用哪种策略后,就不要东一道西一道了,要尽量保障代码逻辑一致性
license_msg = raw_sql_select("""
select a.save_money as save_money, b.dict_value as license_state
from tm_license a
join tb_dict b on a.state = b.dict_id and b.dict_type = 'license_state'
where a.license_code = %s
""", [license_code])
print(license_msg)
if not license_msg:
return JsonResponse({'status': False, 'msg': '授权码不存在'})
license_msg = license_msg[0]
if license_msg['license_state'] == '待使用':
after_money = account_money + license_msg['save_money']
# 添加核销记录
log_entry = TmAccountLog(
order_effect_ret=0,
reason=f'license recharge: {license_code}',
account_id=account_id,
effect=license_msg['save_money'],
before=account_money,
after=after_money,
create_time=datetime.datetime.now()
)
log_entry.save()
# 核销授权码
license_updated = TmLicense.objects.filter(license_code=license_code).update(state=2)
if license_updated:
# 账户余额更新
account_updated = TmAccount.objects.filter(account_id=account_id).update(account_money=after_money)
if account_updated:
return JsonResponse({'status': True, 'msg': '成功!'})
# 账户更新失败则回滚授权码状态为待用
else:
TmLicense.objects.filter(license_code=license_code).update(state=1)
return JsonResponse({'status': False, 'msg': '账户异常!'})
return JsonResponse({'status': False, 'msg': '授权码核销失败!'})
else:
return JsonResponse({'status': False, 'msg': '授权码已失效'})
permission.html
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="/static/css/user_permission.css">
<meta name="csrf-token" content="{% csrf_token %}">
<title>用户授权</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
background-color: #f4f4f4;
color: #333;
}
.container {
width: 80%;
max-width: 800px;
margin: 20px auto;
background: #fff;
padding: 20px;
border-radius: 8px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
h1 {
text-align: center;
color: #007bff;
}
</style>
</head>
<body>
<div class="container">
<h1>授权详情</h1>
<!-- 用户信息部分 -->
<div class="info-section">
<h2>用户名</h2>
<p>{{ user.username }}</p>
</div>
<div class="info-section">
<h2>用户状态</h2>
<p>{{ user.user_state }}</p>
</div>
<div class="info-section">
<h2>账户状态</h2>
<p>{{ user.account_state }}</p>
</div>
<div class="info-section">
<h2>钱包余额</h2>
<p style="color: goldenrod">¥ {{ user.account_money }}</p>
</div>
<div class="info-section">
<h2>冻结金额</h2>
<p style="color: red">¥ {{ user.lock_money }}</p>
</div>
<!-- 授权码提交表单 -->
<div class="form-container">
<h2>提交授权码</h2>
<input name="account_id" id="account_id" value="{{ user.account_id }}" hidden/>
<div class="form-group">
<label for="auth-code">授权码</label>
<input type="text" id="license_code" name="license_code" required>
</div>
<div class="form-group">
<button onclick="upMsg()">提交</button>
</div>
</div>
</div>
</body>
<script>
function upMsg() {
var license_code = document.getElementById("license_code").value;
var account_id = document.getElementById("account_id").value;
if (license_code === "") {
alert("请填写完整内容");
return false; // 阻止表单提交
}
var jsonData = JSON.stringify({
"license_code": license_code,
"account_id": account_id,
});
fetch('', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrfToken // 添加 CSRF 令牌到请求头中
},
body: jsonData
})
.then(response => response.json())
.then(data => {
if (data.status === true) {
alert("已充值")
window.location.reload()
} else {
alert("提交失败: " + data.msg);
}
})
.catch(error => {
console.error('提交失败:', error);
alert("提交失败: " + error);
});
}
</script>
</html>
user_permission.css
.info-section {
margin-bottom: 20px;
}
.info-section h2 {
margin-bottom: 10px;
font-size: 1.2em;
color: #555;
}
.info-section p {
font-size: 1.1em;
margin: 5px 0;
}
.form-container {
margin-top: 20px;
}
.form-container h2 {
margin-bottom: 10px;
font-size: 1.2em;
color: #555;
}
.form-group {
margin-bottom: 15px;
}
.form-group label {
display: block;
margin-bottom: 5px;
font-weight: bold;
}
.form-group input[type="text"] {
width: 100%;
padding: 10px;
font-size: 1em;
border: 1px solid #ddd;
border-radius: 4px;
}
.form-group button {
background-color: #007bff;
border: none;
color: white;
padding: 10px 20px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 1em;
margin-top: 10px;
cursor: pointer;
border-radius: 4px;
}
.form-group button:hover {
background-color: #0056b3;
}