'Django default image not saving

I am having an issue while saving a default image whenever I am not uploading an image in ImageField. I can't understand what I am doing wrong, for me it seems everything ok but couldn't find where the bug is.

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)

The view and the saving is just working fine. In fact, the images are saved properly. But when I try to leave the empty field in the image it doesn't provide the image 'default.png' (which I put inside the media folder). Any suggestion?



Solution 1:[1]

Firstly

  1. Make sure you have default.png in your media file

  2. In your view, you are retrieving your image file but it could be null and also your model allows the image to be null, in that case, you have to check if your request file image is null or not.

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

Same for your 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()

Solution 2:[2]

I think the misunderstanding is in the "default" value: The default field value is only applied once at the moment of instantiation! Not when the instance is modified or saved.

I try to figure out what happens because some code is missing to be sure:

you instantiate a CustomUser and call the method create_user().

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

I suppose in create_user() you also instantiate the Student object ( that is the moment where the default is applied to student.picture!!) and assign it to CustomUser.student

later you assign

...       
            user.student.picture = picture

but the Student is already instantiated so if here you assign None, it will stay None. The default field value is only applied once at the moment of instantiation.

A solution could be to pass picture to the create_user() call and use it at the instantiation of the Student object.

Another option: only assign the picture if it is not None:

if picture is not None:
    user.student.picture = picture

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Khan Asfi Reza
Solution 2