How can we setup a field in a model to accept more than on value?
We simply can make relation fields using foreign key or many to many but in case of simple int or float or any simple variable type , how can we achieve multi value field?
If it is only about the database field, you could simply serialize your values into a string, e.g. values 1, 2, 3 become "1,2,3" in the field. Simply overwrite the getter and setter for that field (using #property), to serialize and unserialize the values each time the field is accessed.
Another approach is to use a JSONField (doc). This has wider support (for example searchability via querysets, at least using PostGreSQL. Also several 3rd party JSON form fields. You'd need to validate that the JSON supplied was a list of integers).
Related
I have several times come across a want to have a Django model field that comprises multiple database columns, and am wondering what the most Django way to do it would be.
Three use cases come specifically to mind.
I want to provide a field that wraps another field, keeping record of whether the wrapped field has been set or not. A use case for this particular field would be for dynamic configuration. A new configuration value is introduced, and a view marks itself as dependent upon a configuration value, redirecting if the value isn't set. Storing whether it's been set yet or not allows for easy indefinite caching of the state. This also lets the configuration value itself be not-nullable, and the application can ignore any value it might have when unset.
I want to provide a money field that combines a decimal (or integer) value, and a currency.
I want to provide a file field with a link to some manner of access rule to determine whether the request should include it/a request for it should succeed.
For each of the use cases, there exists a workaround, that in each case seems less elegant.
Define the configuration fields as nullable. This is undesirable for a few reasons: it removes the validity of NULL as a value for the configuration itself, so tristates and other use valid cases for NULL have to become a pair of fields or a different data type, or an edge case; null=True on the fields allows them to be set back to None in modelforms and the admin without writing a custom FormField for them every time; and every nullable column in a database is arguably bad design.
Define the field as a subclass of DecimalField with an argument accepting a string, and use that to contribute another field to the model. (This is what django-money does). Again, this is undesirable: fields are appearing "as if by magic" on the model; and configuring the currency field becomes not obvious.
Define the combined file+rule field instead as an entire model, and one-to-one to it from the model where you want to have the field. This is a solution to all use cases, but again comes with downsides: there's an extra JOIN required for every instance of the field - one can imagine a User with profile_picture, cv, passport, private_key etc.; there's an implicit requirement to .select_related(*fields) on every query that would ever want to access the fields; and the layout of the related model is going to have cold data interleaved with hot data all over the place given that it's reused everywhere.
In addition to solution 3., there's also the option to define a mixin factory that produces the multiple fields with matching names and whatever desired properties and methods. Again this isn't perfect because the user ends up with fields being defined in the model body, but also above that in the inheritance list.
I think the main reason this keeps sending me in circles is because custom Django model fields are always defined in terms of a single base field, because it's done by inheritance.
What is the accepted way to achieve this end?
How can I make a field that can accept more than one input and connect it to my database?
For example : I want to make a field that is called 'user_skills' and the user can enter more than skil in that field .. How can I do that?
Depends on the Database you are using. If you are using postgresSql you can do this with ArrayField link
Other possible options can be use JsonField or try to use normalize Model where you can store pre-define value's of corresponding field and can access them with ManyToManyField.
I have to extract value of id field from each model instance in queryset. What is more efficient - iterating through queryset with use of list comprehension or values list method with flat argument setted to true and then converted to list?
values_list will be more performant as it will only fetch the requested fields from the database and it will not instantiate model instances.
Quoting the Django documentation:
It is useful when you know you’re only going to need values from a small number of the available fields and you won’t need the functionality of a model instance object. It’s more efficient to select only the fields you need to use.
Preface
I need to have objects (Object model) with an individual set of fields (Field model). It contains name and type (see the diagram). Each connection between Object and Field stores the field's value. Datatype of value depends on the Field type property and physically the value will be stored in one of the predefined db columns (value_number, value_text, ...).
How I want it to work:
field = Field.objects.get(pk=1)
sought_for = Object.fields.filter(field=field, value='test')
Is there a way to create such a field that can be put to QuerySet just as simple as in the example but it actually, depending on the field's type, uses different db column or even columns as I suppose that in the future there will types that involve more than one column to store its value.
P.S. I tried some EAV applications but they seemed to be too complicated for my case.
The diagram:
Field model, it stores name and type of fields
FieldValue, the model the values for the fields are stored.
UPD: Eventually I came to a thought that the very approach to use Postgres (or any relational database) is not the best choice. I got this implemented easily in MongoDB.
I have a model called "Story" that has two integer fields called "views" and "votes". When I retrieve all the Story objects I would like to annotate the returned QuerySet with a "ranking" field that is simply "views"/"votes". Then I would like to sort the QuerySet by "ranking". Something along the lines of...
Story.objects.annotate( ranking=CalcRanking('views','votes') ).sort_by(ranking)
How can I do this in Django? Or should it be done after the QuerySet is retrieved in Python (like creating a list that contains the ranking for each object in the QuerySet)?
Thanks!
PS: In my actual program, the ranking calculation isn't as simple as above and depends on other filters to the initial QuerySet, so I can't store it as another field in the Story model.
In Django, the things you can pass to annotate (and aggregate) must be subclasses of django.db.models.aggregates.Aggregate. You can't just pass arbitrary Python objects to it, since the aggregation/annotation actually happens inside the database (that's the whole point of aggregate and annotate). Note that writing custom aggregations is not supported in Django (there is no documentation for it). All information available on it is this minimal source code: https://code.djangoproject.com/browser/django/trunk/django/db/models/aggregates.py
This means you either have to store the calculations in the database somehow, figure out how the aggregation API works or use raw sql (raw method on the Manager) to do what you do.