Django ModelChoiceField 编辑时未填写

Django ModelChoiceField is not filled when editing

我有一个 ProjectForm 表单,其中一个字段是带有公司模型外键的 ModelChoiceField。创建新记录并保存不是问题,但是当我想编辑该记录时,这个字段是空的(比如如果选择了 none 公司,但在数据库中我可以通过正确的选择看到它),其他字段被填充正确。

我想尽可能避免更改模板代码,因此它由通用表单模板生成。

-----models.py-----

class Company(models.Model):
    name = models.CharField(max_length=250, unique=True)
    ...

class Project(models.Model):
    company = models.ForeignKey(Company, on_delete=models.SET_NULL, null=True, blank=True)
    name = models.CharField(max_length=250, blank=False)
    description = models.TextField()
    ...

-----forms.py-----

@parsleyfy
class ProjectForm(forms.Form):
    company = forms.ModelChoiceField(label='Společnost', queryset=Company.objects.all(), required=False)
    name = forms.CharField(label='Název')
    ...

-----view.py-----

def edit(request, pk):
    context = {'form_url': reverse('projects:project-edit', args=(pk,)),
               'form_type':'edit'}

    obj = get_object_or_404(Project, pk=pk)
    if request.method == "GET":
        form = ProjectForm(initial=obj.__dict__)
    else:
        form = ProjectForm(request.POST, request.FILES)
        if form.is_valid():
            try:
                obj.update(**form.cleaned_data)
            except IntegrityError:
                errors = form._errors.setdefault("name", ErrorList())
                errors.append(u"Toto jméno již existuje")
            else:
                return redirect(LIST_URL) # SUCCESSFULLY SAVED

    context['form'] = form
    return render(request, FORM_TEMPLATE, context)

-----template.html-----

        <form  role="form" action="{{ form_url }}" method="post" enctype="multipart/form-data"
               data-parsley-validate novalidate>
            {% include 'projects/reusable/form_template.html' %}
        </form>

in which:
    {% elif field|input_type == 'Select' %}
        <div for="{{ field.label }}" class="col-sm-2 col-form-label">
            {{ field.label_tag }}
        </div>
        <div class="col-sm-10">
            {{ field|add_classes:'form-control'}}
            {% if field.help_text %}
                <small class="form-text text-muted">{{ field.help_text }}</small>
            {% endif %}
        </div>

-----数据库截图-----

----- 表格截图-----(第一个输入是公司)

initial=obj.__dict__ 将 return project 字典与

{
  ...
  company_id: value
} 

在您的表单中,您将字段名称定义为 company。因此,您需要使用与 company_id 相同的值更新您的表单 initial,这样 company 字段将被正确填充

{
  company: value
}

使用 model_to_dict 可以显式删除不可编辑的字段,检查并获取外键的 ids,你可以阅读更多关于它的源代码,因为没有很好的文档.

def model_to_dict(instance, fields=None, exclude=None):
    """
    Return a dict containing the data in ``instance`` suitable for passing as
    a Form's ``initial`` keyword argument.
    """
    pass


from django.forms.models import model_to_dict

# model_to_dict will handle 'special' fields properly
form = ProjectForm(initial=model_to_dict(obj))

根据@minglyu回答,我添加了代码解决方案

-----forms.py-----

@parsleyfy
class ProjectForm(forms.Form):
    company = forms.ModelChoiceField(label='Společnost', queryset=Company.objects.all(), required=False)
    name = forms.CharField(label='Název')
    ...

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        if 'initial' in kwargs.keys():
            self.initial['company'] = kwargs['initial']['company_id']

-----views.py-----

from django.forms import models
...

def edit(request, pk):
    ...
    obj = get_object_or_404(Project, pk=pk)
    if request.method == "GET":
        form = ProjectForm(initial=models.model_to_dict(obj))
    ...