I have a method generate_certificate(), that uses a base image from default storage in django and edits it through pillow library and saves that image to the default djnago storage and returns file path.
def generate_certificate(name, certification):
base_image_path = os.path.join(settings.MEDIA_ROOT, 'certificates', 'Certificate.png')
font_path = os.path.join(settings.MEDIA_ROOT, 'fonts', 'font.ttf')
if not os.path.exists(base_image_path):
raise FileNotFoundError(f"Base certificate image not found at {base_image_path}")
img = Image.open(base_image_path)
d = ImageDraw.Draw(img)
location = (143, 155)
text_color = (100, 100, 100)
font = ImageFont.truetype(font_path, 40)
d.text(location, name, fill=text_color, font=font)
location = (360, 215)
font = ImageFont.truetype(font_path, 18)
d.text(location, certification, fill=text_color, font=font)
location = (200, 310)
font = ImageFont.truetype(font_path, 15)
d.text(location, '2024-08-07', fill=text_color, font=font)
file_name = f"{name.split(' ')[0]}_{random.randint(0, 255)}.png"
file_stream = BytesIO()
img.save(file_stream, format='PNG')
file_stream.seek(0)
# Save the file to the media directory and return the relative path
file_path = default_storage.save(f'certificates/{file_name}', ContentFile(file_stream.read()))
return file_path # Return the relative path
I am using this method in a post method view that creates a record for UserCertification model. The request payload has the all the data except the image which is generated in the view. as below:
def post(self, request):
try:
user = request.data.get('user')
certification = request.data.get('certification')
score = request.data.get('score')
certificate_url = generate_certificate(user, certification)
print(f"Generated certificate file path: {certificate_url}") # Debugging
data = {
'user': user,
'certification': certification,
'score': score,
'certificate': certificate_url,
}
serializer = UserCertificationSerializer(data=data)
if serializer.is_valid():
serializer.save()
print(serializer.data)
return Response(serializer.data, status=HTTP_201_CREATED)
else:
return Response({"message": "Invalid Json"}, status=HTTP_400_BAD_REQUEST)
except Exception as e:
return Response({"message": str(e)}, status=HTTP_400_BAD_REQUEST)
So when i hit the api through postman the postman returns null in the certificate field instead of the url of the file as shown below however when i use django admin to add user certification that correctly saves the file on the server and also fills the certification field with the correct url.
{
"user": 6,
"certification": 8,
"score": "90.00",
"certificate": null,
"completion_date": "2024-08-09"
}
The serilizer and the model is :
class UserCertification(models.Model):
user = models.ForeignKey(User,on_delete=models.CASCADE)
certification = models.ForeignKey(Certification,on_delete=models.CASCADE)
score = models.DecimalField(decimal_places=2,max_digits=4)
certificate = models.ImageField(upload_to='certificates/', null=True)
completion_date = models.DateField(default=date.today)
class Meta:
unique_together = ('user', 'certification')
class UserCertificationSerializer(serializers.ModelSerializer):
certificate = serializers.SerializerMethodField()
class Meta:
model = UserCertification
fields = ['user', 'certification', 'score', 'certificate', 'completion_date']
def get_certificate(self, obj):
if obj.certificate:
url = obj.certificate.url
print(f"Certificate URL: {url}") # Debugging
return url
print("Certificate URL is None") # Debugging
return None
I am expecting that when i hit the api though postman the certificate field should be filled with url of the saved file that is generated through the generate_certificate method.
I am guessing that there is a problem with the return value of the generate_certificate method as when the serializer is run it prints: Certificate URL is None
But cant figure it out.`
I tried this post Save a generated PIL image into an ImageField in django as well but could not figure out.