How do I save an Image in a specific folder, depending of whom is Loggedin?
My program creates a folder for every user that registers
after they login, they are able to upload some images.
The problem is when I try to save my image, I need to specify the path where is going to be Uploaded (with the userID)
Example:
If Bob is Loggedin, you will upload the images here: space/users/bob123/example.png
Model
class StudentPhotos(models.Model):
image = models.ImageField(upload_to= ??? , default="", null=True)
image_id = models.CharField(max_length = 15, null=False, editable=False, default=id_generator, primary_key=True)
user_id = models.CharField(max_length = 15, null=False, default="")
The main reason to save it that way is to be able to bring in my admin site all images from an user
Lets say you have your model like as follows(Demonstration only):
class StudentPhotos(models.Model):
image = models.ImageField(upload_to=name)
user = models.ForeignKey(User)
Here name (upload_to=name) can be function as follows:
def name(instance, fname):
return '/'.join(instance.user.get_full_name(), fname)
I personally make use of easy-thumbnails for the purpose of having image fields in my models and I am able to use name function in the way I have given above.
Hope, you can infer some relative information and be able to come up with a better solution for your needs.
Related
I'm working on a project in django, I need to duplicate a picture stored in one model and save it with a different name into another one, I've tried many of the responses I've found but nothing seems to work.
This last try doesn't give me an error but is not duplicating the image, nor storing a copy with the name. I'm running Pillow and Django 3.X
models.py:
class Visualization(models.Model):
kind = models.CharField(max_length=90)
description = models.CharField(max_length=90)
image = models.ImageField(upload_to='visualization', null=True,
blank=True)
class Order(models.Model):
visualization = models.ForeignKey(Visualization,
on_delete=models.CASCADE)
hashed = models.ImageField(upload_to='hashedimages', null=True,
blank=True)
def save(self):
super().save()
self.hashed = self.visualization.image
self.hashed.name = 'randomothername.jpg''
self.hashed.save()
my model.py as follows,
class Employee(models.Model):
id = models.IntegerField(max_length = 6,primary_key=True,verbose_name="Employee ID")
name = models.CharField(max_length = 100,verbose_name="Name")
image = models.ImageField(upload_to = ".",blank=True,null=True)
When i try to add image in django admin, it uploads the image to /site_media/media. Here i want to replace the uploaded image name with my primary key field ID.jpeg, so that i can retrieve and show that in html pages .
Even now i can retrieve the image name because its stored in db. However for simplifying i need to customize the image name before upload. Also if the user uploads another image for same person it should overwrite the old one. At present it just changes the new name in db. But still old image is present in the media folder
You can use a callable for upload_to as follows:
def file(self, filename):
url = "./%d.JPG" % (self.id,)
return url
class Employee(models.Model):
id = models.IntegerField(max_length = 6,primary_key=True,verbose_name="Employee ID")
name = models.CharField(max_length = 100,verbose_name="Name")
image = models.ImageField(upload_to = file,blank=True,null=True)
But you will face the problem of Django not overwriting the file which can be solved by a custom storage or deleting the file.
You can use a function for upload_to;
def sample_upload_to_function(instance, filename):
extension = filename.split('.')[-1]
return "%s.%s" %(instance.id, extension)
class Employee(models.Model):
.....
image = models.ImageField(upload_to =sample_upload_to_function, blank=True, null=True)
But i don't know how to overwrite existing file. I think before save, you must delete the existing file.
In my current project I have my images stored on a s3 bucket.
I have a pre_save signal receiver to delete the actually image from the s3 bucket on the Image class.
class Image(models.Model):
name = models.CharField(max_length = 255)
caption = models.CharField(max_length = 255)
image = models.ImageField(upload_to='uploads/',blank=True,null=True)
rent_property = models.ForeignKey(RentProperty, related_name='Images')
is_main_image = models.BooleanField(default=False)
#receiver(models.signals.pre_save, sender=Image)
def auto_delete_file_on_change(sender, instance, **kwargs):
"""Deletes file from filesystem
when corresponding `MediaFile` object is changed.
"""
if not instance.pk:
return False
try:
old_file = Image.objects.get(pk=instance.pk).image
except Image.DoesNotExist:
return False
new_file = instance.image
if not old_file == new_file:
old_file.delete(save=False)
My problem is, I am using django-rest-framework, and I want to get the PATCH to work. but if I try to patch an Image description for example, it would delete the image itself. My question is, how do I write an IF that would differentiate weather or not there is a new image in the patch that needs changing , and if not, do nothing?
For models with an ImageField or FileField, I include an additional field to store the SHA-1 hash string. I've found this useful to have for many reasons:
Reducing unneeded transfers for the same file for updates (your case)
Preventing users from uploading duplicate files as new instances
Providing users with an SHA-1 hash when downloading files so they can verify the download
Doing data integrity checks on the back-end file system to verify the files have not changed
I also save the original file name in order to reproduce it for user facing views/downloads. In this way the back-end names do not matter to the users.
Here's a basic implementation based on your model:
import hashlib
from django.core.exceptions import ValidationError
from django.core.files import File
from django.db import models
class Image(models.Model):
name = models.CharField(max_length = 255)
caption = models.CharField(max_length = 255)
image = models.ImageField(upload_to='uploads/',blank=True,null=True)
original_filename = models.CharField(
unique=False,
null=False,
blank=False,
editable=False,
max_length=256)
sha1 = models.CharField(
unique=True,
null=False,
blank=False,
editable=False,
max_length=40)
rent_property = models.ForeignKey(RentProperty, related_name='Images')
is_main_image = models.BooleanField(default=False)
def clean(self):
"""
Overriding clean to do the following:
- Save original file name, since it may already exist on our side.
- Save SHA-1 hash and check for duplicate files.
"""
self.original_filename = self.image.name.split('/')[-1]
# get the hash
file_hash = hashlib.sha1(self.image.read())
self.sha1 = file_hash.hexdigest()
# Check if this file has already been uploaded,
# if so delete the temp file and raise ValidationError
duplicate_hashes = Image.objects.all().exclude(
id=self.id).values_list('sha1', flat=True)
if self.sha1 in duplicate_hashes:
if hasattr(self.image.file, 'temporary_file_path'):
temp_file_path = self.image.file.temporary_file_path()
os.unlink(temp_file_path)
raise ValidationError(
"This image already exists."
)
This is roughly my model:
class Image(models.Model):
url = models.CharField(max_length=255)
title = models.CharField(max_length=255, blank=True, null=True)
class Favorite(models.Model):
user = models.ForeignKey(User, related_name="favorites")
image = models.ForeignKey(Image, related_name="favorited")
I'm displaying a bunch of images and users can add images to their favorites. I want to display a star next to each image if the current user has it in his favorites. I can do it by using raw and then issuing a left join in the SQL, but I'd much rather do it without doing raw SQL. Is there any way to do it maybe using extra?
Without any extra sql, you can just query the related table to see if anything exists like this:\
images = Image.objects.all().prefetch_related('favorited')
for image in images:
image.favorited = image.favorited.filter(user=current_user).exists()
Then you can check image.favorited in the template.
I think a little cleaner way would be to use .extra() with a little sql. Something like this:
image.objects.extra(select={'favorited': 'EXISTS(SELECT * FROM app_favorite WHERE image_id = app_image.id AND user_id = %s)'}, select_params=[current_user.pk])
I have different categories like English,French and I've applied key language = models.ForeignKey(Category) I want to validate the file before it upload to disk.
I want if category is english then file upload to english/album_name if category is french then file upload to french/album_name. I've written forms.py file. But no idea. Thanks in advance
Models.py
class Artist(models.Model):
name = models.CharField(max_length=100)
slug = models.SlugField(unique = True,max_length=100,help_text="Suggested value automatically generated from name. Must be unique.")
class Album(models.Model):
name = models.CharField(max_length=100)
slug = models.SlugField(unique = True,max_length=100,help_text="Suggested value automatically generated from name. Must be unique.")
path = models.CharField(max_length=100,null=True, blank=True)
language = models.ForeignKey(Category)
albumid = models.CharField(max_length=100)
class Song(models.Model):
title = models.CharField(max_length=100)
artist = models.ManyToManyField(Artist)
music = models.ForeignKey(Music)
album = models.ForeignKey(Album)
file = models.FileField(upload_to='media/mp3_files')
forms.py
from django import forms
from db.song.models import Song
class SongAdminForm(forms.ModelForm):
class Meta:
model = Song
# No idea what to do next :-?
def clean_file(self):
file = self.cleaned_data["file"]
if file:
if file._size > 10*1024*1024:
raise ValidationError("Audio file too large ( > 10mb )")
if not file.content-type in ["audio/mpeg","audio/..."]:
raise ValidationError("Content-Type is not mpeg")
I think what you really want is to validate it after upload, but before saving it really.
When files are uploaded, they are in a temporary folder, so you can do all checks you want before saving it to the appropriate folder.
However, if you really mean pre-upload checks, you have to use Javascript (because it is client-side). But, don't forget that you should "never trust user input", and that includes what Javascript does, because user can change the Javascript code.