如何预填充 Django 更新表单并将其写回数据库

Posted

技术标签:

【中文标题】如何预填充 Django 更新表单并将其写回数据库【英文标题】:How to prepopulate an Django Update form and write it back to the database 【发布时间】:2017-04-25 13:09:08 【问题描述】:

我是 Python 和 Django 的新手,目前正在苦苦挣扎。 我使用 Django 模型表单创建了一个更新/编辑表单,但它只是没有预先填充表单字段并将其同时发布到数据库。

我认为问题出在form = AdvertForm(request.POST or None, request.FILES or None, instance=form)

没有request.POST or None, request.FILES or None,它会预填充字段但不会将数据更新到数据库。

这是我的views.py

def update_advert(request, id):
if not request.user.is_authenticated():
    return render(request, 'forum/login.html')
else:
    form = get_object_or_404(Advert, pk=id)
    if request.method == 'POST':
        form = AdvertForm(request.POST or None, request.FILES or None, instance=form)
        if form.is_valid():
            form = form.save(commit=False)
            form.user = request.user
            form.save()
            return redirect('forum:user_account')
    else:
        form = AdvertForm(instance=form) 


    context = 'form': form
    return render(request, 'forum/update_advert.html', context)

在它看起来像这样的那一刻,当我尝试打开更新表单时:

opening the form --> not prepopulated :(

【问题讨论】:

这是答案:::: link 【参考方案1】:

根据https://docs.djangoproject.com/en/dev/ref/forms/api/#dynamic-initial-values,您可以在实例化表单时使用initial 属性来预填充您的表单。

def update_advert(request, id):
    if not request.user.is_authenticated():
        return render(request, 'forum/login.html')
    else:
        advert_obj = get_object_or_404(Advert, pk=id)


        if request.method == 'POST':
            form = AdvertForm(request.POST or None, request.FILES or None, instance=advert_obj)
            if form.is_valid():
                form.save()
                return redirect('forum:user_account')
        else:
            # Prepopulation happens here:
            data = "some_field": advert_obj.some_val # Insert all the values of advert_obj here and their field names as keys.
            form = AdvertForm(initial=data) 


        context = 'form': form
        return render(request, 'forum/update_advert.html', context)

在您的AdvertForm 中,输入以下代码:

class AdvertForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        self.request = kwargs.pop('request', None)
        super(AdvertForm, self).__init__(*args, **kwargs)

    def save(self, commit=True):
        instance = super(AdvertForm, self).save(commit=False)
        instance.user = self.request.user

        if commit:
            instance.save()
        return instance

覆盖save 方法只是执行您在视图中所做的操作,将request.user 链接到实例,但是我已将该代码放在表单类中以保持您的views 简单。

另外,我可以看到一个令人困惑(但不是重要)的问题 - 您混淆了变量名称。 当调用form = get_object_or_404(Advert, pk=id) 时,这应该返回一个变量名,例如advert 或类似的名称。不是form,因为我们返回的是模型对象而不是表单,这可能会造成混淆。同样,form.save(commit=False) 返回一个“实例”而不是模型表单。这不会解决您的问题,但应该指出以进一步澄清返回的确切内容以及您应该如何命名变量。

【讨论】:

谢谢。这真的帮助我更好地理解我的代码!但它仍然没有显示预填充的字段 "request.POST or None, request.FILES or None "... 当我只是这样: "form = AdvertForm( instance=advert_obj)" 它会向我显示预填充的字段,但不会将其写回数据库... 您能解释一下您所说的“表演”是什么意思吗?当您发出POST 请求时运行的代码form = AdvertForm(request.POST or None, request.FILES or None, instance=advert_obj) 应该更新当前的advert_obj。它不会再次显示这些字段,因为您正在重定向到 forum:user_account else 子句(当您发出GET 请求时)会将数据预填充到您提到的表单字段中。这工作正常。但是那部分根本不应该保存到数据库中,因为我们只是在检索数据。 POST 请求负责保存(在您的情况下,更新当前的advert_obj

以上是关于如何预填充 Django 更新表单并将其写回数据库的主要内容,如果未能解决你的问题,请参考以下文章

如何根据先前的用户选择在 Django 中预填充(多个)ChoiceField

music21:读取 MIDI 文件的 BPM 和乐器信息并将其写回文件

基于 Web 请求预填充 Django 表单

预填充 Django(非模型)表单

Django:ModelForm 使用自定义查询预填充复选框

使用 Django 从数据库预填充 HTML 表单表