Django:已传递user作为关键字参数,Form对象却无'user'属性?
解决Django TransactionForm实例化的AttributeError问题
错误原因分析
你遇到的AttributeError: 'TransactionForm' object has no attribute 'user',核心问题出在TransactionForm的__init__方法执行顺序和参数处理上:
- 你在调用父类
__init__方法之前就尝试访问self.user,但此时self还没有被父类初始化,自然没有user属性 - 你没有从传入的关键字参数中提取
user并将其赋值给self.user - 额外问题:
Coin.objects.get(user=...)会返回单个Coin对象,但ModelChoiceField的queryset需要的是QuerySet类型,用get会导致后续赋值出错(如果用户有多个Coin还会抛出MultipleObjectsReturned异常)
修正方案
第一步:修改forms.py的TransactionForm
调整__init__方法的执行顺序,先提取自定义参数,再调用父类初始化,最后处理字段:
class TransactionForm(forms.ModelForm): CHOICES = ((1, 'Buy'), (2, 'Sell'),) coin = forms.ModelChoiceField(queryset=Coin.objects.all()) buysell = forms.ChoiceField(choices=CHOICES) field_order = ['buysell', 'coin', 'amount', 'trade_price'] class Meta: model = Transactions fields = ['buysell', 'coin', 'amount', 'trade_price'] # 用列表更规范,避免集合的无序性 def __init__(self, *args, **kwargs): # 先从kwargs中取出自定义参数,避免父类初始化报错 self.user = kwargs.pop('user') self.coin_price = kwargs.pop('coin_price', None) # 给个默认值,避免没传时出错 # 先调用父类的初始化方法 super().__init__(*args, **kwargs) # 用filter获取当前用户的Coin QuerySet,而不是get qs_coin = Coin.objects.filter(user=self.user) self.fields['coin'].queryset = qs_coin # 如果要设置trade_price的初始值,示例如下(根据你的需求调整) if self.coin_price: self.fields['trade_price'].initial = self.coin_price
第二步:修复views.py的潜在问题
在GET请求的ajax分支里,str(coin.coin)中的coin变量没有定义,需要补充对应的逻辑(比如从请求参数中获取coin标识),否则会抛出NameError:
def add_transaction(request): print(request.method) print("test1") if request.method == "GET": if request.is_ajax(): print("ajax test") # 补充获取coin变量的逻辑,比如从GET参数中提取 coin_id = request.GET.get('coin_id') coin_price = None if coin_id: coin = Coin.objects.get(id=coin_id) coin_price = GetCoin(str(coin.coin)).price data = {'test': "test1"} form = TransactionForm(request.GET, user=request.user, coin_price=coin_price) return JsonResponse(data) form = TransactionForm(user=request.user) elif request.method == "POST": print("test2") form = TransactionForm(request.POST, user=request.user) if form.is_valid(): print("test3") obj = form.save(commit=False) obj.user = request.user obj.save() return HttpResponseRedirect('/myportfolio/') else: print(form.errors) return render(request, 'myportfolio/add_transaction.html', {'form': form})
关键要点总结
- 自定义表单参数必须在调用父类
__init__之前从kwargs中取出,避免父类无法识别这些参数而报错 - 永远不要在未初始化父类之前访问
self的属性 ModelChoiceField的queryset必须是QuerySet类型,用filter而不是get来获取多个对象的集合
内容的提问来源于stack exchange,提问作者SkillSet12345
相关产品推荐
相关产品推荐

