I'm trying to generate dynamic file paths in django. I want to make a file system like this
hierarchy:
--user_12
--channel_14
--program 2
--image1.jpg
--image2.jpg
--program 1
--image1.jpg
--image2.jpg
--user_14
--channel_13
--program 1
--image1.jpg
--image2.jpg
When a user want to upload image it will upload the image to the corresponding program folder.if program folder does not create it will automatically create a folder and store image..
my image path will look like this: media/images/john/johnchannel/birthday/img1.jpg ( where john=user,johnchannel=channel,birthday=program,images is the pre created folder where all image file should be stored)
I am very new in django. urgent help needed.
Are you looking for something like this?
misc.py
def get_upload_path(instance, filename):
""" creates unique-Path & filename for upload """
ext = filename.split('.')[-1]
filename = "%s%s.%s" % ('img', instance.pk, ext)
return os.path.join(
'images', instance.user.username, instance.channel, instance.something, filename
#images/ john/ johnchannel/ birthday/ img1.jpg
)
models.py
from misc import get_upload_path
class MyThing(models.Model):
user = models.ForeignKey(User)
channel = models.CharField(max_length=100) # johnchannel
something = models.CharField(max_length=100) # birthday
img = models.ImageField(upload_to=get_upload_path)
When using an ImageField in a Django model, you can specify a callable in the upload_to keyword argument: See the FileField docs here
So create a function that you'll point upload_to at, which can generate all your subdirectories as needed.
Related
List item
registration start date
Year
Vin#
Make
Title Owner (Upload field) ==== (can be several files)
HUT # (Upload field) ==== (can be several files)
Ifta # (Upload field) ==== (can be several files)
I need that model
If file upload fields had to be for a single file, then it would be okay, but how Can I handle that model?
(Should I create ForeignKey models for every file_upload field in order to handle multi file uploads??)
I would write something like this:
files_titleowner = models.ManyToManyField(FileTitleOwner, related_name="mymodel_filetitleowner", blank=True)
...
and so on. I usually specify the related_name attribute for each many to many field.
FileTitleOwner could be like this:
class FileTitleOwner(models.Model):
file = models.FileField(upload_to=user_directory_path,
null=True, blank=True,
verbose_name="...")
...
Also, user_directory_path is a function which returns the pathname for the file to be stored on file system:
def user_directory_path(instance, filename):
...
return f"{<construct opportunely a directory name>}/{filename}"
I'm trying to develop a simple model form by Django to upload pdf files. The form is based on a model. Every time, user upload a file a database table entry would be created with the file path (including filename), uploaded user name and time Etc.
when I upload the same file again, Django is uploading the same file by altering its name (poster-proposal.pdf ->poster-proposal_IomFZQM.pdf). It is also creating another entry in the database table.
I want Django to give the user a warning when he is trying to upload an already existing file saying (a file with the same name is already existing) or something like that and not to upload the duplicate file.
I followed this post,post 1 but it says it does not prevent Django from uploading the file.
I followed this method post 2, but I'm new to Django and it seems complicated. I believe for newer Django versions there should be an easier way to address this issue.
I added unique = True to FileField.It did not work
models.py
class files(models.Model):
repo_id = models.ForeignKey(Repository, on_delete = models.CASCADE)
username = models.CharField(db_column='username',max_length = 45)
date = models.DateTimeField(auto_now_add=True, db_column = 'date')
file = models.FileField(upload_to='documents/', db_column = 'file', unique = True)
indicator_name =models.CharField(db_column = 'indicator_name',max_length = 100)
username = models.CharField(db_column='username',max_length = 45)
Any idea would be highly appreciated. Thanks
The simplest way is to search for the name and then upload the file:
# Note that file name depends on your upload_to path.
# Either you should include it in the search or you have to use something like:
# filter(file_contains="filename") which might return results that you don't want
filename = "documents/" + filename_you_want_to_upload
files = files.objects.filter(file=filename)
if files.count() > 0:
# A file with that name exists.
# Return some error or ...
else:
# There is no file with that name.
# Upload the file and save it to database.
I have a django form which I am using to access a directory. However I would like to access two different directories based on a given input, but have one FilePathField.
As an example - I have two panels - 'panel1' and 'panel2'. The directory I would like to access is the analysis directory of each of these panels as such:
/path/destination/panel1/analysis/
/path/destination/panel2/analysis/
In each of these analysis directories are directories starting with "Experiment" which I would like a user to be able to choose to obtain some results.
I have my form:
class RunUploadForm(forms.Form):
directory_path = forms.FilePathField(
path='/path/destination/panel1/analysis',
required=True,
allow_folders=True,
allow_files=False,
recursive=True,
match="Experiment*",
label="Pick folder for results:"
)
class Meta:
fields = ('directory_path',)
This only allows the user to access panel1 directory as it is hardcoded into the path arg. Is there a way to dynamically change this path argument, maybe with a choicefield?
One way of doing so would be to pass the path as an argument to the __init__ method of the form, for example:
class RunUploadForm(forms.Form):
directory_path = forms.FilePathField(
path='/path/destination/panel1/analysis',
required=True,
allow_folders=True,
allow_files=False,
recursive=True,
match="Experiment*",
label="Pick folder for results:"
)
class Meta:
fields = ('directory_path',)
def __init__(self, *args, **kwargs):
path = kwargs.pop('path', 'somedefaultvalue')
super().__init__(*args, **kwargs)
self.fields['directory_path'] = forms.FilePathField(
path=path,
required=True,
allow_folders=True,
allow_files=False,
recursive=True,
match="Experiment*",
label="Pick folder for results:"
)
You need to crate a new instance of FilePathField because choices for this kind of field are generated on __init__
Since some image files have name conflicts, I decided to make the system to change a uploaded file's name automatically. However, after changing the system, I got in trouble with getting a current date for the file path.
This is how my previous Image model looks like, and it stores an image with a name like boutique/index/2018/9/20/FILE_NAME.jpg.
class Image(TimeStampedModel):
...
image = ImageField(..., upload_to='boutique/index/index/%Y/%m/%d')
...
After that, I changed it to like this. This successfully changes a uploaded image's name automatically. However, it stores a name like boutique/%Y/%m/%d/FILE_NAME.jpg.
def image_path(instance, filename):
basefilename, file_extension = os.path.splitext(filename)
chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890'
randomstr = ''.join((random.choice(chars)) for x in range(10))
return 'boutique/index/%Y/%m/%d/{imageid}/{basename}{randomstring}{ext}'.format(imageid=instance.store.domainKey, basename=basefilename, randomstring=randomstr, ext=file_extension)
class Image(TimeStampedModel):
...
image = ImageField(..., upload_to=image_path)
...
Like you see the above, the problem is that %Y, %m, and %d don't provide date data I need anymore. What is wrong here? image_path function returns the same thing in the same place. I don't know why they are just like recognized as a normal string
You have to set those values manually.
Add the import
from datetime import datetime
And replace in your function %Y, %m, %d with {year}, {month}, {day} variables and add the values to the format call.
def image_path(instance, filename):
basefilename, file_extension = os.path.splitext(filename)
chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890'
randomstr = ''.join((random.choice(chars)) for x in range(10))
_now = datetime.now()
return 'boutique/index/{year}/{month}/{day}/{imageid}/{basename}{randomstring}{ext}'.format(
imageid=instance.store.domainKey,
basename=basefilename, randomstring=randomstr, ext=file_extension,
year=_now.strftime('%Y'), month=_now.strftime('%m'), day=_now.strftime('%d')
)
More about file uploads in django
In my django app i'm trying to resize & compress an Image before saving it to the database.
Here's how I did it inside the models
class Data(models.Model):
image = models.ImageField(upload_to='all_images/', null=True, blank=True)
def save(self, *args, **kwargs):
if self.image:
img = Image.open(self.image)
resize = img.resize((240, 240), Image.ANTIALIAS)
new_image = BytesIO()
resize.save(new_image, format=img.format, quality=80, save=False)
temp_name = os.path.split(self.image.name)[1]
self.image.save(temp_name, content=ContentFile(new_image.getvalue()), save=False)
super(Data, self).save(*args, **kwargs)
Here's the problem, I saved an image named tesla.jpg into the database, it compressed & resized it well, but it renamed it something like, tesla_CKBw0Kr_iWKC4Ry_ucPoh4b_BB2C8Ck_WrfWkPR_Tzig2T1_tdhst4b_3Bysn6k_i4ffhPR_yhig2T1.jpg
I'm worried about the new name because normally it should be tesla_CKBw0Kr.jpg or something smaller, so what's the problem in my code & how can we fix that?
Django mangles the image filename so that you don't run into filename collisions in the filesystem. Consider what if you had to save another image named tesla.jpg and don't want it to accidentally overwrite the first one.
You don't have to worry about that though. Django stores the real, original filename in the UploadeFile object.
UPDATE
Django will keep adding random characters to the filename if you upload more files with the same filename:
https://github.com/django/django/blob/master/django/core/files/storage.py#L60-L89
If you worry about hitting the filesystem's filename length limit, then set an appropriate max_length on the ImageField. The function will then keep truncating the file_name and generating new names within the filename length limit, until it finds a free name.