Django annotated queryset vs model properties - python

I have model with custom manager (replaced from properties) that annotate queryset by pseudo fields (adds some annotation inside get_queryset). And its cool because I have one database query per list and so on.
But in some cases this is a problem. For example I want to get my_annotated_field inside signal function or with Django Rest Framework on save ViewSet (where we didn't get object via my manager). Model class doesn't have those fields.
Is there way to solve this problem without extra query like obj = MyModel.objects.get(pk=obj.id)?

Related

Practical way to render form widget for a OneToMany relation in django. (Need to nest fields of multiple models in one auto generated form)

Let's say we have the following pseudo database structure:
models.py
class Order(models.Model):
...
class OrderItem(models.Model):
order = models.ForeignKey(Order, on_delete=models.CASCADE)
...
So each Order may contain one or more OrderItems.
By default, if I render the default form for these models, we will end up with two separate forms, where the user will have to create the Order first in one form, and then navigate to another form for OrderItem to start creating OrderItems for that Order.
Unless I create my own custom form from scratch (which is not integrated with any models) and then write the code to connect it with data models in the server-side. However, this is a very common use case so there has to be a way to handle such a scenario without having to rebuild so much from scratch.
Django already has a ManyToManyField which allows us to handle a similar kind of operation where what the user sees in the auto-generated form is simple, yet it involves interaction with multiple data models. How come there's no way to handle such form representation of data without having to do so much from scratch?
For example, in Django Rest Framework we can use Nested Relationships to define one model serializer as a field of another model serializer. But for Django models, I couldn't find any documentation for anything similar.

Call nested Serializer's .update() method

I have a JSONField in my model that stores some configuration data. I want to access this field (both read and write) with ability to make partial updates of inner fields and their values.
For purpose of example let a model be called MyModel with JSONField called config:
class MyModel(models.Model):
config = JSONField(default=dict())
...
I created a separate ViewSet to access information stored in config field. Assume that user model has ForeignKey relation to MyModel. Simplified version of this ViewSet is:
class ConfigurationFieldViewSet(mixins.RetrieveModelMixin, mixins.UpdateModelMixin, viewsets.GenericViewSet):
serializer_class = MyModelConfigurationSerializer
def get_object(self):
return self.request.user.my_model
Data stored in config has a certain structure with several possible inner objects:
{
"C1": {"counter": 42, "active": false},
"C2": {"counter": 13, "active": true}
}
To access and correctly serialize MyModel instance at all levels of nesting I have created serializers for each level of field. To acces config field in MyModel itself I'm using this serializer:
class MyModelConfigurationSerializer(serializers.ModelSerializer):
configuration = ConfigurationFieldSerializer(required=True)
class Meta:
model = MyModel
fields = ('configuration',)
To access and serialize first layer of configuration field there's second serializer:
class ConfigurationFieldSerializer(serializers.Serializer):
C1 = BaseConfigurationSerializer(required=True)
C2 = BaseConfigurationSerializer(required=True)
At last to access inner structure of each C1 and C2 fields there's third serializer:
class BaseConfigurationSerializer(serializers.Serializer):
counter = serializers.IntegerField(
required=False,
help_text=_('Some integer field help text')
)
active = serializers.BooleanField(
required=False,
help_text=_('Some boolean field description')
)
The code above works perfectly to read data stored in config field and correctly serializes it's inner objects. The problem appears when I try to perform a PUT on this field.
If I override update method at the level of MyModelConfigurationSerializer, then serializers verify data I'm submitting but as a chunk and I'm only able to save it all at once. If I'm trying to submit some inner field I still correctly receive validation errors by inner serializers.
def update(self, instance, validated_data):
instance.configuration = validated_data.get(
'configuration', instance.configuration
)
instance.save()
return instance
What I'm unable to do though is call update methods of inner serializers (ConfigurationFieldSerializer and BaseConfigurationSerializer in this case): if I implement their update methods they simply do not get called.
According to DRF Documentation writable nested representations are possible and corresponding update or create methods should be called whenever update is called on serializer of top level.
I've had this problem recently as well, and it looks like the way you are doing it is the "only way" when it comes to nested writable serializers.
From the same DRF docs you've probably already seen:
Because the behavior of nested creates and updates can be ambiguous, and may require complex dependencies between related models, REST framework 3 requires you to always write these methods explicitly. The default ModelSerializer .create() and .update() methods do not include support for writable nested representations.
There are however, third-party packages available such as DRF Writable Nested that support automatic writable nested representations.
Basically it means that when you have nesting it won't even try to call any of the nested serializer storage methods.
That may seem like a bit of a pain, but in retrospect it's probably better for the design of your application. Your example is pretty simple, but in other situations the ordering in which things are saved might be important. If update of each nested serializer was ran automatically then DRF would have to somehow know when to save each thing.
As an example, if your example was about create rather than update, it would mean that you need to first store your model MyModel before storing the configuration on top of it. However DRF cannot know that.
Also it could as easily have been that configuration was actually another related model which needed to be saved first before you could save a relation to it from MyModel. So DRF takes the route of just telling you to do it yourself, at the root serializer.
From my own experience this is also helpful to allow you to fine-tune performance later (ex. in your case you can avoid saving MyModel twice).
Finally, if you want to make your code more modular, you can still do it (send segments of the validated data to different handlers, eg to a new update_configurations() function), it just won't be done automatically using the nested serializers.

Is it possible to use a table in the database when it is NOT a Django model?

Is it possible get a queryset from a table in the app database that is NOT a model in the app?
If I have a table that is not a model named "cartable", conceptually, I want to do this:
myqueryset = cartable.objects.all()
Is there a relatively easy way to do this? Thanks!
If you want to access an existing table in your database that is not managed by your application, you can still create a class for it, and tell django to ignore it for migrations.
Just create a model and add the fields you need to access and then add a meta class to tell django to leave it alone.
class MyModel(model.Model):
class Meta:
managed = False
you can read about that at https://docs.djangoproject.com/en/1.9/ref/models/options/#managed
To do so you would need to create a class (not a model), with methods that use raw SQL. You should see more details here on how to do so: https://docs.djangoproject.com/en/1.9/topics/db/sql/#executing-custom-sql-directly
Please note that you will have to manually create the object with the right properties afterwards.
If you wanted to use Django ORM without the models, I don't think it is possible. You could however create a model that matches your db in a separate app and never create migrations for it to ensure you don't accidentally modify the DB.
Short answer is, "not really". Django QuerySet deals with model instances, so everything in QuerySet API is tied into models. Everything expects to return model instances, uses model fields etc.
That said, you should be able to create a model for an existing table. You will need to add db_table to the Meta, so Django knows where the table lives. If you have some indexing, you will need to make sure Django's idea of indexes is the same as the one in the database. indexed=True on fields and unique_together in Meta should help a lot with that.

How to define a Model with fields filled by other data sources than database in django?

Does anyone can tell me if it's possible to create a Model class, with some model fields and some other fields taking their data from external data sources. The point is that I would like this model to be exploited the same way as another model by ModelForm for instance. I mean if I redefine "objects" Manager of the model by specifying the actions to get the datas for special fields (those who may not be linked to datas from the database), would the modelForm link the input with the fields not attached to the database ? Similar question about related objects. If I have a Model that has a relation with that special Model, can I get this Model instances through the classic way to get related objects (with both the classic model fields and the non-database fields) ?
Please tell me if I'm not clear, I'll reformulate.
Thanks.
EDIT: I tried to make a Model with custom fields, and then override the default Manager and its functions: all, get, ... to get objects like it would be with classical Model and Manager, it works. However, I don't use QuerySet, and it seems that the only way to get ModelForm, related objects and the admin functionnalities, working with it, is to build the QuerySet properly and let it being returned by the manager. That's why now I'm wondering if it's possible to properly and manually build a QuerySet with data got from external sources, or tell django-admin, model forms and related objects to take care of another class than queryset on this Model.
Thanks
The way is to define custom methods:
Define custom methods on a model to add custom "row-level"
functionality to your objects. Whereas Manager methods are intended to
do "table-wide" things, model methods should act on a particular model
instance.
This is a valuable technique for keeping business logic in one place
-- the model.
I have now a partial solution. I override the Manager and in particular its all() and get() functions (because I only need those functions for now). all() returns a queryset in which I added the result of some logics that give me objects build from external datas (taken through xmlrpc in my case). I added those objects to the qs through _result_cache attribute.
I think it's not clean and in fact my Model is now a custom Model and I don't have any database field. I may use it to fill database Models... However I can use it the same way as classic models: MyModel.objects.all() for example.
If anyone has another idea I'd really appreciate.
Regards

How can I access the parent_link setting on a Django Data Model Field?

I've got a hierarchical model structure and have defined by own field types using OneToOneFields as described here.
I'm now writing a view customiser which takes any Model within this hierarchy and creates a form on-the-fly with checkboxes for each field to toggle visibility. Now I would like to remove the fields that link the models together (i.e. all those described using parent_link=True) but the property seems to have vanished from the fields in question, much to my displeasure. (I'm doing this because no-one would wish to view a Parent Relationship in the views I have composed).
My question is therefore, does anyone know how to locate that property at runtime?

Categories

Resources