python:django项目知识点02——搭建简易授权码核销系统
前言
如标题所述,本篇博客主要围绕快速搭建业务系统展开,旨在:快速、逻辑分明。
适用对象
django+mysql,实现一套授权码核销功能,包含用户登录和授权码核销两个方面内容
业务代码
前述
基础代码已在上篇博客中讲述,这里给出核心views代码和html代码
python:django项目知识点01——前期配置、用户管理、权限核验、django-orm-CSDN博客
最终效果
登录
login.pyfrom django.shortcuts import render, redirect
from django.contrib import messages
from django.contrib.auth import authenticate, logindef 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, messageelse: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.pyimport 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_selectdef 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_stateFROM tp_user aLEFT 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_idLEFT 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_statefrom tm_license ajoin 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;
}