Django 1.3 removing images - django

Django 1.3 do not removes file which was deleted from database. I'm not found how to set Django remove deleted files. Is it possible? If so, how?

Simple:
Override the delete and save and method in your model. Remember that a file can both be dereferenced by the deletion of the object, but also by uploading a new file. But beware that the delete method is not called when you delete in bulk, ie. QuerySet.delete().
https://docs.djangoproject.com/en/dev/topics/db/models/#overriding-model-methods
You can also use signals:
https://code.djangoproject.com/wiki/Signals
But beware! The reason why Django does not automatically delete the file, is that it cannot guarantee that the file is not refered to by some other application or model. But if you can guarantee that as a programmer, go ahead.
This blog article gives you the best possible info, I think:
http://haineault.com/blog/147/

Related

Delete Django ImageField and FileField records whose files are not found on the server

I've recently lost some files in my media folder, and I want to delete the image field/FileField objects whose files have been removed, across all models of my application.
I've tried django-cleanup, but it appears to be doing the inverse operation, i.e. deleting files on the server whose objects have been removed from the database.
You can write a management command for this, here is a way how to handle this
Class cleanup(BaseCommand):
def handle(self,options):
for obj in Files.objects.all():
if os.path.exists(settings.MEDIA_DIR+ obj.filename): continue
obj.delete()
Note that a FileField will be falsy if the file is not there, so you can use this simple solution:
for instance in ModelWithFileField.objects.all():
if bool(instance.file_field):
continue
instance.delete()
You can even do it in a django shell, so you do not have to write a script for it.

Django: Save ContentFile (or some kind of virtual file) to database

In my django app I create a string which I have to save to my database as a File.
If i understand correctly, django is supposed to automatically upload the file when I save the entry:
class Foo(models.Model):
bar1=models.ForeignKey(Table1)
bar2=models.ForeignKey(Table2)
res=models.FileField(upload_to='MYPATH')
The problem is that to create an instance of Foo, I have to first create a physical file on the server's disk which would mean two copies would be created (one by me in order to create a database entry, one by django when saving the entry).
As far as I can see, I must create the file myself in 'MYPATH' and instead of using a FileField, I have to save a reference in the database (essentially what django is doing ????). However I have doubts that this is the best method as
It doesn't strike me as Pythonesque.
I won't have access to the same methods as when using a real FileField. For instance when calling it, I won't have a FieldFile but just a reference string.
Basically, what I wanted to do was: String --> ContentFile (or some form of "virtual" file) --> Physical File handled by Django when saving entry in the database.
entry = Foo(bar1=var1, bar2=var2, res=ContentFile(XMLSTRING))
entry.save()
This doesn't work, but it shows what I want to achieve.
So, please show me one of the following three:
How to save a file to the database without physically creating it (using a ContentFile doesn't create a physical file after saving the entry which is what I want to do)
Make django not upload the given file but use the already uploaded version whilst maintaining all the methods provided by FileField
What I don't understand.
I apologize for [my english, my lack of understanding, the lack of clarity]
Anything you need to know, I'd happy to specify.
EDIT: I looked at this thread, but there, the urlretrieve creates a temp file, which is something I don't really want to do. Maybe I should be doing that, but is there a better way?

Use validation to prevent duplicate file _name_ being uploaded

How can I detect that the name of a file that a user has provided for upload (via a django.forms.ModelForm using a FileField field) is a duplicate of one that exists, and thus decide to fail validation on the form?
I'm finding this particularly challenging, because from within the form, I don't see how I can find out what the value of upload_to is for this FileField, so I can't go looking myself in the file system to see if that file is there already.
As i see it you have 2 options:
Set a value in your settings.py to hold your 'upload_to' and then use it to check when you are validating.
Something like this to verify would work (you need to change your upload_to ofc):
from django.conf import settings
if settings.UPLOAD_TO:
# Do something
Issue with that is that you can't have subfolders or anything complex there.
A second option would be, as mentioned in your comments, to add a new column to your model that holds a hash for your file. This approach should work better. As someone mentioned in your comments, to avoid uploading a big file, checking, failing, uploading another big file, etc, you can try to hash it in the client and verify it via ajax first (you will verify it again in the server, but this can make things go faster for your users).
Older question, but Django 1.11 now supports the unique option on FileField. Set unique=True on your field declaration on your model.
It shouldn't matter what you are setting upload_to to. The file name will still be stored in the database.
Changed in Django 1.11:
In older versions, unique=True can’t be used on FileField.
https://docs.djangoproject.com/en/1.11/ref/models/fields/#unique

Django delete without calling signals

I use signals for things that should always be done when an object is deleted, saved, updated, etc. However, there are times when I don't want to call my save signals, so I use
Model.objects.filter(id=instance.id).update(field=value)
instead of the instance's save method:
instance.save()
In the case of deleting objects, there are also times when I don't want to call the delete signals, but I haven't found a way to avoid calling them. Is there a way??
UPDATE:
I'm using django 1.6.2 and calling the delete method like this:
Model.objects.filter(id=instance.id).delete()
on the queryset still still calls the delete signal.
There is unsafe and undocumented way which probably can change between versions and also can lead to unexpected consequences which will be hard to debug.
This is a hack that probably you don't want to use but.... it's possible.
qs = Model.objects.filter(id=instance.id)
qs.order_by().select_related(None)._raw_delete(qs.db)
If you have any related objects to this one it will probably fail with database error because records will not be deleted automatically by Django
In the place where you don't want signals to be called, you have to disconnect them, run you code and then reconnect them again. You can take a look on how mute_signal decorator is implemented in FactoryBoy or just use (but it's basically intended for django tests)
You can do this.
Model.objects.filter(id=instance.id).delete()
Try using raw SQL and don't resist it. It is always a powerful ultimate weapon you could use.
from django.db import connection
with connection.cursor() as cursor:
cursor.execute(f'DELETE from tbl_model where id={instance.id}')

objects.get_or_create() or transactions in Django views

OK, objects.get_or_create(), when called, will create a new record in the database (if there is no record I need). But what if the code throws an exception/fails AFTER objects.get_or_create() has been called?
Basically, I end up with a new record in the database which should not be there. To put it differently, shouldn't the whole thing be wrapped in a transaction which is rolled back if there is a problem? Is it possible?
As Ignacio suggests the answer (in much greater detail than I would be capable of) is available in the django docs.
http://docs.djangoproject.com/en/dev/topics/db/transactions