如何在Django Admin中提交并存储两个关联模型表单的数据?
解决Django Admin嵌入关联模型表单提交问题
要让嵌入的RateCategoryGroup表单数据被提交并保存,需要修改FeeEarnerProfileAdmin的提交处理逻辑,同时调整模板确保表单能正常参与提交流程,具体步骤如下:
1. 修改Admin的change_view方法处理POST请求
在change_view中,优先处理POST请求里的RateCategoryGroupForm数据,验证通过后保存,再交由父类处理FeeEarnerProfile的保存逻辑:
class FeeEarnerProfileAdmin(VersionAdmin): change_form_template = "admin/organizations/fee_earner_profile/change_form.html" def change_view(self, request, object_id, form_url="", extra_context=None): # 获取关联的RateCategoryGroup实例 rate_category_group_instance = RateCategoryGroup.objects.get( group_memberships__membership__fee_earner_profile__id=object_id ) # 处理POST请求中的RateCategoryGroup表单数据 if request.method == "POST": rate_category_group_form = RateCategoryGroupForm( request.POST, instance=rate_category_group_instance ) if rate_category_group_form.is_valid(): rate_category_group_form.save() else: # GET请求时正常初始化表单 rate_category_group_form = RateCategoryGroupForm(instance=rate_category_group_instance) # 将表单传入上下文 extra_context = extra_context or {} extra_context["rate_category_group_form"] = rate_category_group_form # 调用父类方法处理FeeEarnerProfile的保存 return super().change_view( request, object_id, form_url, extra_context=extra_context )
2. 调整模板确保表单参与提交流程
直接渲染表单可能缺少CSRF令牌或无法和原Admin表单共用提交按钮,分两种场景处理:
场景1:单独提交关联表单
给嵌入的表单添加独立提交按钮,需要手动加入CSRF令牌:
{% extends "admin/change_form.html" %} {% load i18n admin_urls static admin_modify %} {% block content %} {{ block.super }} <hr> <h2>Rate Category Group</h2> <form method="post"> {% csrf_token %} {{ rate_category_group_form.as_p }} <input type="submit" value="保存分组修改" class="default"> </form> {% endblock %}
场景2:和原表单共用提交按钮
将关联表单的字段嵌入原Admin的<form>标签内,点击原"保存"按钮即可同时提交两个模型的数据:
{% extends "admin/change_form.html" %} {% load i18n admin_urls static admin_modify %} {% block content %} {% block form_top %}{% endblock %} <div class="module aligned"> {% block field_sets %} {{ block.super }} {% endblock %} <!-- 嵌入RateCategoryGroup表单字段到原表单中 --> <h2>Rate Category Group</h2> {% for field in rate_category_group_form %} <div class="form-row"> {{ field.label_tag }} {{ field }} {% if field.help_text %} <p class="help">{{ field.help_text|safe }}</p> {% endif %} {% for error in field.errors %} <p class="error">{{ error }}</p> {% endfor %} </div> {% endfor %} </div> {% block submit_buttons_bottom %}{{ block.super }}{% endblock %} {% endblock %}
3. 可选:添加表单前缀避免字段冲突
如果两个模型存在同名字段,初始化表单时添加prefix参数区分:
# 在change_view中初始化表单时 rate_category_group_form = RateCategoryGroupForm( request.POST if request.method == "POST" else None, instance=rate_category_group_instance, prefix="rate_group" )
注意事项
- 确保
RateCategoryGroupForm包含所有需要编辑的字段,且当前用户有修改RateCategoryGroup的权限。 - 如果关联的
RateCategoryGroup实例可能不存在,需要捕获DoesNotExist异常,补充创建实例的逻辑。 - 此方法确实不属于Django Admin的最佳实践,更推荐使用
InlineModelAdmin,但针对需求可实现功能。
内容的提问来源于stack exchange,提问作者Pete Dermott
相关产品推荐
相关产品推荐

