Search code examples
pythondjangodjango-orm

Changing ImageField URL


I'm attempting to correct my image URLs by invoking the correct_image_url method of the Page model. However, for some reason, the result is not being saved. Thus, while it operates correctly, at the step where I execute:

print(f"New URL of the page: {new_image_url}")

it returns the old URL.

class Page(models.Model):
    image = models.ImageField(
        max_length=400,
        storage=S3Boto3Storage(),
        validators=[FileSizeValidator(limit_value=8)])
    number = models.PositiveIntegerField(default=0, blank=True, null=True)
    chapter = models.ForeignKey(Chapter, on_delete=models.CASCADE)

    objects = PageManager()

    def correct_image_url(self):
        url = self.image.url
        corrected_url = url.replace(
            "https%3A/dist.cloudfront.net", "https://dist.cloudfront.net")

        domain = "https://dist.cloudfront.net"
        first_occurrence = corrected_url.find(domain)
        second_occurrence = corrected_url.find(
            domain, first_occurrence + len(domain))

        if second_occurrence != -1:
            corrected_url = corrected_url[:second_occurrence]

        if corrected_url != url:
            if self.image:
                original_url = self.image.url
                print(
                    f"Correcting URL from: {original_url} to {corrected_url}")
                self.image = corrected_url
                try:
                    self.save()
                    self.refresh_from_db()
                    new_image_url = self.image.url
                    print(f"New URL of the page: {new_image_url}")
                except DataError:
                    print(
                        f"Skipped saving due to DataError for URL: {corrected_url}")
                except ValidationError as e:
                    print(
                        f"Validation error: {e.messages} for URL: {corrected_url}")

I run it in the Django shell like this:

from app.models import Page

for page in Page.objects.all()[:1]:
    page.correct_image_url()

Also, when i try to run

self.image.url = corrected_url

It returns

AttributeError: can't set attribute


Solution

  • You are doing something unusual. Domain name in the image URL should come from MEDIA_URL. It should never be stored in ImageField path. image.url is composed from MEDIA_URL + image relative path. For changing MEDIA_URL you should define something like environment variable.

    ImageField.url is a function inherited from FileField class. It cannot be updated, its' value is not stored in DB. It is computed on the fly.

    If you store domain name and protocol in ImageField attributes - you're violating Django concepts, functionality is misused.