updated file name in django - python

This is an admin form handler, for example I upload a test.txt file in the django admin panel:
def save_model(self, request, obj, form, change):
if 'file' in form.changed_data:
print("file has changed: ")
print(obj.file)
else:
print("file has not changed")
super(FileAdmin, self).save_model(request, obj, form, change)
here I get the original file name from the upload form, but by fact the file is saved with another name if there is already a file with this name, but in the above code i get only the original name in all cases, how to can I get the changed/updated file name that was saved?..

The "_somehash" part is added by your project's filestorage when he sees there's already a file by the same name in the destination directory. This happens when the model instance is saved, so if all you need is to read the "final" name, you can get it from your (saved) model field's .name attribute (I assume you use a FileField of course).

Related

How to get the file object in `request.data` in Django?

Upload a tar file.
How to get the file object in request.data?
class AlbumViewSet(viewsets.ModelViewSet):
#action(methods=['POST'], detail=False, url_path='upload-album')
def upload_album(self, request):
# Upload one tar file.
logging.error("----> request.data = {}".format(request.data))
Thanks
You can get file object in request.FILES.
request.FILES is dictionary like object containing all uploaded files. You can access your file object by its name, like this: request.FILES['my-file-name']
For example, if you want to log filename::
class AlbumViewSet(viewsets.ModelViewSet):
#action(methods=['POST'], detail=False, url_path='upload-album')
def upload_album(self, request):
# Upload one tar file.
logging.error("----> Uploaded file name = {}".format(request.FILES['my-file-name'].name))
Check here for more details.

FileField PDF Won't Open Django

I am creating and saving a PDF as such in my views:
views.py
#login_required(login_url="/login")
def PackingListView(request):
if request.method == "POST":
form = PackingListForm(request.POST)
if form.is_valid():
if 'preview' in request.POST:
...
elif 'save' in request.POST:
pdf_contents = form
file = ContentFile(pdf_contents)
item = PackingListDocuments.objects.get(pk=1)
item.PackingListDocument.save('test.pdf', file) #saving as FileField in model
form.save()
messages.success(request, "Success: Packing List Has Been Created!")
return redirect('HomeView')
I see that the test.pdf is saved. I can see it in my file explorer as well as in the admin, but every time that I attempt to open it, the file seems to be corrupted. What do I need to add or subtract in my code to get this working?
Thanks!
UPDATE:
I've changed the line: file = ContentFile(pdf_contents) to file = File(pdf_contents)
But now I am receiving an attribute error that 'PackingListForm' object has no attribute 'read'
I believe the error must be to do with this line
file = ContentFile(pdf_contents)
Note that, from the docs
The ContentFile class inherits from File, but unlike File it operates on string content (bytes also supported), rather than an actual file. For example:
So my guess is that you are not passing in a string/byte type as argument to the ContenetFile object.
Try finding the type of it. You can also convert it to string type by doing String(pdf_contents).

"Upload" file from disk in Django

I generate a file in python, and want to "upload" that file to the django database. This way it is automatically put inside the media folder, and organized neatly with all other files of my application.
Now here is what I tried: (type hinting used, since it's python 3.6)
# forms.py
class UploadForm(forms.ModelForm):
class Meta:
model = UploadedFile
fields = ('document',)
# models.py
class UploadedFile(models.Model):
document = models.FileField(upload_to=get_upload_path)
# mimetype is generated by filename on save
mimetype = models.CharField(max_length=255)
# ... additional fields like temporary
def get_upload_path(instance: UploadedFile, filename):
if instance.temporary:
return "uploaded_files/temp/" + filename
return "uploaded_files/" + filename
# views.py, file_out has been generated
with open(file_out, 'rb') as local_file:
from django.core.files import File
form = UploadForm(dict(), {'document': File(local_file)})
print(form.errors)
if form.is_valid():
file = form.save(commit=False)
# ... set additional fields
file.save()
form.save_m2m()
return file
Now this is not the only thing I've tried. First I've gone with setting the FileField directly, but that resulted in the save() to fail, while the mimetype field is set. Because the original file sits outside the media folder, and thus a suspicious file action is triggered.
Also, the form gives some feedback about the "upload", through the form.errors.
Depending on my approach, either the save() fails as mentioned above -- meaning the "uploading" does not actually copy the file in the media folder -- or the form returns the error that no file was transmitted, and tells to check the form protocol.
Now my theory is, that I would have to go and initialize my own instance of InMemoryUploadedFile, but I could not figure out how to do that myself, and no documentation was available on the internet.
It feels like I'm taking the wrong approach from the get go. How would one do this properly?
Do you have get_upload_path defined? If not, that would explain the errors you're getting.
From what I can see you're on the right track. If you don't need a dynamic path for your uploads, if you just want them in media/uploads, you can pass in a string value for upload_to (from the Django docs):
# file will be uploaded to MEDIA_ROOT/uploads
document = models.FileField(upload_to='uploads/')
First of all, thanks to Franey for pointing me at storage documentation which lead me to contentfile documentation.
The ContentFile actually solves the problem, because it basically is the self-instantiated version of InMemoryUploadedFile that I was looking for. It's a django File that is not stored on disk.
Here's the full solution:
# views.py, file_out has been generated
with open(file_out, 'rb') as local_file:
from django.core.files.base import ContentFile
# we need to provide a name. Otherwise the Storage.save
# method reveives a None-parameter and breaks.
form = UploadForm(dict(), {'document': ContentFile(local_file.read(), name=name)})
if form.is_valid():
file = form.save(commit=False)
# ... set additional fields
file.save()
form.save_m2m()
return file

How to implement a script while saving a file in django admin panel?

I'm new to django.
I want to run a script(for ex. zipping a file) after it gets uploaded to a server through "admin panel",i.e when user hits Save "in" from admin panel,it should get zipped(or some other manipulation that i may want to implement) after it gets uploaded.
Or can you just tell me which function is called when user hits the save button.
Signals might work, but it seems like the OP wants to do something only when an object is created or changed from the admin panel.
I think the best way to do this is to use the ModelAdmin method save_model().
From the Django docs:
ModelAdmin.save_model(self, request, obj, form, change)
You can overwrite this method in your definition of an admin class, as follows:
class SomeObjectAdmin(admin.ModelAdmin):
def save_model(self, request, obj, form, change):
# do any pre-save stuff here
obj.save()
The change arg is a Boolean value that is True if the object is being changed, and false if the object is being created for the first time. So if you want to execute some function only on object creation:
def save_model(self, request, obj, form, change):
if not change:
# do your compression here
# do any other pre-save stuff here
obj.save()
# do any post-save stuff here
You may use signals : https://docs.djangoproject.com/en/dev/topics/signals/
to detect the save action.

save_model method in django admin barfs on update

I'm using this snippet from the documentation:
class ArticleAdmin(admin.ModelAdmin):
def save_model(self, request, obj, form, change):
obj.user = request.user
obj.save()
I've used the admin site and successfully created entries in the model, but now when I try to edit the entry, clicking submit generates a TypeError:
Database is trying to update a relational field of type CharField with a value of type User. Make sure you are setting the correct relations
I don't understand why it would throw this error now and not during the initial creation.
Is there a way around it?
ADDENDUM:
Reexamining the traceback for the error above, I also took at look at the local variables. It looks like there isn't any username information at all in the request variable, so I'm having my doubts that this works at all in the case of an update.
PS Since the traceback only shows a picture of the request object, the 'user' attribute is probably not displayed, but it could be there.
PPS: I found that the documentation on the user attribute explains that middleware must be activated, and when I check, I see that Heroku already added those settings for me. The attribute is indeed django.contrib.auth.models.User, whose username attribute is what I'm looking for.
It says that, whatever class obj belongs to, the user attribute of that class is not a foreign key to the User class that you are referring to, but just a CharField. Change the type of that attribute in the class that obj belongs to, migrate the database and then you will find this working.
If you just want it to be a string, not a foreign key relation, then use:
class ArticleAdmin(admin.ModelAdmin):
def save_model(self, request, obj, form, change):
obj.user = request.user.username
obj.save()

Categories

Resources