提交表单时 Django ImageField 未更新

发布于 2025-01-17 06:04:21 字数 4801 浏览 3 评论 0原文

问题描述

我有一个模型,它描述了用户配置文件和一个专用表单,以允许用户更新模型。除了 photo(ImageField) 之外,一切正常。 photo 字段的问题是 EditProfileForm 根本没有更改图像。换句话说,在表单提交之前和之后,我在该字段中附加了相同的图像,photo 指向同一张图片,并且没有任何新内容上传到服务器。 值得注意的是,photo 字段是通过管理面板中的表单进行操作的。 与 UserProfileUser 相关的其他字段没有问题:所有这些字段都可以更新,并且更新保存在数据库中。

环境详细信息

目前,我使用 Django 4.0.3 版本,运行 DEBUG=True 并构建在开发服务器中。

代码

### Models
def get_image_save_path(
        instance,
        filename:str
        ) -> str:
    save_dir = instance.__class__.__name__
    file_name = uuid.uuid4().hex
    file_extension = pathlib.Path(filename).suffix
    return f"{save_dir}/{file_name}{file_extension}".lower()

def validate_image_size(image):
    if not image:
        raise ValidationError("No image found")
    if image.size > 512*1024:
        raise ValidationError("Max size is 512kb")

class UserProfile(models.Model):
    user = models.OneToOneField(User,
                                on_delete=models.CASCADE,
                                related_name='user_profile',
                                primary_key=True)
    photo = models.ImageField(upload_to=get_image_save_path,
                                    verbose_name="Photo", 
                                    validators=[validate_image_size],
                                    default="userprofile/default_photo.jpg",
                                    null=False,
                                    blank=False)
    bio = models.TextField(default='', blank=True)

    def __str__(self):
        return f"{self.user.username}"

@receiver(post_save, sender=User)
def create_user_profile(
        sender:ModelBase,
        instance:User,
        created:bool,
        **kwargs:Dict) -> None:
    if created:
        UserProfile.objects.create(user=instance)
    else:
        return

@receiver(post_save, sender=User)
def save_user_profile(
    sender: ModelBase,
    instance: User,
    **kwargs: Dict) -> None:
    instance.user_profile.save()
### Forms
class EditUserForm(ModelForm):
    class Meta:
        model = User
        fields = ('first_name', 'last_name', 'email')

class EditProfileForm(ModelForm):
    photo = ImageField(widget=FileInput(attrs={'class': 'form-control-file'}))
    class Meta:
        model = UserProfile
        fields = ('photo', 'bio')
### Views
@login_required
def profile_view(request):
    return render(request, 
                    template_name="accounts/profile_view.html",
                    context = {})

@login_required
def profile_edit(request):
    if request.method == 'POST':
        userForm = EditUserForm(data=request.POST, instance=request.user)
        profileForm = EditProfileForm(data=request.POST, 
                                      files=request.FILES, 
                                      instance=request.user.user_profile)
        if userForm.is_valid() and profileForm.is_valid():
            profileForm.save()
            userForm.save()
            return redirect('accounts_app:profile_view')
    else:
        userForm = EditUserForm(instance=request.user)
        profileForm = EditProfileForm(instance=request.user.user_profile)
        context = {"userForm": userForm, "profileForm": profileForm, }
        return render(request, 'accounts/edit_profile.html', context)
### Template
{% block content %}
<div class="row">
  <div class="panel panel-primary panel-login rounded-lg">
    <div class="panel-body">
      <form class="" action="" method="POST">
        {% csrf_token %}
        {% for field in userForm %}
        <p>
          {{ field.label_tag }}<br>
          {{ field }}
          {% if field.help_text %}
            <small style="color: grey">{{ field.help_text }}</small>
          {% endif %}
          {% for error in field.errors %}
            <p style="color: red">{{ error }}</p>
          {% endfor %}
        </p>
        {% endfor %}

        {% for field in profileForm %}
        <p>
          {{ field.label_tag }}<br>
          {{ field }}
          {% if field.help_text %}
            <small style="color: grey">{{ field.help_text }}</small>
          {% endif %}
          {% for error in field.errors %}
            <p style="color: red">{{ error }}</p>
          {% endfor %}
        </p>
        {% endfor %}
      <button class="btn btn-danger standard-btn" type="submit">Zapisz zmiany</button>
      </form>
    </div>
  </div>
</div>
{% endblock %}

问题

我在代码中做错了什么,导致 photo 字段出现并描述了问题?

Issue describrion

I have a model which describes a UserProfile and a dedicated form to allow user to update the model. Except photo(ImageField), everything is working fine. Issue with photo field is that the image is not being changed at all with EditProfileForm. In other words I have same image attached to this field before and after form submition, the photo is pointing to the same picture, and nothing new was uploaded to the server.
It is worth to be noted that photo field is working through the form from admin panel.
No issues with other fields related to UserProfile and User: all of them can be updated, and the update is saved in database.

Environment details

For a time being I am using Django in version 4.0.3 running with DEBUG=True and build in development server.

Code

### Models
def get_image_save_path(
        instance,
        filename:str
        ) -> str:
    save_dir = instance.__class__.__name__
    file_name = uuid.uuid4().hex
    file_extension = pathlib.Path(filename).suffix
    return f"{save_dir}/{file_name}{file_extension}".lower()

def validate_image_size(image):
    if not image:
        raise ValidationError("No image found")
    if image.size > 512*1024:
        raise ValidationError("Max size is 512kb")

class UserProfile(models.Model):
    user = models.OneToOneField(User,
                                on_delete=models.CASCADE,
                                related_name='user_profile',
                                primary_key=True)
    photo = models.ImageField(upload_to=get_image_save_path,
                                    verbose_name="Photo", 
                                    validators=[validate_image_size],
                                    default="userprofile/default_photo.jpg",
                                    null=False,
                                    blank=False)
    bio = models.TextField(default='', blank=True)

    def __str__(self):
        return f"{self.user.username}"

@receiver(post_save, sender=User)
def create_user_profile(
        sender:ModelBase,
        instance:User,
        created:bool,
        **kwargs:Dict) -> None:
    if created:
        UserProfile.objects.create(user=instance)
    else:
        return

@receiver(post_save, sender=User)
def save_user_profile(
    sender: ModelBase,
    instance: User,
    **kwargs: Dict) -> None:
    instance.user_profile.save()
### Forms
class EditUserForm(ModelForm):
    class Meta:
        model = User
        fields = ('first_name', 'last_name', 'email')

class EditProfileForm(ModelForm):
    photo = ImageField(widget=FileInput(attrs={'class': 'form-control-file'}))
    class Meta:
        model = UserProfile
        fields = ('photo', 'bio')
### Views
@login_required
def profile_view(request):
    return render(request, 
                    template_name="accounts/profile_view.html",
                    context = {})

@login_required
def profile_edit(request):
    if request.method == 'POST':
        userForm = EditUserForm(data=request.POST, instance=request.user)
        profileForm = EditProfileForm(data=request.POST, 
                                      files=request.FILES, 
                                      instance=request.user.user_profile)
        if userForm.is_valid() and profileForm.is_valid():
            profileForm.save()
            userForm.save()
            return redirect('accounts_app:profile_view')
    else:
        userForm = EditUserForm(instance=request.user)
        profileForm = EditProfileForm(instance=request.user.user_profile)
        context = {"userForm": userForm, "profileForm": profileForm, }
        return render(request, 'accounts/edit_profile.html', context)
### Template
{% block content %}
<div class="row">
  <div class="panel panel-primary panel-login rounded-lg">
    <div class="panel-body">
      <form class="" action="" method="POST">
        {% csrf_token %}
        {% for field in userForm %}
        <p>
          {{ field.label_tag }}<br>
          {{ field }}
          {% if field.help_text %}
            <small style="color: grey">{{ field.help_text }}</small>
          {% endif %}
          {% for error in field.errors %}
            <p style="color: red">{{ error }}</p>
          {% endfor %}
        </p>
        {% endfor %}

        {% for field in profileForm %}
        <p>
          {{ field.label_tag }}<br>
          {{ field }}
          {% if field.help_text %}
            <small style="color: grey">{{ field.help_text }}</small>
          {% endif %}
          {% for error in field.errors %}
            <p style="color: red">{{ error }}</p>
          {% endfor %}
        </p>
        {% endfor %}
      <button class="btn btn-danger standard-btn" type="submit">Zapisz zmiany</button>
      </form>
    </div>
  </div>
</div>
{% endblock %}

Question

What I did wrong in the code, that is causing and described issue with photo field?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

久伴你 2025-01-24 06:04:21

请尝试使用 multipart/form-data

任何元素时,

当您的表单包含模板中的

  <form class="" action="" method="POST" enctype="multipart/form-data">

try this

use multipart/form-data when your form includes any elements

in templates

  <form class="" action="" method="POST" enctype="multipart/form-data">
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文