Django. self.file.path does not include upload_to subdirectory - python

I'm trying to get some information from a file before the Model is saved to the database.
So basically what i'm doing it is overwriting method save like follow:
class Media(models.Model):
file = models.FileField(upload_to='audio/')
def save(self, *args, **kwargs):
if not self.id:
print self.file.path
super(Media, self).save(*args, **kwargs)
But when I print attribute self.file.path is does not include "audio/" subdirectory.
Instead of this '/Users/me/Dropbox/Public/music/audio/myfile.ext'
I'm getting
'/Users/me/Dropbox/Public/music/myfile.ext'
The file is located where it suppose to be. In
'/Users/me/Dropbox/Public/music/audio/myfile.ext'
My
MEDIA_ROOT = '/Users/me/Dropbox/Public/music'
What I've missed?
UPDATE:
Looks like it add 'audio/' to the path after it save the model.

Related

Catching bulk events in Django

I have Book model. It has some fields like title, year publish and etc. Also, i have overrided save() method. When new books is adding, it checks if book exsists, it creating new directory with name self.title in MEDIA_ROOT path.
def save(self, *args, **kwargs):
book_dir = os.path.join(MEDIA_ROOT, self.title)
# check that at least one file is loading
if all([self.pdf, self.fb2, self.epub]):
raise ValidationError("At least 1 file should be uploaded!")
# create book's directory if it not exists
if os.path.exists(book_dir):
raise ValidationError("This book is already exists!")
else:
os.mkdir(book_dir)
# rename and edit storage location of books to book_dir
for field in [self.image, self.pdf, self.fb2, self.epub]:
field.storage.location = book_dir
super().save(*args, **kwargs) # Call the "real" save() method.
Also i have overrided delete() method, that just remove directory of deleted book.
def delete(self, *args, **kwargs):
book_dir = os.path.join(MEDIA_ROOT, self.title)
rmtree(book_dir)
super().delete(*args, **kwargs) # Call the "real" delete() method.
delete() method works well if i delete only 1 book.
But, if i want to delete multiple files (all actions take place in the admin panel), only DB records got deleted.
So, i want to just catch this moment to remove directory of deleted book.
Looks like pre_delete signal could be useful here: https://docs.djangoproject.com/en/2.2/ref/signals/#pre-delete

Django EventLog: Passing in current user

I am trying to add logging to my Django app using EventLog. I followed an example online but not sure how to pass in the user that makes the changes. The example shows it as user=self.user. Obviously this wouldn't work in my case as it doesn't refer to anything in my model
models.py
class Client(models.Model):
name = models.CharField(max_length=50)
....
def save(self, *args, **kwargs):
# Initial Save
if not self.pk:
log(user=self.user, action='ADD_CLIENT',
extra={'id': self.id})
else:
log(user=self.user, action='UPDATED_CLIENT',
extra={'id': self.id})
super(Client, self).save(*args, **kwargs)
The save method will only know what has been passed into it, this will normally not include the request which is where you would get the current user (request.user).
You should instead add logging in the view which is calling the save method.
user = request.user

Dynamic File Path in Django and South

I'm having a problem setting a dynamic path to my imageField.
This is my models.py
class Imagen(models.Model):
def get_upload_path(self, filename):
return os.path.join(
"img/experiencias/experiencia_%d" % self.id_experiencia.id, 'ficha' + '_' + filename)
nombre = models.CharField(max_length=50)
id_experiencia = models.ForeignKey(TipoExperiencia)
imagen = models.ImageField(upload_to= get_upload_path)
caption = models.CharField(max_length=150,blank=True)
alt = models.CharField(max_length=100)
This is a solution that I've found here
This actually works fine when updating objects, but when I try to insert new elements, the inserts fail because in that moment self does not exists.
I've tried another solution here whose proposal is overriding the ImageField method to customize upload_to.
The problem is that I use South and it's quite difficult to manage custom fields
I use Django 1.5. I would like to know if exists any easy way to manage dynamic file path in django
Thanks
Alternatively you can override the save method to move the file to the correct path.
class Model(models.Model):
def save(self, *args, **kwargs):
instance = super(Model, self).save(*args, **kwargs)
# your logic here to change the file location
return instance
I think you can get away here with Unipath.
Unipath usage

Initialize Django Form FileField

I have a Django form class like;
class FileDefinitionForm(ModelForm):
fileContent = forms.FileField(required=False)
def __init__(self, *args, **kwargs):
super(FileDefinitionForm, self).__init__(*args, **kwargs)
????Initialization of file field which is named "fileContentUpl" ???
I have my file as string which is base64 decoded and I need to put the file to my fileField on initialization to show it in html. I tried someting but i couldn't make it works. Is there a way to do this ?
Thank You.

Django: Save a FileField before calling super()

I need to save an uploaded file before super() method is called. It should be saved, because i use some external utils for converting a file to a needed internal format. The code below produce an error while uploading file '123':
OSError: [Errno 36] File name too long: '/var/www/prj/venv/converted/usermedia/-1/uploads/123_1_1_1_1_1_1_1_1_1_1_1_1_1_1_1_1_1_1_1_1_1_1_1_1_1_1_1_1_1_1_1_1_...'
It seems, that it tries to save it in super().save() twice with the same name in an infinite loop. Also, it creates all these files.
def save(self, **kwargs):
uid = kwargs.pop('uid', -1)
for field in self._meta.fields:
if hasattr(field, 'upload_to'):
field.upload_to = '%s/uploads' % uid
if self.translation_file:
self.translation_file.save(self.translation_file.name, self.translation_file)
#self.mimetype = self.guess_mimetype()
#self.handle_file(self.translation_file.path)
super(Resource, self).save(**kwargs)
EDIT:
Here is inelegant way i wanted to get around (it will double call save() method):
def save(self, *args, **kwargs):
uid = kwargs.pop('uid', -1)
for field in self._meta.fields:
if hasattr(field, 'upload_to'):
field.upload_to = '%s/uploads' % uid
super(Resource, self).save(*args, **kwargs)
if self.__orig_translation_file != self.translation_file:
self.update_mimetype()
super(Resource, self).save(*args, **kwargs)
You got an infinite loop in your first example, thats right.
Calling self.translation_file.save(self.translation_file.name, self.translation_file) will save the uploaded file to disk and call the Resources class save method again because the methods save paramter defaults to true (have a look here https://docs.djangoproject.com/en/dev/ref/files/file/#additional-methods-on-files-attached-to-objects) as well as your custom FileField does anyway.
Calling it like this (just add save=False) is more likely to work:
self.translation_file.save(self.translation_file.name, self.translation_file, save = False)
I hope this points into the right direction.

Categories