Django表单提交报错:'User' object has no attribute 'get' 求助
问题描述
尝试从用户提交的数据生成PDF(数据基于models.py定义的字段),点击提交按钮后出现报错:
AttributeError at /website/tbt.html
'User' object has no attribute 'get'
相关代码
models.py
tbt_date = models.DateField( verbose_name="Date of Creation", default=timezone.now ) selected_site = models.ForeignKey( sites_data, verbose_name="Choose a site", on_delete=models.CASCADE ) selected_block = models.ForeignKey( blocks_list, verbose_name="Choose a block", on_delete=models.SET_NULL, null=True ) tbt_report_img1 = models.ImageField( upload_to="formImages/TBT/", verbose_name="Upload Image 1" ) tbt_report_img2 = models.ImageField( upload_to="formImages/TBT/", verbose_name="Upload Image 2" ) rt_pdf = models.FileField(upload_to='pdfs/', verbose_name='PDF File', null=True)
views.py
def tbtform(request): tbt_form_view = tbt_report_form() context = { "loggedInUser": request.user, "tbt_form":tbt_form_view, } return context #@login_required(login_url="user_login") def generate_tbt_report(request, t_form, selected_form, filename): selected_site = t_form.selected_site selected_block = t_form.selected_block selected_site_data = sites_data.objects.filter(name=selected_site)[0] tbt_date = t_form.tbt_date print(tbt_date) params = { "selected_site": selected_site_data, "tbt_date": tbt_date, "selected_block": selected_block, "t": t_form, "data": selected_form, "loggedInUser": request.user, } template_path = "website/tbt_report_pdf.html" temp_pdf = render_to_pdf(request, template_path, params, filename) return temp_pdf @login_required(login_url="user_login") def tbt_form(request): if request.method == "POST": t_form=tbt_report_form(request.user, request.POST, request.FILES) t_form.full_clean() print("in post") if t_form.is_valid(): print("Valid") t_form = t_form.save() filename='TBT' + ' ' + str(t_form.tbt_date) + ' ' + str(t_form.selected_block) + '.pdf' pdf = generate_tbt_report(request, t_form, filename) cv_get = tbt_report.objects.get(id = t_form.id) cv_get.rt_pdf.save(filename, File(BytesIO(pdf.content))) print("Saved") return pdf else: print("1") print(t_form) messages.error( request=request, message="Please check all the fields entered!!!" ) return render(request, "website/tbt.html", context=tbtform(request)) else: return render(request, "website/tbt.html", context=tbtform(request))
tbt.html
{% load crispy_forms_tags %} <!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" type="text/css" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"> <style> /* .tab { display: none; } */ label { font-family: "Franklin Gothic Medium", "Arial Narrow", Arial, sans-serif; text-transform: uppercase; padding-top: 18px; border-bottom: 5px inset #008000; margin-bottom: 15px; } .form-control-file { border: 2px solid #ccc; display: inline-block; padding: 12px 10px; cursor: pointer; font-family: monospace; } .hidden{ display: none; } </style> <title>VoltAmp - Solar Panacea</title> </head> <body> <div class="container" style="padding: 5% 12% 10% 12%;"> <div class="container"> <img src="{% static 'website/img/logo.jpg' %}" alt=""> </div> <hr> <form method="POST" role="form" id='tbt_form' enctype="application/x-www-form-urlencoded" data-blocks-url="{% url 'ajax_load_blocks' %}" novalidate> {% csrf_token %} {% for message in messages %} {% if message.tags == "error" %} <div class="alert alert-danger"> {% else %} <div class="alert alert-{{ message.tags }}"> {% endif %} <a class="close" href="" data-dismiss="alert">×</a> {{ message }} </div> {% endfor %} <div class="container" style="background-color: #FFFF00;padding: 4% ;"> <h1 class="text-center" style="font-weight: bold;font-family:'Gill Sans', 'Gill Sans MT', Calibri, 'Trebuchet MS', sans-serif"> TBT </h1> </div> <div class="tab"> <div class="form-group"> {{ tbt_form|crispy }} </div> </div> <div style="overflow:auto;"> <div class="col-sm-12 d-grid gap-2 pt-3"> <button type="submit" id="submitBtn" class="btn btn-warning btn-block">Submit</button> </div> <div class="col-sm-12 d-grid gap-2 pt-3"> <a href="{% url 'user_logout' %}"><input type="button" id="logoutBtn" class="btn btn-danger btn-block" value="Logout"></a> </div> </div> </form> </div> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.1/dist/js/bootstrap.bundle.min.js" integrity="sha384-gtEjrD/SeCtmISkJkNUaaKMoLD0//ElJ19smozuHV6z3Iehds+3Ulb9Bn9Plx0x4" crossorigin="anonymous"></script> <script src="https://code.jquery.com/jquery-3.3.1.min.js"></script> </body> </html>
错误分析
- 表单实例化参数错误:
views.py中POST分支创建表单时,错误地将request.user作为第一个参数传入tbt_report_form。Django表单类的第一个参数应为data(POST数据),表单初始化时会尝试调用data.get()方法,而User对象没有该方法,直接触发报错。 - 函数调用参数不匹配:
generate_tbt_report定义需要4个参数,但调用时只传了3个,导致参数位置错位,后续逻辑可能出现异常。 - 表单编码类型错误:表单包含文件上传字段,却使用
application/x-www-form-urlencoded编码,无法正确处理文件数据。
解决步骤
1. 修正表单实例化方式
如果表单需要用到当前用户,需在表单类的__init__方法中接收自定义参数:
# forms.py class tbt_report_form(forms.ModelForm): def __init__(self, *args, user=None, **kwargs): super().__init__(*args, **kwargs) self.user = user # 可根据user做字段过滤等操作 class Meta: model = tbt_report fields = ['tbt_date', 'selected_site', 'selected_block', 'tbt_report_img1', 'tbt_report_img2']
然后在views.py中正确实例化:
t_form = tbt_report_form(request.POST, request.FILES, user=request.user)
若表单不需要用户参数,直接去掉多余参数:
t_form = tbt_report_form(request.POST, request.FILES)
2. 修正generate_tbt_report函数调用
函数定义中selected_form参数未被实际使用,直接删除该参数:
def generate_tbt_report(request, t_form, filename): selected_site = t_form.selected_site selected_block = t_form.selected_block # 改用first()避免索引错误 selected_site_data = sites_data.objects.filter(name=selected_site).first() if not selected_site_data: messages.error(request, "Selected site does not exist") return render(request, "website/tbt.html", context=tbtform(request)) tbt_date = t_form.tbt_date params = { "selected_site": selected_site_data, "tbt_date": tbt_date, "selected_block": selected_block, "t": t_form, "loggedInUser": request.user, } template_path = "website/tbt_report_pdf.html" temp_pdf = render_to_pdf(request, template_path, params, filename) return temp_pdf
调用时保持参数匹配:
pdf = generate_tbt_report(request, t_form, filename)
3. 修正表单编码类型
在tbt.html的form标签中,设置正确的文件上传编码:
<form method="POST" role="form" id='tbt_form' enctype="multipart/form-data" data-blocks-url="{% url 'ajax_load_blocks' %}" novalidate>
4. 额外优化
- 移除
t_form.full_clean(),is_valid()会自动执行表单校验逻辑。 - 避免使用
filter(...)后直接取索引[0],改用first()并处理数据不存在的情况,防止抛出索引错误。
验证修复
完成修改后重新提交表单,确认:
- 表单可正常校验通过
- PDF能正确生成并保存至数据库
- 页面不再抛出
AttributeError异常
内容的提问来源于stack exchange,提问作者Aditya Gidh
相关产品推荐
相关产品推荐

