首页 > 解决方案 > 各种动态django表单集抛出missing_management_form错误

问题描述

当我动态构建多个表单集时,我在验证 django 表单集时遇到问题在这种情况下,一个客户可能是各种品牌并联系人们。

模型.py

class Client(ChangesMixin, models.Model):
  name = models.CharField(verbose_name="Nombre", max_length=100, unique=True)
  code = models.PositiveIntegerField(verbose_name="Código", blank=True)

  class Meta:
    verbose_name = "Cliente"
    verbose_name_plural = "Clientes"

class Brand(ChangesMixin, models.Model):
  name = models.CharField(verbose_name="Marca", max_length=100, blank=True, null=True)
  client = models.ForeignKey('Client', verbose_name="Cliente", related_name='brand_client', on_delete=models.DO_NOTHING)

  class Meta:
    verbose_name = "Marca"
    verbose_name_plural = "Marcas"

 class Contact(ChangesMixin, models.Model):
   name = models.CharField(verbose_name="Contacto", max_length=100, blank=True, null=True)
   client = models.ForeignKey('Client', verbose_name="Cliente", related_name='contact_client', on_delete=models.DO_NOTHING)

   class Meta:
     verbose_name = "Contacto"
     verbose_name_plural = "Contactos"

我有两种动态创建表单和表单集的方法

表格.py

def get_custom_formset(entry_model=None, entry_fields=None, action=None):

  formset = None

  if action == 'create':
    extra = 1
  else:
    extra = 0

  formset = modelformset_factory(
    model = entry_model,
    extra = extra,
    form = get_custom_form(entry_model, entry_fields, action)

  return formset

def get_custom_form(entry_model=None, entry_fields=None, action=None):

  class _CustomForm(forms.ModelForm):

    class Meta:
      model = entry_model
      fields = [field.name for field in entry_fields]

    def __init__(self, *args, **kwargs):
      """
      """
      super(_CustomForm, self).__init__(*args, **kwargs)
      instance = getattr(self, 'instance', None)
      if instance and instance.pk:
        for field in entry_fields:
          if action == 'detail':
            self.fields[field.name].widget.attrs['readonly'] = True

  return _CustomForm

我有一个带有 get 和 post 方法的创建类视图,取决于传递的模型。我得到模型字段来构建表单,如果一个字段是外键,我用这些具体模型构建表单集。

视图.py

class CustomCreateView(LoginRequiredMixin, View, PermissionRequiredMixin):
  model = None
  template = 'create.html'

  def get(self, request, *args, **kwargs):
    template_form = str(self.model._meta.verbose_name).lower() + "_form.html"
    model_fields = self.model._meta.get_fields()

    form = None
    formset = None
    formsets = {}

    for main_field in model_fields:
      main_field_name = main_field.__class__.__name__
      if main_field_name == 'ManyToOneRel':
        model_names = str(main_field.name).split("_")
        submodel = apps.get_model('app', model_names[0])
        submodel_fields = submodel._meta.get_fields()
        formset = app_forms.get_custom_formset(submodel, submodel_fields, 'create')
        queryset = submodel.objects.none()

        UPDATED with SOLUTION
        formset = formset(queryset=queryset, prefix=submodel.__name__.lower())
        formsets[submodel._meta.verbose_name.lower()] = formset

      elif main_field_name == 'ManyToManyField':
        print("NOT PROVIDED YET")

      form = app_forms.get_custom_form(self.model, model_fields, 'create')
      form = form(prefix=self.model.__name__.lower())

    return render(request, self.template, {
        'form': form,
        'formsets': formsets,
        'template_form': template_form,
    })

  def post(self, request, *args, **kwargs):
    template_form = str(self.model._meta.verbose_name).lower() + "_form.html"
    model_fields = self.model._meta.get_fields()

    for main_field in model_fields:
      main_field_name = main_field.__class__.__name__

      if main_field_name == 'ManyToOneRel':
        model_names = str(main_field.name).split("_")
        submodel = apps.get_model('app', model_names[0])
        submodel_fields = submodel._meta.get_fields()
        formset = app_forms.get_custom_formset(submodel, submodel_fields, 'create')
        queryset = submodel.objects.none()
        formset = formset(queryset=queryset, prefix=submodel.__name__.lower())
        formsets[submodel.__name__.lower()] = formset

      elif main_field_name == 'ManyToManyField':
        print("NOT PROVIDED YET")

    form = app_forms.get_custom_form(self.model, model_fields, 'create')
    form = form(request.POST, prefix=self.model.__name__.lower())

    for prefix, formset in formsets.items():
      formset = formset.__class__(request_post, prefix=prefix)
      if formset.is_valid() and form.is_valid(): HERE THROWS THE ERROR

对于模板,我有 3 个级别来动态构建表单和表单集

创建.html

{% get_url urls 'create' as element_create %}
<form class="" action="{% url element_create %}" method="POST">
  {% csrf_token %}
  {% include template_form %}
  {% if formsets|length > 0 %}
    {% for subtemplateformname, formset in formsets.items %}
      {% include 'formset.html' %}
    {% endfor %}
  {% endif %}
</form>

表单集.html

{{ formset.management_form }}
{% for form in formset %}
  {% for hidden in form.hidden_fields %}
    {{ hidden }}
  {% endfor %}
  {% include 'form.html' %}
{% endfor %}

表单.html

{% load widget_tweaks %}

{% for field in form %}
  <div class="form-group{% if field.errors %} has-error{% endif %}">
    <label for="{{ field.id_for_label }}">{{ field.label }}</label>
    {{ field|add_class:"form-control" }}
    {% for error in field.errors %}
      <p class="help-block">{{ error }}</p>
    {% endfor %}
  </div>
{% endfor %}

标签: djangoformset

解决方案


首先,当您获得相关模型的表单集时,您会通过sub_fields但我不知道这是从哪里来的?

formset = app_forms.get_custom_formset(submodel, sub_fields, 'create')

错误在于您定义表单集前缀的方式。在您传递的 GET 中model_names[0],对于正常的关系,模型名称将是小写的,没有任何空格。让我们使用一个名为MyModel例如的模型

main_field.name  # 'mymodel_set'
model_names = str(main_field.name).split("_")  # ['mymodel', 'set']
model_names[0]  # 'mymodel'
formset = formset(queryset=queryset, prefix=model_names[0])

当您将表单集分配给formsets字典时,您使用的是不同的东西,即使您对待它是一样的

formsets[submodel._meta.verbose_name.lower()] = formset
...
for prefix, formset in formsets.items():
    formset = formset.__class__(request_post, prefix=prefix)

submodel._meta.verbose_name将返回带有空格的模型名称。因此,任何在其详细名称中包含 2 个“单词”的模型都不会设置正确的前缀(例如MyModel._meta.verbose_name.lower() == 'my model'but model_names[0] == 'mymodel'


推荐阅读