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?
CodePudding user response:
You are saving only User object, not Student one.
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
...
Another thing is you probably should not let Django save picture as None.
models.py:
class Student(models.Model):
...
picture = models.ImageField(
blank=True, null=False, default='default.png')
...
CodePudding user response:
Firstly
Make sure you have
default.pngin your media fileIn 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()
CodePudding user response:
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
