Django Call Python Function From Query - django

When I querying a Model in Django, I want to create a custom field (using "extra" function) which may use as a sorting field. For example,
result = foo_model.objects.filter(active=True).extra(select={'cal_field': pythonFunction()}).extra(order_by=['cal_field'])
I have 2 questions:
Can I create a field which calling a Python function inside "extra"?
If it can, how can I pass the current row into the function?
Thanks a lot!

Related

Best practice for using Django templates and connect it to database

I am trying to build a database for my website. There are currently three entries with different attributes in my database. I have not created these entries in order, but I have assigned a 'Chapter number' attribute which indicates the order 1,2,3.
I am now trying to inject this using 'context' and 'render' function in my views. I am using the method 'objects.all()' to add all objects to my context. I have a simple Html file where I am inserting the data from the database by looping over (a simple for loop) these added objects.
Now the output that is being generated (naturally) is that it is following the order in which I created the database. I am not sure how I can have the loop run in such a way that I get these chapters in correct order. Thank you for patiently reading my question. Any help will be appreciated.
You may use the order_by method which is included in Djangos QuerySet API:
https://docs.djangoproject.com/en/3.0/ref/models/querysets/
If you offer some more information of your specific data I might provide you with an example.
For orientation purposes, sorting queried objects by date would work as follows:
most_recent = Entry.objects.order_by('-timestamp')
You can sort by any field like so:
sorted_by_field = Entry.objects.order_by('custom_field')

How do I batch update a field with a function in Django

How do I batch update a field with a function in Django and The function argument is the field value . such as
Data.objects.filter(need_add=1).update(need_add=Myfunc(F('need_add')))
You can't. .update does its work at the SQL query level, i.e. inside the Database engine. Unless you can encode your function in SQL, you have to fetch the objects, update them, and save them. There is .bulk_update (link) as an optimization compared to a simple iteration over a queryset saving objects one-by-one.
Database functions here

Values list vs Iterating

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.

Django model field storing a function or class

Is it possible to create a Django Custom Model Field that references a function or class, instead of a model?
In case you're wondering why i would want this, here's a brief explanation of waht i'm trying to achieve.
Basically i have a FreightTable model, that is used to calculate the value of a freight, so it should have method to do this. But the problem is that there are several different ways to calculate it, and each instance of the FreightTable should calculate on its specific way.
At first i thought about solving this using some kind of polymorphism, but then i would have to create an specific model for each different algorithm, and they would also be in different tables in the DB, what would be a problem for me. I also thought about using Django Polymorphic, but i heard it doesnt really scale well, so it's also not a good idea.
My thought is that if I could just reference this different algorithms on a Model Field, I'll have an ellegant and eficient solution.
My thought is that if I could just reference this different algorithms
on a Model Field
This is a good idea, for example:
CALCULATION_TYPES = [(1, 'Normal'), (2, 'Express')]
class FreightTable(models.Model):
# Normal fields
calculation_type = models.IntegerField(choices=CALCULATION_TYPES)
def calc_normal(self):
pass
def calc_express(self):
pass
def calc_default(self):
pass
Now, for each freight type, you set your calculation method:
ft = FreightType(calculation_type=2)
ft.save()
At the point where you want to display the result of the calculation, fetch the method from the instance, and then call the appropriate method:
call_map = {1: 'calc_normal', 2: 'calc_express'}
ft = FreightTable.objects.get(pk=1)
calculated_value = getattr(ft, call_map(ft.calculation_type))()
Python classes, functions and methods cannot be pickled, so you cannot store the code itself in the database.
What you can do is
1) Store the full dotted path to the function in a CharField. Then resolve the reference to function using zope.dottedname package, and call it.
or
2) Store the calculation code as Python source code in the database as plain text. Then execute it through eval() or dynamic module import using imp module
I am not sure if Django had internal dotted name resolver, you could use it instead of zope.dottedname.

Django - How to annotate QuerySet using multiple field values?

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.