如何在Django应用中实现数值增减运算并允许用户修改CharField值
Django虚拟货币系统+CharField字段修改实现方案
一、虚拟货币系统实现
1. 模型设计
扩展用户模型添加虚拟货币余额(用DecimalField规避浮点精度问题),同时创建商品模型:
# models.py from django.contrib.auth.models import AbstractUser from django.db import models class CustomUser(AbstractUser): balance = models.DecimalField( max_digits=10, decimal_places=2, default=0.00, verbose_name="虚拟货币余额" ) class Product(models.Model): name = models.CharField(max_length=100) price = models.DecimalField(max_digits=8, decimal_places=2) description = models.TextField(blank=True) def __str__(self): return self.name
记得在settings.py中配置AUTH_USER_MODEL = 'yourapp.CustomUser'
2. 安全的余额增减操作
必须使用Django的F()表达式+数据库事务,避免并发请求下的竞态条件(这是多数人实现失败的核心原因):
# utils.py 或 views.py from django.db import transaction from django.db.models import F from .models import CustomUser def add_balance(user, amount): """增加用户余额""" with transaction.atomic(): CustomUser.objects.filter(id=user.id).update(balance=F('balance') + amount) def deduct_balance(user, amount): """扣减用户余额,返回操作是否成功""" with transaction.atomic(): # 先校验余额充足,再执行扣减 updated_rows = CustomUser.objects.filter( id=user.id, balance__gte=amount ).update(balance=F('balance') - amount) return updated_rows > 0
3. 商品购买逻辑
结合余额扣减实现完整购买流程:
# views.py from django.shortcuts import get_object_or_404, render, redirect from django.contrib.auth.decorators import login_required from .models import Product from .utils import deduct_balance @login_required def buy_product(request, product_id): product = get_object_or_404(Product, id=product_id) if request.method == 'POST': success = deduct_balance(request.user, product.price) if success: # 可选:创建订单记录用于追溯 # Order.objects.create(user=request.user, product=product, amount=product.price) return render(request, 'buy_success.html', {'product': product}) else: return render(request, 'buy_fail.html', {'message': '余额不足'}) return render(request, 'confirm_buy.html', {'product': product})
二、CharField字段修改实现
以修改CustomUser的username为例,完整实现如下:
1. 创建表单
# forms.py from django import forms from .models import CustomUser class UserProfileForm(forms.ModelForm): class Meta: model = CustomUser fields = ['username'] # 替换为你需要修改的CharField字段名 widgets = { 'username': forms.TextInput(attrs={'class': 'form-control'}) }
2. 视图实现
类视图方式(推荐):
# views.py from django.views.generic.edit import UpdateView from django.contrib.auth.mixins import LoginRequiredMixin from django.urls import reverse_lazy from .models import CustomUser from .forms import UserProfileForm class UserProfileUpdateView(LoginRequiredMixin, UpdateView): model = CustomUser form_class = UserProfileForm template_name = 'update_profile.html' success_url = reverse_lazy('profile') # 修改成功后的跳转页面 def get_object(self, queryset=None): return self.request.user # 仅允许修改当前登录用户的字段
函数视图方式:
# views.py from django.contrib.auth.decorators import login_required from django.shortcuts import render, redirect from .forms import UserProfileForm @login_required def update_profile(request): if request.method == 'POST': form = UserProfileForm(request.POST, instance=request.user) if form.is_valid(): form.save() return redirect('profile') else: form = UserProfileForm(instance=request.user) return render(request, 'update_profile.html', {'form': form})
3. 模板示例(update_profile.html)
<form method="post"> {% csrf_token %} {{ form.as_p }} <button type="submit">保存修改</button> </form>
常见问题排查
- 虚拟货币操作失败:检查是否使用了
F()表达式和事务,直接user.balance -= amount再user.save()会引发并发问题; - CharField修改失败:确保表单绑定了用户实例,视图处理了POST请求的表单验证,且目标字段在表单的
fields列表中; - 权限问题:确认视图添加了
login_required或LoginRequiredMixin,仅允许登录用户操作。
内容的提问来源于stack exchange,提问作者Doffy
相关产品推荐
相关产品推荐

