How and where do I handle file uploads from django admin? - django

So ive read over the docs and I have come out a little confused. I have a model as such
class Image(models.Model):
name = models.CharField(max_length=80)
file = models.ImageField(upload_to = 'project_images')
description = models.CharField(max_length=30)
def __unicode__(self):
return self.name
The handling of the file uploads are done through the admin interface, which works but I need to do a few more things to the data based on other fields present when the upload is committed.
Basically the current directory is project_images what i want to do is when saved the images must be placed in ---> project_images/<year>/<month>. The file path saved must reflect this when saved in the database and the filename must also be saved in the name field.
I understand the logic behind doing this;
Check post
Check valid (the ImageField takes care of this already i assume)
Get filename
Get year and month (numbers)
Check if directories exist
If directories dont exist create it, if they do use them
Set the name to the filename
upload and save all
Where am i supposed to specify this? In the model under a save method?
Sorry if this is specified in the docs but this is one area of the docs which just confused me.
Thanks

from django.db import models
import datetime
import os
import uuid
# Create your models here.
def get_file_path(instance,filename):
ext=filename.split('.')[-1]
filename="%s.%s" % (uuid.uuid4(),ext)
return os.path.join(instance.directory_string_var,filename)
class Image(models.Model):
file=models.ImageField(upload_to=get_file_path)
now=datetime.datetime.now()
directory_string_var = 'image/%s/%s/%s/'%(now.year,now.month,now.day)
change your model to above one.
this saves your file with a random name in the folder media/year/month/day.
if you don't want filename to be random just comment out
ext = filename.split('.')[-1] #and
filename="%s.%s" % (uuid.uuid4(),ext)

check this:
how to create year/month/day structure when uploading files with django
So in your model, you can just do:
class Image(models.Model):
name = models.CharField(max_length=80)
file = models.ImageField(upload_to = 'project_images/%Y/%m')
description = models.CharField(max_length=30)
def __unicode__(self):
return self.name
The '%Y/%m' part of upload_to is strftime formatting; '%Y' is the four-digit year and '%m' is the two-digit month
You must check this to:
http://scottbarnham.com/blog/2007/07/31/uploading-images-to-a-dynamic-path-with-django/
I Hope this helped

Related

Changing file name on upload using id in Django ImageField

In this model, I want to change the name of the file uploaded in ImageField
class Product(models.Model):
image = models.ImageField(upload_to=content_file_name)
name = models.CharField(max_length=100)
amount = models.PositiveIntegerField()
class Meta:
ordering = ('name',)
def __str__(self):
return self.name
To change the name of image I'm using this function
def content_file_name(instance, filename):
ext = filename.split('.')[-1]
filename = '%s.%s' % (instance.id, ext)
return os.path.join('products', filename)
but the name of my image is None, if I use other fields like 'name', it works. What should I do to change the name with id? Thanks!
The instance's id is not yet created, because the upload_to function is called before the new object is first written to the database.
In most cases, this object will not have been saved to the database yet, so if it uses the default AutoField, it might not yet have a value for its primary key field.
Emphasis from the Django docs
Two alternatives:
Use a uuid.uuid4() value, its easy to create and as unique as the pk.
Another suggestion, if you care about search engines and SEO, use a slugify(instance.name) so that your images can be easier found in the image search of search engines.

How to change upload_to parameter of ImageField based on field name in Django?

I would like to upload images to the media root based on the field values given by the Django admin user. Here is the code that I've written and I know that the upload_to parameter is causing the problem. But I don't know how to make it work.
models.py
class Info(models.Model):
file_no = models.CharField(max_length=100)
date = models.DateField()
area = models.IntegerField(default=0.00)
mouja = models.CharField(max_length=100)
doc_type_choices = (
('deed', 'Deed'),
('khotian', 'Khotian'),
)
doc_type = models.CharField(max_length=50,
choices=doc_type_choices,
default='deed')
doc_no = models.CharField(max_length=50)
def __unicode__(self):
return self.file_no
class Image(models.Model):
info = models.ForeignKey('Info')
content = models.ImageField(upload_to=self.info.mouja/self.info.doc_type)
def __unicode__(self):
return self.info.file_no
Whenever I run python manage.py makemigrations it shows NameError: name 'self' is not defined
Thanks in advance for any help!
In the upload_to keyword you would need to provide a function that you will define, for instance:
def path_file_name(instance, filename):
return '/'.join(filter(None, (instance.info.mouja, instance.info.doc_type, filename)))
class Image(models.Model):
content = models.ImageField(upload_to=path_file_name)
From Django documentation: Model field reference:
This may also be a callable, such as a function, which will be called to obtain the upload path, including the filename. This callable must be able to accept two arguments, and return a Unix-style path (with forward slashes) to be passed along to the storage system.
Within this callable, which in the particular case is path_file_name function, we build a path from the instance field which is the particular record of Image model.
The filter function removes any None items out of the list and the join function constructs the path by joining all list items with /.
Here is the original code that worked. Just in case anyone needs it.
def path_file_name(instance, filename):
return '/'.join(filter(None, (instance.info.mouja, instance.info.doc_type, filename)))

Changing name of image uploaded

I'm a noob django developer, I can upload images but name of the images have to be changed to image ID or whatever I want.
In addition to this, when I delete entries, images are still resting in the media file but I don't want this.
What I have to add ?
Here is my models.py
from django.db import models
class Flower(models.Model):
name = models.CharField(max_length = 30)
price = models.IntegerField()
image = models.ImageField(upload_to = 'static/media')
def __unicode__(self):
return self.name
To customize the path and filename of where the files are stored, you'll need to define a method for upload_to. Here's an example:
def my_upload_to(instance, filename):
# "instance" is an instance of Flower
# return a path here
return 'my/path/to/storage/' + filename
class Flower(models.Model):
image = models.ImageField(upload_to=my_upload_to)
See https://docs.djangoproject.com/en/dev/ref/models/fields/#filefield
To delete the underlying file, you'll need to make a call manually:
flower = Flower.objects.get(id=1)
flower.image.delete()
You can choose to override your model's delete() method, or use signals pre_delete or post_delete to delete the associated files automatically.
See https://docs.djangoproject.com/en/dev/ref/models/fields/#filefield-and-fieldfile

saving an image as [self.id].jpg on DJANGO admin

I need an admin on django to be able to upload an image that should be saved as /path/{self.id}.jpg
So far I have a database with id,status,title fields and a model with id,status,title,THUMB fields:
class MEL(models.Model):
id = models.AutoField(primary_key=True, editable=False)
status = models.IntegerField(choices=( (0, 'inactive'), (1, 'active') ), default=1)
title = models.TextField(verbose_name='Título')
thumb = models.ImageField(upload_to=upload_path)
class Meta:
db_table = u'MEL'
The problem is that the image is uploaded previously to the model being saved, so I can't save it to "self.id" at this moment.
I think I could save it to /tmp/{uuid} and then renaming it post-save, probably something like:
def upload_path(self, filename):
self.file_uuid = uuid.uuid4()
return '/tmp/' + self.file_uuid
and then a post-save that renames it and delete it from /tmp/
Or I could try overriding this model's save() method to first call super().save(), then process the image upload (which is in a ImageFieldFile object) and rename it to self.id
suggestions?
thanks
You should be able to change the filename using upload_to. I say this because I have done it in projects and the django documentation says so:
https://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.FileField.upload_to
The third paragraph down of that link says this: "This may also be a callable, such as a function, which will be called to obtain the upload path, including the filename." [emphasis added]. I'm not trying to be sarcastic I'm just showing that this is and should be possible so something else must be going on.
try something like this. The problem could be that you were leaving off the extension:
def upload_path(self, filename):
basename, extension = os.path.splitext(filename)
return '/'.join(["path",("%s%s" % (self.id, extension))])

File uploads in Django: prevent FileField from writing the full path to the database

I'm building a software repository on top of the Django framework. Because it will contain a lot of files, i want it to make some sense when looking at it through a file manager. So i grouped the files first by the URL of a program they belong to and then by first two letters of that URL. Here's how it looks:
The schema looks like this:
class File(models.Model):
# If called like upload_to, don't put a slash in front of the result
# because we already have one in settings.MEDIA_ROOT
def get_absolute_url(self, filename=None):
return '%sfiles/%s/%s/%s' % ('' if filename else '/',
self.download.url[:2],
self.download.url,
filename or self.name)
name = models.FileField(upload_to=get_absolute_url, max_length=255)
size = models.IntegerField()
title = models.CharField(blank=True, max_length=255)
download = models.ForeignKey('Download', related_name='files')
class Download(models.Model):
url = models.SlugField(unique=True, max_length=255)
title = models.CharField(max_length=255)
There is, however, a minor problem: FileField will store the entire generated path instead of just the name, which i would rather like to avoid. Is there any way to override (probably in my own field class) what FileField writes to the database and how it reconstructs the path after loading the raw field?
name = models.FileField(upload_to=get_absolute_url, max_length=255)
upload_to usually looks like this
upload_to ='./files'
It will be stored as ./files/your.file in the db
and as <MEDIA_ROOT>/files/your.file at your disk
You can change the upload_to-String to whatever fits best for you programatically
upload_to ='./files'+'/subdir'
but it should start with './'
FileField-Reference
get_absolute_url() should return a url like http://domain.com/sitemedia/files/your.file
EDIT:
to remove the path from the file name you could do string operations in File.save() like
def save(self, force_insert=False, force_update=False):
self.name = self.name[self.name.rfind('/')+1:]
super(File, self).save(force_insert, force_update)