Django股票交易应用查询报错:QuerySet无quantity_available属性
Django股票买卖应用问题解决及优化思路
核心问题分析
你遇到的AttributeError: 'QuerySet' object has no attribute 'quantity_available'错误,原因是:
Share.objects.filter()和Share.objects.all()返回的是QuerySet(对象集合),不是单个Share实例,无法直接访问单个对象的属性(比如quantity_available)。- 买卖逻辑中还存在其他漏洞:卖股票未校验用户实际持仓数量、表单未关联具体股票选择等。
代码修复方案
1. 修复买入视图(buy_share)
假设业务逻辑是让用户选择具体可购买的股票,修复后的代码如下:
视图代码
from django.shortcuts import render, redirect from django.db import transaction from .models import Share, Transaction from .forms import BuyShareForm @transaction.atomic # 确保数据库操作原子性,避免数据不一致 def buy_share(request): # 获取所有可购买的股票(数量>100) available_shares = Share.objects.filter(quantity_available__gt=100) form = BuyShareForm(request.POST or None) if request.method == 'POST' and form.is_valid(): selected_share = form.cleaned_data['share'] quantity = form.cleaned_data['quantity'] if quantity <= selected_share.quantity_available: total_price = quantity * selected_share.price # 创建交易记录 Transaction.objects.create( user=request.user, share=selected_share, quantity=quantity, total_price=total_price, is_purchase=True ) # 更新股票可用数量 selected_share.quantity_available -= quantity selected_share.save() return redirect('shares:buy-success') else: form.add_error('quantity', 'Insufficient shares available') context = { 'available_shares': available_shares, 'form': form, } return render(request, 'shares/buy_share.html', context)
对应的BuyShareForm
需要添加股票选择字段,让用户指定要买哪只股票:
from django import forms from .models import Share class BuyShareForm(forms.Form): share = forms.ModelChoiceField( queryset=Share.objects.filter(quantity_available__gt=100), label="选择股票" ) quantity = forms.IntegerField(min_value=1, label="购买数量")
2. 修复卖出视图(sell_share)
卖出逻辑必须先校验用户实际持仓数量,修复后的代码如下:
视图代码
from django.shortcuts import render, redirect from django.db import transaction from .models import Share, Transaction from .forms import SellShareForm @transaction.atomic def sell_share(request): # 获取用户持有的所有股票(通过交易记录统计) user_purchases = Transaction.objects.filter(user=request.user, is_purchase=True) user_owned_share_ids = user_purchases.values_list('share_id', flat=True).distinct() user_shares = Share.objects.filter(id__in=user_owned_share_ids) form = SellShareForm(request.POST or None, user=request.user) if request.method == 'POST' and form.is_valid(): selected_share = form.cleaned_data['share'] quantity = form.cleaned_data['quantity'] # 计算用户当前持有该股票的总数量 total_held = user_purchases.filter(share=selected_share).aggregate( total=models.Sum('quantity') )['total'] or 0 if quantity > total_held: form.add_error('quantity', '你持有的股票数量不足') else: total_price = quantity * selected_share.price # 创建卖出交易记录 Transaction.objects.create( user=request.user, share=selected_share, quantity=quantity, total_price=total_price, is_purchase=False ) # 恢复股票可用数量 selected_share.quantity_available += quantity selected_share.save() return redirect('shares:sell_success') context = { 'user_shares': user_shares, 'form': form, } return render(request, 'shares/sell_share.html', context)
对应的SellShareForm
只显示用户实际持有的股票:
from django import forms from .models import Share, Transaction class SellShareForm(forms.Form): def __init__(self, *args, **kwargs): self.user = kwargs.pop('user') super().__init__(*args, **kwargs) # 动态生成用户持有的股票选项 user_purchases = Transaction.objects.filter(user=self.user, is_purchase=True) user_owned_share_ids = user_purchases.values_list('share_id', flat=True).distinct() self.fields['share'].queryset = Share.objects.filter(id__in=user_owned_share_ids) share = forms.ModelChoiceField(queryset=Share.objects.none(), label="选择要卖出的股票") quantity = forms.IntegerField(min_value=1, label="卖出数量")
其他实现思路
支付功能集成
- 使用
@transaction.atomic()装饰器包裹支付+交易逻辑,确保支付成功后才更新股票数量和创建交易记录,避免数据不一致。 - 对接移动支付API时,需处理回调通知:只有收到支付成功的回调后,才执行股票和交易的更新操作。
- 使用
用户持仓优化
- 可以给
CustomUser模型添加get_portfolio()方法,或者单独创建Portfolio模型,实时记录用户的持仓情况,避免每次查询都统计交易记录,提升性能。
- 可以给
股票价格动态更新
- 用Celery定时任务调用第三方股票API,定期更新
Share模型的price字段,实现价格实时同步。
- 用Celery定时任务调用第三方股票API,定期更新
权限与安全
- 给买卖视图添加
@login_required装饰器,禁止未登录用户访问。 - 对表单输入做更严格的校验(比如购买数量不能超过单日限额等)。
- 给买卖视图添加
交易记录展示
- 开发用户交易历史页面,过滤当前用户的
Transaction记录,支持按时间、股票类型筛选,并实现分页展示。
- 开发用户交易历史页面,过滤当前用户的
内容的提问来源于stack exchange,提问作者derekr
相关产品推荐
相关产品推荐

