如何在Django中从HTML表单向views.py传递模型类名称?
问题
我希望让用户能下载应用中展示的Django模型数据为Excel文件,但因为有多种模型类型,需要做通用化处理。目前我用以下HTML实现Plant模型的下载:
<form id="downloadfile" method="post" action="{% url 'download_file' filename='Irrelevant.xlsx'%}"> {% csrf_token %} <input type="hidden" value="Plant" name="database" /> <input type="submit" name="downloadfile" class="btn btn-success" value="Download Plant"> </form>
对应的views.py代码:
# Define function to download excel file using template from database.models import Plant def download_file(request, filename=''): if 'downloadfile' in request.POST: db_name = request.POST.get('database') # 如何动态指定对应的模型? response = xlsx_generator(Plant, db_name) # db_name仅用于命名xlsx文件,是字符串 return response else: # 处理其他POST请求的逻辑
现在我不想手动指定模型类,希望通过表单提交的database参数动态获取对应的模型类,然后传入xlsx_generator实现下载,请问能不能做到?具体怎么实现?
解决方案
完全可以实现,核心是通过模型名称到模型类的白名单映射来安全地动态获取模型,避免直接使用用户输入带来的安全风险,步骤如下:
1. 创建模型白名单映射
在views.py中,先导入所有需要支持下载的模型,然后创建一个字典,将模型名称(字符串)和对应的模型类关联起来:
from database.models import Plant, Animal, Product # 导入所有需要支持的模型 # 模型白名单:仅允许列表内的模型被下载 MODEL_MAP = { 'Plant': Plant, 'Animal': Animal, 'Product': Product, }
2. 修改视图逻辑
在download_file函数中,从POST参数获取模型名称,然后从白名单字典中取出对应的模型类,再传入xlsx_generator:
def download_file(request, filename=''): if 'downloadfile' in request.POST: db_name = request.POST.get('database') # 从白名单中获取模型类,若不存在则返回错误或默认处理 model_class = MODEL_MAP.get(db_name) if not model_class: # 处理无效模型名称的情况,比如返回400错误 return HttpResponseBadRequest("Invalid model name") response = xlsx_generator(model_class, db_name) return response else: # 处理其他POST请求的逻辑
3. 扩展表单支持多模型
如果要支持其他模型的下载,只需要复制原表单,修改隐藏字段的value和按钮文字即可:
<!-- 下载Animal模型的表单 --> <form id="download-animal" method="post" action="{% url 'download_file' filename='Irrelevant.xlsx'%}"> {% csrf_token %} <input type="hidden" value="Animal" name="database" /> <input type="submit" name="downloadfile" class="btn btn-success" value="Download Animal"> </form> <!-- 下载Product模型的表单 --> <form id="download-product" method="post" action="{% url 'download_file' filename='Irrelevant.xlsx'%}"> {% csrf_token %} <input type="hidden" value="Product" name="database" /> <input type="submit" name="downloadfile" class="btn btn-success" value="Download Product"> </form>
关键安全提示
不要直接使用django.apps.get_model()来解析用户输入的模型名称(比如get_model('database', db_name)),这种方式存在安全风险——恶意用户可以构造输入来访问你不想开放的模型。通过手动维护白名单字典,能严格控制允许下载的模型范围。
内容的提问来源于stack exchange,提问作者Rivered
相关产品推荐
相关产品推荐

