django: how to update an existing file in FileSystemStorage - django

The goal is to update the content of an existent file identified by 'filename'.
The first save call (aStorage.save(filename, ContentFile(content1)) creates the file 'test1'.
The second save call (aStorage.save(filename, ContentFile(content2))) creates a new file (done by Storage.get_available_name) instead of updating the current one.
>>> from django.core.files.storage import FileSystemStorage
>>> from django.core.files.base import ContentFile
>>> import sys
>>> sys.path.append('/home/project1')
>>> import os
>>> os.environ['DJANGO_SETTINGS_MODULE']='project1.settings'
>>> from django.conf import settings
>>> aStorage = FileSystemStorage(location=settings.BASE_DIR)
>>> content1 = "1514 – Mary Tudor (pictured), sister of Henry VIII of England"
>>> content2 = "1874 – The Universal Postal Union, then known as the General Postal"
>>> filename = os.path.join(settings.BASE_DIR, 'tests', 'test1')
>>> aStorage.save(filename, ContentFile(content1))
'./tests/test1'
>>> aStorage.save(filename, ContentFile(content2))
'./tests/test1_ESZ5jdM'
One solution might be this one here:
>>>>if (aStorage.exists(filename)):
>>>> aStorage.delete(filename)
>>> aStorage.save(filename,ContentFile(content2))
`'./tests/test1'`
Is there any other mechanism/workaround to achieve the same functionality ? Thank you.

IF you want to "overwrite" the file, you can go with your own custom Filestorage like this:
class MyFileSystemStorage(FileSystemStorage):
def get_available_name(self, name):
if os.path.exists(self.path(name)):
os.remove(self.path(name))
return name
In this case the file will be deleted so that a file with the same name can be created. This feels like it would be overwritten. Hope this is what you are looking for.
Update:
MyFileSystemStorage is a small custom class which inherits from FileSystemStorage and overwrites the "default" get_available_name function from Djangos FileSystemStorage. You do not need to use this function directly. Its transparently handled if you save a FileObject.
You can use it like this:
aStorage = MyFileSystemStorage(location=settings.BASE_DIR)
If you use MyFileSystemStorage instead of Django FileSystemStorage and save a file with a certain name, an already existing file with that name will be deleted and a new one will be created with the given name. Be careful to use the code like this because any existing file will be "overwritten" if it already exists. If I follow your example correctly you want this behaviour, so I think that it wouldnt not have an impact on your existing code.

It's not clear to me in which situation I can use save method. Therefore, for the moment, I prefer not to change/overwrite the Django Storage.save/get_available_name method behavior. This sounds like another solution to my problem : to use the Storage.open method instead of Storage.save:
>>> content1 = "11111111"
>>> content2 = "22222222"
>>> aStorage
<django.core.files.storage.FileSystemStorage object at 0x7f94ffccc6d0>
>>> fd = aStorage.open("test1.txt","w+")
>>> fd.write(content1)
8
>>> fd.seek(0)
0
>>> fd.read()
'11111111'
>>> fd.close()
>>>
>>> fd = aStorage.open("test1.txt","w+")
>>> fd.read()
''
>>> fd.write(content2)
8
>>> fd.seek(0)
0
>>> fd.read()
'22222222'
>>> fd.close()
>>> aStorage.exists("test1.txt")
>>> True
I will appreciate if you could share with me a situation for the usage of Django's Storage.save method. I am looking here a real case situation. Thanks.

Related

Django REST Framework internal value

I have a simple serializer with a date field (not ModelSerializer).
class MySerializer(Serializer):
some_date = DateField()
I'm trying to access the date object after deserialization.
slz = MySerializer(data={"some_date": "2020-05-03"})
# I surely have a better error handling in my actual code
assert slz.is_valid()
some_extracted_date = slz.data["some_date"]
I would like my variable some_extracted_date to be a datetime.date instance.
But the value in the MySerializer.data dict is a string.
Is there a way to get this datetime.date instance ?
You access data after validation using validated_data.
>>> from app.models import MySerializer
>>> slz = MySerializer(data={"some_date": "2020-05-03"})
>>> slz.is_valid(True)
True
>>> slz.data
{'some_date': '2020-05-03'}
>>> slz.validated_data
OrderedDict([('some_date', datetime.date(2020, 5, 3))])
>>> slz.validated_data['some_date']
datetime.date(2020, 5, 3)

Is django model field lookup_type 'contains' case-sensitive or insensitive..?

As per documentation 'contains' field lookup is case-sensitive and 'icontains' is case-Insensitive, but I don't see any difference while i'm querying it.
>>> from users.models import SnetUser
>>> SnetUser.objects.get(email__contains='Satti')
<SnetUser: satti>
>>> SnetUser.objects.get(email__contains='satti')
<SnetUser: satti>
>>> obj = SnetUser.objects.get(email__contains='satti')
>>> obj.email
'satti#gmail.com'
Both are resulting same.
Note: I'm using django's SQLite DB locally
This case is written in the docs.
contains field lookup is being converted to LIKE clause and in SQLite it is case-insensitive.
In case you want to make LIKE clause to work case-sensitively, you need to use the following PRAGMA:
PRAGMA case_sensitive_like = true;
>>> from django.db import connection
>>> with connection.cursor() as cursor:
... cursor.execute('PRAGMA case_sensitive_like = true;')
>>> SnetUser.objects.get(email__contains='Satti')
<QuerySet []>

In django-guardian, how can I get all objects user has any permissions for

In django-guardian, how can I get all objects user has any permission for (through groups as well). There is a shortcut to get all users having any permission over an object, but I am searching for all objects a given user has any permission over.
get_objects_for_user()
>>> from guardian.shortcuts import get_objects_for_user
>>> joe = User.objects.get(username='joe')
>>> get_objects_for_user(joe, 'auth.change_group')
[]
>>> from guardian.shortcuts import assign_perm
>>> group = Group.objects.create('some group')
>>> assign_perm('auth.change_group', joe, group)
>>> get_objects_for_user(joe, 'auth.change_group')
[<Group some group>]
For any permission you could type the codenames in a list yourself, or use get_perms_for_model().
>>> group_perms = [perm.codename for perm in get_perms_for_model(Group)]
>>> get_objects_for_user(joe, group_perms, klass=Group, any_perm=True)
[<Group some group>]

How to get a model object using model name string in Django

Desciption:
I have a generic function
def gen(model_name,model_type):
objects = model_name.objects.all()
for object in objects:
object.model_type = Null (Or some activity)
object.save()
How Can I achieve the above ? Is it possible?
I would use get_model:
from django.db.models import get_model
mymodel = get_model('some_app', 'SomeModel')
As of Django 1.7 the django.db.models.loading is deprecated (to be removed in 1.9) in favor of the the new application loading system. The 1.7 docs give us the following instead:
$ python manage.py shell
Python 2.7.6 (default, Mar 5 2014, 10:59:47)
>>> from django.apps import apps
>>> User = apps.get_model(app_label='auth', model_name='User')
>>> print User
<class 'django.contrib.auth.models.User'>
>>>
if you pass in 'app_label.model_name' you could use contenttypes e.g.
from django.contrib.contenttypes.models import ContentType
model_type = ContentType.objects.get(app_label=app_label, model=model_name)
objects = model_type.model_class().objects.all()
The full answer for Django 1.5 is:
from django.db.models.loading import AppCache
app_cache = AppCache()
model_class = app_cache.get_model(*'myapp.MyModel'.split('.',1))

How can i overwrite dir/help method on module?

>>> import module1
>>> dir(module1)
['__builtins__', '__doc__', '__file__', '__name__', '__package__']
I try putting some functions like this to module1 code:
def __dir__(self):
return 'ok'
def __dir__():
return 'ok'
def __dir__(self):
print 'ok'
def __dir__():
print 'ok'
... but nothing of those works. How good writen overwriting dir function should look?
I want something like this:
>>> import module1
>>> dir(module1)
'ok' [or ok]
Your question is asking how to modify the behavior of dir() on module objects, but in your comments you clarified that your ultimate goal is to modify the behavior of help(module). dir works differently on different objects, and I don't believe there is a direct way to change that for a module. It will simply always want to list the attributes of the module being everything in the scope.
What you can do though, is define an __all__ attribute in your module, and specify which attributes should be made public in the help doc:
mymodule
__all__ = ['foo']
foo = 'bar'
class Klass(object):
pass
>>> import mymodule
>>> help(mymodule)
You will see that because Klass was excluded from __all__ it will not be visible in the help.
Also, if you do from mymodule import *, only the foo attribute will be imported:
>>> from mymodule import *
>>> dir()
# ['__builtins__', '__doc__', '__name__', '__package__', 'foo']