在django中替换文件

在django中替换文件,django,django-forms,Django,Django Forms,我有一个标准表单来编辑一个包含文件字段的对象。当我添加一个新的配置文件时,一切正常,但当我想修改一个字段时,就会出现问题:当我不包括request.FILES时,所有字段都会在表单中检索,并且可以毫无问题地更新,除了化身(filefield),但是当我添加request.FILES时,输入中不再检索字段,而且表格无效。我做错了什么 models.py: from django.db import models class Profile(models.Model): name = mo

我有一个标准表单来编辑一个包含文件字段的对象。当我添加一个新的配置文件时,一切正常,但当我想修改一个字段时,就会出现问题:当我不包括request.FILES时,所有字段都会在表单中检索,并且可以毫无问题地更新,除了化身(filefield),但是当我添加request.FILES时,输入中不再检索字段,而且表格无效。我做错了什么

models.py:

from django.db import models

class Profile(models.Model):
    name = models.CharField(max_length=45)
    email = models.EmailField()
    avatar = models.FileField(upload_to="avatars/")

    def __str__(self):
        return self.name
forms.py:

from django import forms
from .models import Profile

class EditUserForm(forms.ModelForm):
    class Meta:
        model = Profile
        fields = ["name", "email", "avatar"]
profile.html:

<form method="POST">
        {% csrf_token %}
        <div class="col-md-12">
          <div class="row border m-3 p-5">
            <div class="col-md-6">Name</div>
            <div class="col-md-6">{{ form.name }}</div>
          </div>
          <div class="row border m-3 p-5">
            <div class="col-md-6">Email</div>
            <div class="col-md-6">{{ form.email }}</div>
          </div>
          <div class="row border m-3 p-5">
            <div class="col-md-6">Avatar</div>
            <div class="col-md-6">
              <img src="{{ profile.avatar.url }}" width="100rem" />
              {{ form.avatar }}
            </div>
          </div>
          <div class="row">
            <button type="submit" class="btn btn-success">Save</button>
          </div>
        </div>
      </form>

尝试如下重构代码:(如果我遗漏了什么,请编辑它。form.is_有效后,应在上下文中发送相同的表单以显示错误

def profile(request, pk):
    profile_instance = Profile.objects.get(id=pk)
    form = EditUserForm(instance = profile_instance)
    if request.method == "POST":
        form = EditUserForm(request.POST, request.FILES, instance = profile_instance)
        if form.is_valid():
            profile = form.save(commit=False)
            profile.save()
            form = EditUserForm(instance = profile_instance)

   context = {
        'profile': profile_instance,
        'form': form,
    }

    return render(request, "app/profile.html", context)

特别感谢@bruno desthuilliers和@dirkgroten。 以下是解决这两个问题的答案:

def profile(request, pk):
    if request.method == 'POST':
        form = EditUserForm(request.POST, request.FILES, instance = Profile.objects.get(id=pk))
        if form.is_valid():
            profile = form.save(commit=False)
            profile.save()
            return redirect('profile', pk)
    else:
        form = EditUserForm(instance = Profile.objects.get(id=pk))
    context = {
        'profile': Profile.objects.get(id=pk),
        'form': form,
    }
    return render(request, "app/profile.html", context)

首先,您需要将(html)表单的enctype设置为“multipart/form data”(cf),否则
request.FILES
将为空。然后您希望在模板中实际显示表单的验证错误。最后,您应该始终在成功发布后重定向(post redirect get pattern)为了防止重复提交。它现在正在工作,谢谢。不,我的代码中已经有enctype,但问题是返回渲染,我将其更改为重定向,它工作了。但是,前两个字段(名称和电子邮件)未在表单中填充。如果是
GET
请求,则不应使用数据实例化表单。这是因为如果传递数据(通过传入
request.POST
)并且数据为空,您的表单被绑定,初始值被设置为数据值。请完全按照如下所示操作:实例化
EditUserForm(实例=…)
如果是
获取
请求。并且仅在有效表单的情况下重定向。包含使正确的基于函数的视图处理表单所需的确切代码。此答案不正确,因为当表单成功提交时,它不会重定向。即使表单位于同一视图,也应始终重定向。
def profile(request, pk):
    if request.method == 'POST':
        form = EditUserForm(request.POST, request.FILES, instance = Profile.objects.get(id=pk))
        if form.is_valid():
            profile = form.save(commit=False)
            profile.save()
            return redirect('profile', pk)
    else:
        form = EditUserForm(instance = Profile.objects.get(id=pk))
    context = {
        'profile': Profile.objects.get(id=pk),
        'form': form,
    }
    return render(request, "app/profile.html", context)