Django ImageField не обновляется при отправке формы

Описание выпуска

У меня есть модель, которая описывает UserProfile и специальная форма, позволяющая пользователю обновлять модель. За исключением photo (ImageField), все работает нормально. Проблема с полем photo заключается в том, что изображение не изменяется вообще при EditProfileForm. Другими словами, у меня есть одно и то же изображение, прикрепленное к этому полю до и после отправки формы, photo указывает на то же самое изображение, и ничего нового не было загружено на сервер. Стоит отметить, что поле photo работает через форму из админ панели. С другими полями, относящимися к UserProfile и User, проблем нет: все они могут быть обновлены, и обновление сохраняется в базе данных.

Подробности об окружающей среде

<

На данный момент я использую Django версии 4.0.3, запущенный с

и собранный на сервере разработки.
### 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?

попробуйте это

используйте multipart/form-data, если ваша форма включает в себя какие-либо элементы

в шаблонах

  <form class="" action="" method="POST" enctype="multipart/form-data">
Вернуться на верх