1

models.py

class Image(models.Model):
    title = models.CharField(max_length=255)
    image = models.ImageField(upload_to='attack_images', blank=True, null=True)
    source_url = models.URLField(blank=True,null=True)
    domain = models.ForeignKey(Domain, on_delete=models.CASCADE, blank=True, null=True)
    creator = models.ForeignKey(User, on_delete=models.CASCADE, blank=True,null=True)
    slug = models.SlugField(blank=True,null=True)

    def save(self, *args, **kwargs):
        if not self.slug:
            self.slug = slugify(self.title)[:50]

        if self.source_url and not self.image:
            result = urllib.request.urlretrieve(self.source_url)
            self.image = os.path.basename(self.source_url), File(open(result[0], 'rb'))

        if self.source_url:
            if '//' in self.source_url:
                d = self.source_url.split('//')[1].split('/')[0]
            else:
                d = self.source_url.split('/')[0]

            try:
                domain = Domain.objects.get(domain_url=d)
            except Exception as e:
                print(e)
                domain_object = Domain.objects.create(domain_url=d)
                domain = domain_object
            self.domain = domain

        return super(AttackImage, self).save(*args, **kwargs)

    def get_absolute_url(self):
        return reverse("attack_image_detail", kwargs={
            'pk': str(self.id),
            'slug': str(self.slug)})

I believe this happens because of the line self.image = os.path.basename(self.source_url), File(open(result[0], 'rb'))

Can anyone help with this? Thanks in advance. Stack is python/django. My basic question is, if I am correct, and the line above is what is causing the problem, how do I assign an image to an ImageField properly (without saving it)?

Michael
  • 763
  • 1
  • 10
  • 25
  • Please show us the code around `File "crawl_ebaumsworld.py", line 66, in crawl creator=mike`. – Kent Shikama Dec 15 '19 at 02:53
  • Does this answer your question? [Programmatically saving image to Django ImageField](https://stackoverflow.com/questions/1308386/programmatically-saving-image-to-django-imagefield) – 2ps Dec 15 '19 at 03:09
  • seems this line causing the error, `self.image = os.path.basename(self.source_url), File(open(result[0], 'rb'))`. – JPG Dec 15 '19 at 03:10
  • Is that `open()` the standard Python function? If so, I suggest using a context manager. Is `File` imported from a library, or something you created? – AMC Dec 15 '19 at 03:10
  • @2ps no. see >(without saving it) in my question. Alexander, File imported from a Django module. – Michael Dec 15 '19 at 05:29

1 Answers1

2

When working with ImageField or FileField you actually operate on instance of FieldFile

And error in this case is assigning wrong type to ImageField - it expects FieldFile or at least File type.


Brief answer what can be used instead of self.image = .... in your code:

from django.core.files import File

...

with open(result[0], "rb") as downloaded_file:
    self.image.save(os.path.basename(self.source_url), File(downloaded_file), save=False)
...

Check this StackOverflow answer on saving files. I added a small change - save=False - while saving image - at this step we only save downloaded file = copying it from temporary path, where it was downloaded by urllib to desired target path in MEDIA, but not saving model instance.

self.image.save(name, file) - file is read and saved in MEDIA at upload_to path with name name and model instance is saved aftewards (default save=True).

self.image.save(name, file, save=False) - the same, but model instance is not saved after the file has been altered, which is probably desired as you save model instance super().save() later.


What steps are happening in your code:

  • downloading file with urllib (to temp path)
  • saving it / copying to correct media / upload_to path and setting ImageField to its value
  • setting other model instance fields
  • saving model
Oleg Russkin
  • 4,234
  • 1
  • 8
  • 20