Different upload and download urls for Django Models's Image Field - python

I need a way to have different upload and download URLs for ImageField. I want to upload the image to AWS S3 and while accessing the image I want the image to route through CDN (in my case Fastly).
def get_avatar_upload_path(identity, filename):
file_ext = filename.split('.')[-1]
file_name = f'{uuid.uuid4()}.{file_ext}'
return f'{settings.AWS_MEDIA_PREFIX}{identity.uuid}/{file_name}'
class Identity(identity_revision_base):
"""
Identity model. Ties a user to a chat identity.
"""
badges = models.ManyToManyField(Badge, blank=True)
key = models.UUIDField(_("key"), unique=True, default=uuid.uuid4)
uuid = models.UUIDField(_("UUID"), unique=True, default=uuid.uuid4)
avatar = models.ImageField(upload_to=get_avatar_upload_path, blank=True)
user = models.ForeignKey(
to=settings.AUTH_USER_MODEL,
blank=True,
null=True,
on_delete=models.SET_NULL,
related_name="+",
)
Just like I am specifying upload path in ImageField, I would like a way to do something similar for accessing Image. It also seems that I cannot modify avatar.url once it is created. Is there any way around?
If there is any way, I can override the Model's behaviour to modify the url while accessing.

Did you check django-storages? It takes care of uploading to object store and returns CDN URLs for downloading. Fastly is S3 compatible so it should work.
In general you can also also use model methods with property decorator for getting a custom calculated value from model instances.

Related

Django admin: How to get path of uploaded file

I have created model field for User Pic and User_pic_url, what i'm trying to do is when i upload image it's path should get populated in user_pic_url.
Note that i'm uploading image from django admin itself. any idea.
snapshot for ref:
Snapshot
Model.py:
class Main(models.Model):
name = models.CharField(max_length=50)
address = models.CharField(max_length=100)
about = models.TextField()
contact = models.CharField(default='0', max_length=12)
email = models.CharField(default='-', max_length=50)
linkedin = models.CharField(default='-', max_length=50)
github = models.CharField(default='-', max_length=50)
site_name = models.CharField(default='-', max_length=50)
resume = models.FileField()
cover_letter = models.FileField()
user_pic = models.ImageField()
user_pic_url = models.TextField(default="-")
From Django documentation regarding managing files
Consider the following model, using an ImageField to store a photo:
class Car(models.Model):
name = models.CharField(max_length=255)
price = models.DecimalField(max_digits=5, decimal_places=2)
photo = models.ImageField(upload_to='cars')
Any Car instance will have a photo attribute that you can use to get
at the details of the attached photo:
car = Car.objects.get(name="57 Chevy")
car.photo
<ImageFieldFile: cars/chevy.jpg>
car.photo.name
'cars/chevy.jpg'
car.photo.path
'/media/cars/chevy.jpg'
car.photo.url
'http://media.example.com/cars/chevy.jpg'
if you want to get the uploaded path first make sure you have configure you MEDIA_URL MEDIA_ROOT in settings.py and also you have to put your put url patterns for media url given in the documentation
if you have already done that you have to simply put the query set
obj = Main.objects.all().first()
like this when you get any object you have to go to the imagefield and add url after that like this
you have to only put url after all the configuration in the imagefield
print(obj.user_pic.url) <---------you can get your url like this
You don't need a user_pic_url field. You can fetch the data from the user_pic field itself
class Main(models.Model):
# rest of your fields
user_pic = models.ImageField()
#property
def user_pic_url(self):
return self.user_pic.url
Now, you can access the URL directly as,
model_instance = Main.objects.first()
print(model_instance.user_pic_url)

How to save an image in a directory named on the User?

I am using Django2.2 and I am currently learning Django. I have created a model where I have to post an image of a certain thing and that model is connected with a User. I want to save the image on a directory named on that certain user
I have a custom User Model where I created a field called Profile Photo and that profile photo is saved to a directory named on that User.But then I created another application called 'Product' and there I created many fields including an image field.I am trying to save that image on that directory named on that specific User.
def user_directory_path(instance, filename):
return 'media/%s/%s' % (instance.username, filename)
class Products(models.Model):
title = models.CharField(max_length=100)
body = models.CharField(max_length=1000)
image = models.ImageField(upload_to = user_directory_path)
product_user = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.title
When I try to save a Product and error occurs.
'Products' object has no attribute 'username'
Is there any successful ways to do it.
A Products instance indeed has no username attribute. The product_user has, you thus can change this to:
def user_directory_path(instance, filename):
return 'media/%s/%s' % (instance.product_user.username, filename)
Note: models have usually singular names, so Product, instead of Products.

Unable to save InMemoryUploadedFile to model in Django

I have the following model:
class IdentifierImage(models.Model):
super = models.ForeignKey(Super)
identifier = models.CharField(null=False, blank=False, max_length=32, db_index=True)
image = models.ImageField(upload_to='/identifierimages/%Y/%m/', blank=True, null=True, )
class Meta:
unique_together = (
('survey', 'identifier'),
)
I also have a form (NOT a ModelForm and will never be) which uploads an image file, and I get it as an InMemoryUploadedFile. From the Super class I create the IdentifierImage object and try to save it with:
def save_identifier_image(identifier, image):
identifier_image, created = self.identifierimage_set.update_or_create(identifier=identifier)
<logics to remove old images, disabled for current tests>
identifier_image.image.save(image.name, image)
, where identifier is a valid string, and image is the InMemoryUploadedFile.
However saving of the InMemoryUploadedFile to model fails with SuspiciousFileOperation, and shows me: The joined path (C:/</identifierimages/%Y/%m/>) is located outside of the base path component (<MEDIA_ROOT>).
Why does this happen?
Why does it try to save under C:/ instead of under the media root? Or is something completely different going on?
You may want to try without the leading slash in your ImageField's upload_to path:
>>> os.path.join("/whatever", "/else")
'/else'

ImageField and several sizes in Django

I am new at Django (and Python) and was wondering about the ImageField property of a class. My example is about users of my website. I need 3 sizes of each picture of a user:
* user1-200-200.png
* user1-120-120.png
* user1-60-60.png
Of course I want only 1 file input type.
Should I create 3 properties and resize the one from the form for all properties:
class UserProfile(models.Model):
user = models.OneToOneField(User)
slug = models.CharField(max_length=30)
avatar_200_200 = models.ImageField(null=True, blank=True, upload_to="images/")
avatar_120_120 = models.ImageField(null=True, blank=True, upload_to="images/")
avatar_60_60 = models.ImageField(null=True, blank=True, upload_to="images/")
Can I use no property and do what I did in PHP, resize the images several times, move them to the proper folder and in the website, use the session to find them (I always rename the images and transform them to png).
I don't know what to do and what's possible to do and what's the best. Thanks for your advices.
Sure you can do that but you will have to reimplement some of built-in django features like file uploading, storage support, width/height calculating/saving etc.

django change image file location with setattr

In my project I have an app with a school model and a schoolsuggestion model.
The school model has fields for various images, like logo, seal, etc:
seal_image = models.ImageField(upload_to="sealimgs", null=True, blank=True)
logo_image = models.ImageField(upload_to="logos", null=True, blank=True)
The schoolsuggestion model has a field for what the corresponding school field is, and an image field.
field_name = models.CharField(max_length=255, default="")
image_field = models.ImageField(upload_to='img', null=True, blank=True)
When a school suggestion is approved, I overwrote save so that it will get the associated school's field via getattr(field_name) and set it with setattr(field_name, image_field) (I'm simplifying the syntax, but you get the idea).
Problem is, the file is still being saved in img, presumably because I'm using setattr and not the image field specific save, which would have uploaded it to the correct directory.
So how do I do this? It makes sense that I could maybe get the upload_to value of the attribute somehow, resave the image with that filepath somehow, and then use setattr on the resaved image, but I can't figure out how to do the first two.
I modified the upload to to this function and included it in the file above the class def:
def get_upload_to(instance, filename):
return School._meta.get_field(instance.field_name).upload_to+"/"+filename

Categories