How does Django work with either instance id and instance itself? - python

For instance django queryset's filter takes either instance or instance_id.
Probably django code needs id for Database query, and it extracts instance_id when it receives instance
Although I don't remember, there could be a scenario where django would want instance but receives instance_id .
How does django handle such cases? just do typechecking with isinstance(something, models.Model) and do something with it?

Related

How do I ensure that certain model instances are always present in django database?

My django-application requires a few model instances to always be present in the database to function properly.
I currently create the model instances that I require in the Appconfig.ready(self) method for the corresponding app. This way the instances are always present on boot of the django-application. This works but not as well as I'd like, I have to be careful when deleting objects so that I do not delete the required objects.
I would like the required model instances to be undeletable or preferably, be created whenever they are not present in the database.
I agree with your solution about protecting certain objects from deletion in you problem. To do this there are two ways I can think of:
When deletion is happening check to see if object is protected or not
Tweak admin permissions and do not let anyone delete the object from admin panel
The main difference is in first way your only way to delete protected objects is from your database command line interface, However in second way the model can be deleted in code.
For the first way you need to override delete method of the model and check something like this
assert pk != self.protected_objects
Where protected objects list is a property of your model class.
For second way you would do
class YourModel(admin.ModelAdmin):
protected_objects = [1,2,...]
def has_delete_permission(self, request, obj=None):
return obj.pk not in self.protected_objects

How to create a Django REST Framework View instance from a ViewSet class?

I'm trying to unit test Django REST Framework view set permissions for two reasons: speed and simplicity. In keeping with these goals I would also like to avoid using any mocking frameworks. Basically I want to do something like this:
request = APIRequestFactory().post(…)
view = MyViewSet.as_view(actions={"post": "create"})
self.assertTrue(MyPermission().has_permission(request, view))
The problem with this approach is that view is not actually a View instance but rather a function which does something with a View instance, and it does not have certain properties which I use in has_permission, such as action. How do I construct the kind of View instance which can be passed to has_permission?
The permission is already tested at both the integration and acceptance level, but I would like to avoid creating several complex and time-consuming tests to simply check that each of the relevant actions are protected.
I've been able to work around this by monkeypatching a view set instance and manually dispatching it:
view_set = MyViewSet()
view_set.action_map = {"post": "create"}
view_set.dispatch(request)
You can do something like below.
request = APIRequestFactory().post(…)
view_obj = MyViewSet()
self.assertTrue(MyPermission().has_permission(request, view_obj))

Making Django's CBV's get an instance method

I'm currently building a Django app which uses a singleton object.
I want to save this object as a CBV variable because I dont want to initialize it for every 'get' call.
My question in short - can you make a CBV's get function an instance method instead of a classmethod?
And if so, can I save a variable as an instance variable?
EDIT - A better explanation to my question:
I created a class that handles a serialized connection with an electronic measurment instrument.
This class must have only 1 instance (singleton), if another instance will be created a memory leak will crash python.
I want to use it with django in the following way:
Get request to a certain url address ->
The view will ask the instrument class instance for data->
Instance responds with data ->
View returns a JsonResponse with the data.
I think the best way to do it is making the CBV's get method (whose related to the url im getting from) an instance method, but its not such a good practice..
How should I do it?
As I said, get is an instance method.
But you are confusing responsibilities here. A class should have one responsibility only. The view class has the responsibility of responding to the request and returning a response; this is quite separate from the connection to the instrument. That should be a separate class, which is instantiated at module level and used within the view class.

In Django, can I specify database when creating an object?

Look at this Django ORM code:
my_instance = MyModel()
my_instance.some_related_object = OtherModel.objects.using('other_db').get(id)
At this point, in the second line, Django will throw an error:
ValueError: Cannont assign "<OtherModel: ID>": instance is on database "default", value is on database "other_db"
To me, it doesn't make much sense. How Django can tell on which database my_instance is, if I haven't even called:
my_instance.save(using='some_database')
yet?
I guess, that during the construction of an object Django automatically assigns it to the default database. Can I change it? Can I specify database when creating an object, by passing an argument to its constructor? According to the documentation, the only arguments I can pass, when creating an object are the values of its fields. So how can I solve my problem?
In Django 1.8 There is a new method called Model.from_db (https://docs.djangoproject.com/en/1.8/ref/models/instances/) but I'm using earlier version of Django and can't switch to the newer now. Looking at the implementation all it does is setting two model's attributes:
instance._state.adding = False
instance._state.db = db
So would it be enough to change my code to:
my_instance = MyModel()
my_instance._state.adding = False
my_instance._state.db = 'other_db'
my_instance.some_related_object = OtherModel.objects.using('other_db').get(id)
or it is too late to do it because those flags are used in constructor and have to be set in constructor only?
You might want to look into database routing, which has been supported since Django 1.2. This will let you setup multiple databases (or "routers") for different models.
You can create a custom database router (a class inheriting from the built-in object type), with db_for_read and db_for_write methods that return the name of the database (as defined in the DATABASES setting) that should be used for the model passed into that method. Return None to let Django figure it out.
It's usually used for handling master-slave replication, so you can have a separate read-only database from your writeable one, but the same logic would apply to let you specify that certain models live in certain databases.
You would probably also want to define an allow_syncdb method so that only the models you want to appear in database B will appear there, and everything else will appear in database A.
Django knows what database each object comes from because it notes it such in its internal properties. The QuerySet too has this information stored within itself.
Actually, database routing isn't really needed to achieve what you want here.
Consider the following code fragment:
my_instance = MyModel()
my_instance.some_related_object_id = OtherModel.objects.using('other_db').get(id).id
Note how I assign just the ID, not the object itself.
You will lose the actual object here, but gain the ability to store referential data.
AFAIK there's no API to change an object's associated database.

Django model attribute to refer to arbitrary model instance

I'm working on a logging app in Django to record when models in other apps are created, changed, or deleted. All I really need to record is the user who did it, a timestamp, a type of action, and the item that was changed. The user, timestamp, and action type are all easy, but I'm not sure what a good way to store the affected item is beyond storing an id value and a class name so the item can be retrieved later. I imagine that storing the class name will result in a bit of a hacky solution in order to find the actual class, so I'm wondering if there's a better way. Does anyone know of one?
Use generic relations which do just that (use instance id and model class) but are integrated in Django and you also get a shortcut attribute that returns related instance so you don't have to query it yourself. Example usage.
Check out generic relations.

Categories