How to store image in Django - use link or no? - django

I have field:
image = models.ImageField(
max_length=500,
upload_to='images'
)
and some settings to upload an image to AWS S3 Bucket, where PublicMediaStorage is my custom storage:
PUBLIC_MEDIA_LOCATION = 'media'
AWS_S3_MEDIA_ENDPOINT_URL = env('AWS_S3_MEDIA_ENDPOINT_URL', None)
DEFAULT_FILE_STORAGE = 'new_project.storages.PublicMediaStorage'
I need to store and get my images from database(postgres).
For now my image stores at the database like
here.
And if i write image.url i will get the url of my image(that's why I don't need to store urls of images in my database).
But is it right way? Maybe it will be better to store immediately links at the database? Any solutions?

OP is doing well using ImageField . OP might want to add blank=True so that OP's forms don't require the image.
image = models.ImageField(upload_to='images', blank=True)
The reason to use ImageField is that it checks whether the image is valid and also uploads it to the right location, which is something one wouldn't get with a simple URL. That is why the docs mention it requires the Pillow library.
With regards to the DB path, it is better to store the the relative path. OP can access the rest of the URL in the template if needed too and if the rest of the URL changes then OP only has to change in one place and not in the database(s).

Related

Django ImageField Creating New Folder by ID on upload?

I'm Currently developing a app with a ManyToMany ImageField Relantionship . I want to have the ImageField save all images to a specific folder based on the ID of the Relantionship.
I want to have something like this.
class PostImages(models.Model):
image = models.ImageField(upload_to='Post_Images/post/' + post.id)
class Post(models.Model):
images = models.ManyToManyField(PostImages)
How do I access the post.id to do this ? I mostly want to do this for organization purposes right now cause its on my local machine but also see no reason to change it when I deploy.
E.g. based on FileField^ but the same you can use for ImageField:
def get_file_path(instance, filename):
return instance.created.strftime("folder/%Y/%m/%d/") + instance.post.id
bfile = models.FileField(upload_to=get_file_path, null=True)

Django - Is there a remote image field

I was wondering if there is a field (A model field) that represents a remote image.
What I need is to add an image field to my model that isn't stored locally, but is given a remote URL and can only be viewed, not edited or uploaded.
Edit: To make myself more clear, I meant I need a field such as URLField that can store a URL (to the image) but that in the admin page, (or other forms) it will show the image like ImageField does.
A URLField is an extension of the CharField and can store a valid URL that points to an image. Note that you will not be able to upload an image, only reference an image that already exists on the web.
class MyModel(models.Model):
remote_image = models.URLField()
In your view you can set the remote image with a string:
my_instance = MyModel()
my_instance.remote_image = 'http://example.com/images/example.jpg'
my_instance.save()
You can display the remote image in your template by setting the src attribute:
<img src="{{ my_instance.remote_image }}">
Django has a file storage API. The default storage class is the FileSystemStorage, that stores your images using the file system.
One of the best things about Django is its huge ecosystem: you can find storage classes for S3 and other popular hosting services.
It is somewhat easy to write your own, also.
You can use URLField to store the source URL and handle viewing the image a django View that you build, I can imagine that your django View can read data using your model (including the image source URL), set it in context dictionary object, which can be read from the HTML template of your view to display the image.
Please read about django Views and Templates for more info.

Django, two ImageField pointing to the same file

I'd like my two image fields point to the same image.
At one time, I'll have one image field populated.
At later time, I'd like another imageField to point to the same file.
(If the first one changes, the second one gets updated as well)
The file is at amazon s3 if it matters.
I could use django-imagekit.
I would do it with a structure like this:
class Image(models.Model):
img = models.ImageField(upload_to = "images", related_name="+")
class A_model(models.Model):
image = models.ForeignKey(Image)
class B_model(models.Model):
image = models.ForeignKey(Image)
This avoids redundancies in the database, which you would have using two image fields. And access to the image is quite easy.
Note that you have to set the related to "+", because Django cannot reverse the relation in this case.

Customize ImageField url/path

I have a Page model that basically describes an HTML page. Pages are then served with URLs, such as http://www.mysite.com/page/1234/ for the page of id (pk) 1234.
I want to be able to add or attach images to my page. Therefore, I would like to use an Image class with a foreign key to a Page object:
class Page(models.Model):
title = ...
content = ...
class Image(models.Model):
page = models.ForeignKey(Page)
image = models.ImageField(...)
Here is my problem: I would like to deliver images to the client with urls of the form:
http://www.mysite.com/images/1234/image_name.jpg, i.e a URL that includes the page id. Also on the server, the paths should reflect the page structure: /path/to/media/images/1234/image_name.jpg
I don't know how to tackle this problem. On one hand, I would like to keep the features of an ImageField related to path formatting. For example when uploading two images with the same name, Django creates two paths ending with "image.jpg" and "image_2.jpg" or so to make the difference between both images.
On the other hand, the upload_to option has limited capability, and I don't know how to insert the page id in the path. Especially, some tricky cases such as uploading an image at the same time a page is created (using the same form), which means a page id should be generated before uploading the image.
Is it reasonably easy to make an image model that would behave as described above? If so, how do I have to modify the Image model to insert the page id in the image path?
I have seen the question Customize save path for ImageField, but it does not address the problem of primary key that might not be assigned.
Thanks.
Actually, a simple function passed as an upload_to parameter works, and there is no problem of non-existing id. So I guess that Django's default behaviour saves the image after saving the parent page model, as I wanted to.
In the Image model:
image = models.ImageField(upload_to=get_image_path)
with the following function:
def get_image_path(instance, filename):
return 'pics/' + str(instance.page.id) + '/' + filename

Django - FileField and images

I'm trying to create some kind of 'media manager' model which will allow the user to upload different kings of media (images, swfs, pdfs) similar to the way WordPress does. My media model looks something like this:
class Media(models.Model):
id = models.AutoField(primary_key=True)
url = models.FileField(upload_to="uploads")
mimetype = models.CharField(max_length=64, editable=False)
created = models.DateTimeField(auto_now_add=True, editable=False)
When a user uploads a file, I want to first determine what kind of file it is and if it's an image, manipulate it further. I want to be able to to specify the dimensions (crop) of the uploaded image via a view, so when I call the .save() method, the model will resize and crop the image, upload it and populate the database with the url to the file.
I also want to ensure that the upload of the image is done AFTER the post processing (cropping etc), I have no need to keep the original file.
So the question I am asking is how do I got about passing parameters to the FileFields save method (so I can pass dynamic properties for image post processing) and how can I ensure the post processing is done BEFORE the image is uploaded?
Edit: When I say before the image is uploaded, I mean before it's saved to it's final destination. I understand the image has to go int othe tmp folder first before I can post process it. Sorry for the misleading question.
Hope someone can help :)
You cannot do anything before the image is uploaded (because you have nothing to work with).
But if you want modify the image before saving it into db, you can do it in model's save() method, before calling parent's save()
If you are uploading it via admin, override method save_model() in admin.py, ie:
def save_model(self, request, obj, form, change):
file = request.FILES.get('url') # name of field
if file:
# proceed your code
return super(AdminClassName, self).save_model(request, obj, form, change)
Here is my code how to change file before actually upload it. I think you should get my idea
from django.core.files.uploadedfile import InMemoryUploadedFile
#....
#some form
def clean_avatar(self):
av = self.cleaned_data['avatar']
resized = make_avatar(av,65) # My custom function than returns image
return InMemoryUploadedFile(resized, av.field_name, av.name, av.content_type, resized.len, av.charset)
You can read django code for InMemoryUploadedFile "documentation".
And in your resize/crop function you should use StringIO not file to save result
How could the processing be done before the image is uploaded? That doesn't make sense. The server doesn't have any access to the file until you upload it.
If you actually want to handle the file before it's saved, you can write a custom upload handler. You can test there whether the file is an image, then crop it appropriately, before saving. (You'll need the Python Imaging Library for both of those tasks.)