Сохранение самостоятельно сгенерированного изображения в 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 и передайте его сериализатору

Вам также не нужно сохранять файл в медиа

Вернуться на верх