Изображение по умолчанию в Django не сохраняется

У меня проблема с сохранением изображения по умолчанию, когда я не загружаю изображение в ImageField. Я не могу понять, что я делаю неправильно, для меня вроде бы все в порядке, но я не могу найти, где ошибка.

models.py

class Student(models.Model):
    user = models.OneToOneField(CustomUser, on_delete=models.CASCADE)
    date_of_birth = models.DateField()
    fiscal_code = models.CharField(max_length=50)
    phone = models.CharField(max_length=50)
    license = models.ForeignKey(
        License, on_delete=models.CASCADE, blank=True, null=True)
    picture = models.ImageField(
        blank=True, null=True, default='default.png')
    id_card = models.ForeignKey(
        IDCard, on_delete=models.CASCADE, blank=True, null=True)
    address = models.CharField(max_length=100)
    cap = models.CharField(max_length=10)
    city = models.CharField(max_length=100)
    province = models.CharField(max_length=100)
    country = models.CharField(max_length=100)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

views.py

def create_student(request):
    context = {

    }
    if request.method == 'POST':
        username = request.POST.get('username')
        first_name = request.POST.get('first_name')
        last_name = request.POST.get('last_name')
        date_of_birth = request.POST.get('date_of_birth')
        email = request.POST.get('email')
        phone = request.POST.get('phone')
        password = request.POST.get('password')
        address = request.POST.get('address')
        cap = request.POST.get('cap')
        province = request.POST.get('province')
        country = request.POST.get('country')
        fiscal_code = request.POST.get('fiscal_code')
        id_number = request.POST.get('id_number')
        expire_date = request.POST.get('expire_date')
        picture = request.FILES.get('picture')
        id_image = request.FILES.get('id_image')

        # fs = FileSystemStorage()
        # filename = fs.save(picture.name, picture)
        # profile_pic_url = fs.url(filename)
        # filename2 = fs.save(id_image.name, id_image)
        # id_image_url = fs.url(filename2)

        try:
            user = CustomUser.objects.create_user(
                username=username, password=password, email=email, last_name=last_name, first_name=first_name, user_type=3)
            user.student.address = address
            user.student.date_of_birth = date_of_birth
            user.student.cap = cap
            user.student.province = province
            user.student.country = country
            user.student.phone = phone
            user.student.fiscal_code = fiscal_code

            user.student.picture = picture

            user.save()

            id_card = IDCard.objects.create(
                number=id_number, expire_date=expire_date, picture=id_image)
            id_card.save()

            messages.success(request, "Successfully Added Student")
            return HttpResponseRedirect(reverse('user:student_list'))
        except:
            messages.error(request, "Failed to Add Student")
            return HttpResponseRedirect(reverse('user:create_student'))

    return render(request, 'user/create_student.html', context)

settings.py

STATIC_URL = '/static/'
STATICFILES_DIRS = [
    BASE_DIR / 'static',
]
MEDIA_URL = '/media/'
MEDIA_ROOT = BASE_DIR / 'media'

urls.py

urlpatterns = [
    path('', include('user.urls')),
    path('admin/', admin.site.urls),
    path('student/', include('student.urls')),
    path('instructor/', include('instructor.urls')),
]

urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
<

Вы сохраняете только User объект, а не Student один.

views.py:

...
    user.student.picture = picture

    user.save()
    user.student.save()    # this will save student object to databse

    id_card = IDCard.objects.create(
        number=id_number, expire_date=expire_date, picture=id_image)
    id_card.save()    # this line does nothing, because object is saved in create() function
...

Другое дело, что вам, вероятно, не следует позволять Django сохранять изображение как None.

models.py:

class Student(models.Model):
    ...
    picture = models.ImageField(
        blank=True, null=False, default='default.png')
    ...

Первоначально

  1. Убедитесь, что в вашем медиафайле есть default.png

  2. В вашем представлении вы получаете файл изображения, но он может быть нулевым, а также ваша модель позволяет изображению быть нулевым, в этом случае вы должны проверить, является ли изображение файла запроса нулевым или нет.

picture = request.FILES.get('picture', None)
# Allowing null check
# Remove user.student.picture = picture and use the following
if picture:
    user.student.picture = picture

То же самое для вашего id_image

id_image = request.FILES.get('id_image', None)
#...
# I assume id_image will also use default
id_card = IDCard(number=id_number, expire_date=expire_date, )
if id_image:
   id_card.picture=id_image
id_card.save()

Я думаю, что недоразумение заключается в значении "по умолчанию": Значение поля по умолчанию применяется только один раз в момент инстанцирования! Не тогда, когда экземпляр изменяется или сохраняется.

Я пытаюсь понять, что происходит, потому что некоторый код отсутствует, чтобы быть уверенным:

вы создаете CustomUser и вызываете метод create_user().

    user = CustomUser.objects.create_user(
              username=username, password=password, email=email,last_name=last_name, first_name=first_name, user_type=3)
...
...

Полагаю, что в create_user() вы также инстанцируете объект Student (именно в этот момент по умолчанию применяется student.picture!!!) и присваиваете его CustomUser.student

позже вы назначаете

...       
            user.student.picture = picture

но Student уже инстанцирован, поэтому если здесь присвоить None, то оно останется None. Значение поля по умолчанию применяется только один раз в момент инстанцирования.

Решением может быть передача картинки в вызов create_user() и использование ее при инстанцировании объекта Student.

Другой вариант: назначать картинку, только если она не None:

if picture is not None:
    user.student.picture = picture
Вернуться на верх