Сохранение самостоятельно сгенерированного изображения в django models.ImageField
У меня есть метод generate_certificate(), который использует базовое изображение из хранилища по умолчанию в django, редактирует его через библиотеку pillow и сохраняет это изображение в хранилище по умолчанию djnago и возвращает путь к файлу.
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
Я использую этот метод в представлении пост-метода, которое создает запись для модели UserCertification. Полезная нагрузка запроса содержит все данные, кроме изображения, которое генерируется в представлении, как показано ниже:
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)
Когда я обращаюсь к api через postman, postman возвращает null в поле сертификата вместо url файла, как показано ниже, однако когда я использую django admin для добавления сертификации пользователя, он корректно сохраняет файл на сервере и также заполняет поле сертификации правильным url.
{
"user": 6,
"certification": 8,
"score": "90.00",
"certificate": null,
"completion_date": "2024-08-09"
}
Серилизатор и модель:
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
Я ожидаю, что когда я обращаюсь к api через postman, поле сертификата должно быть заполнено url сохраненного файла, который генерируется через метод generate_certificate.
Я предполагаю, что проблема в возвращаемом значении метода generate_certificate, так как при запуске сериализатора он выводит: Certificate URL is None
Но не
могу разобраться.Я пробовал этот пост Сохранить сгенерированное изображение PIL в ImageField в django, но так и не смог разобраться.
Вам нужно отправить файл сериализатору Верните файл изображения из generate_certificate
и передайте его сериализатору
Вам также не нужно сохранять файл в медиа