Django annotate with complex value - django

Is it possible to annotate with complex value?
Like if I have table
class Test(models.model):
value = models.PositiveIntegerField(_('value'))
next = 5
import math
Test.objects.annotate(new_field=math.sqrt(next-value)/math.atan(value))

No, you can't pass math functions into annotate().
If you want to do this calculation in Test model then create a method:
class Test(models.model):
value = models.PositiveIntegerField(_('value'))
def calc_value(self, next):
return math.sqrt(next-self.value)/math.atan(self.value))
for t in Test.objects.all():
print t.value. t.calc_value(5)
But if you want to use this calculation to order the queryset then you have to do the math at SQL level:
next = 5
Test.objects.extra(select={'new_field': 'SQRT(%d-value)/ATAN(value)' % next}) \
.order_by('new_field'))
To filter the queryset by new field use where argument of the same extra() method:
Test.objects.extra(select={'new_field': 'SQRT(%d-value)/ATAN(value)' % next},
where=['new_field > 10'])
SQLite doesn't support math functions by default but with Postgres and MySQL this code should work just fine.

No, annotations can only be done on django aggregations.
Annotates each object in the QuerySet with the provided list of aggregate values (averages, sums, etc) that have been computed over the objects that are related to the objects in the QuerySet.

Related

django DateField model -- unable to find the date differences

I'm unable to find the difference between two dates in my form.
models.py:
class Testing(models.Model):
Planned_Start_Date = models.DateField()
Planned_End_Date = models.DateField()
Planned_Duration = models.IntegerField(default=Planned_Start_Date - Planned_End_Date)
difference between the date has to calculated and it should stored in the database but It doesn't works
default is a callable function that is just used on the class level, so you can't use it to do what you want. You should override the model's save() method (or better, implement a pre_save signal handler to populate the field just before the object is saved:
def save(self, **kwargs):
self.Planned_Duration = self.Planned_End_Date - self.Planned_Start_Date
super().save(**kwargs)
But why do you save a computed property to the database? This column is unnecessary. Both for querying (you can easily use computed queries on the start and end date) as for retrieving, you're wasting db space.
# if you need the duration just define a property
#property
def planned_duration(self):
return self.Planned_End_Date - self.Planned_Start_Date
# if you need to query tasks which last more than 2 days
Testing.objects.filter(Planned_End_Date__gt=F('Planned_Start_Date') + datetime.timedelta(days=2))
Note: Python conventions would recommend you name your fields using snake_case (planned_duration, planned_end_date, planned_start_date). Use CamelCase for classes (TestingTask). Don't mix the two.

Filter models by checking one datetime's month against another

Using Django's ORM, I am trying to find instances of myModel based on two of its datetime variables; specifically, where the months of these two datetimes are not equal. I understand to filter by the value of a modelfield, you can use Django's F( ) expressions, so I thought I'd try something like this:
myModel.objects.filter(fixed_date__month=F('closed_date__month'))
I know this wouldn't find instances where they aren't equal, but I thought it'd be a good first step since I've never used the F expressions before. However, it doesn't work as I thought it should. I expected it to give me a queryset of objects where the value of the fixed_date month was equal to the value of the closed_date month, but instead I get an error:
FieldError: Join on field 'closed_date' not permitted. Did you misspell 'month' for the lookup type?
I'm not sure if what I'm trying to do isn't possible or straightforward with the ORM, or if I'm just making a simple mistake.
It doesn't look like django F objects currently support extracting the month inside a DateTimeField, the error message seems to be stating that the F object is trying to convert the '__' inside the string 'closed_date__month' as a Foreignkey between different objects, which are usually stored as joins inside an sql database.
You could carry out the same query by iterating across the objects:
result = []
for obj in myModel.objects.all():
if obj.fixed_date.month != obj.closed_date.month:
result.append(obj)
or as a list comprehension:
result = [obj for obj in myModel.objects.all() if obj.fixed_date.month != obj.closed_date.month]
Alternatively, if this is not efficient enough, the months for the two dates could be cached as IntegerFields within the model, something like:
class myModel(models.Model):
....other fields....
fixed_date = models.DateTimeField()
closed_date = models.DateTimeField()
fixed_month = models.IntegerField()
closed_month = models.IntegerField()
store the two integers when the relevant dates are updated:
myModel.fixed_month = myModel.fixed_date.month
myModel.save()
Then use an F object to compare the two integer fields:
myModel.objects.filter(fixed_month__ne=F('closed_month'))
The ne modifier will do the not equal test.
Edit - using raw sql
If you are using an sql based database, then most efficient method is to use the .raw() method to manually specify the sql:
myModel.objects.raw('SELECT * FROM stuff_mymodel WHERE MONTH(fixed_date) != MONTH(close_date)')
Where 'stuff_mymodel' is the correct name of the table in the database. This uses the SQL MONTH() function to extract the values from the month fields, and compare their values. It will return a collection of objects.
There is some nay-saying about the django query system, for example: http://charlesleifer.com/blog/shortcomings-in-the-django-orm-and-a-look-at-peewee-a-lightweight-alternative/. This example could be taken as demonstrating another inconsistency in it's query api.
My thinking is this:
class myModel(models.Model):
fixed_date = models.DateTimeField()
closed_date = models.DateTimeField()
def has_diff_months(self):
if self.fixed_date.month != self.closed_date.month:
return True
return False
Then:
[x for x in myModel.objects.all() if x.has_diff_months()]
However, for a truly efficient solution you'd have to use another column. It makes sense to me that it'd be a computed boolean field that is created when you save, like so:
class myModel(models.Model):
fixed_date = models.DateTimeField()
closed_date = models.DateTimeField()
diff_months = models.BooleanField()
#overriding save method
def save(self, *args, **kwargs):
#calculating the value for diff_months
self.diff_months = (self.fixed_date.month != self.closed_date.month)
#aaand... saving:
super(Blog, self).save(*args, **kwargs)
Then filtering would simply be:
myModel.objects.filter(diff_months=True)

ORDERBY query on 2 django models collectively

I have 2 models namely A and B. Both have a common field, say timestamp.
X = A.objects.all()
Y = A.objects.all()
results = chain(X,Y) # Union
Now I want to apply ORDERBY query on results. How can I do that?
While the python way of doing it is by using some kind of sorting, this is normally not the correct way of doing it in Django.
The reason is that in order to join two queries of two different models, you have to transform them to lists (as other answers suggest).
While this seems good, most of the time it is not, because you hit the database, i.e. the database is asked for all elements of both models for creating both lists, and them joining.
The most likely reason why you are joining two models in a single list is because both should be derived from a common model, e.g. an Abstract model. Doing this both models have a natural common field obtained by being subclasses of the abstract model.
The ordering of such a query can then be made using order_by. This is more efficient because queries are lazy.
EDIT:
Example:
class Parent(models.Model):
date_field = models.DateField()
def pretty_show():
# returns general behavior
class B(Parent):
# other specific fields
def pretty_show():
# returns specific behavior
class C(Parent):
# other specific fields
def pretty_show():
# returns specific behavior
X = Parent.objects.all().order_by("date_field")
for x in X:
x.pretty_show()
Notice that Parent class in this case is not Abstract and childs are not proxies, but this choice strongly depends on what you want to achieve. Hope this helps.
You mean:
X = A.objects.all()
Y = B.objects.all()
results = chain(X,Y) # Union
You can cast result to list(). List has order function:
ut.sort(key=lambda x: x.count, reverse=True)
more
You could try to create a list of the model objects and then sort by their time stamp like this (both models must have the same time_stamp attribute):
l= list(x)+list(y)
l.sort(key=lambda l: l.time_stamp)
Hope this is what you are looking for.

Django Queryset creating a .values() based on the sorting of another field

I'm trying to the most likely predicted category for a datapoint. Since code is the best explanation:
models:
class DataPoint(models.Model):
#... unimportant fields
class PredResult(models.Model):
likelihood = models.FloatField()
value = models.IntegerField()
data_point = models.ForeignKey(DataPoint)
For each DataPoint object I am trying to find the value for the PredResult with the highest likelihood. Currently I'm using a for-loop:
data_points = DataPoints.objects.select_related('predresult')
for dp in data_points:
if dp.predresult_set.all().exists():
val = dp.predresult_set.order_by('-likelihood')[0].value
#do other stuff here with val and dp
I'd like to get add a best_value field to the DataPoint queryset. Currently there are ~5 PredResult objects per DataPoint and ~20,000 DataPoints (although this may balloon rapidly). However, this for-loop takes too long to complete within a view.
Can anyone suggest a way to deal with this? Either a Django ORM trick, a extra() method on the Queryset. Or do you think I should use a post-save method on the PredResult object and update a field on the DataPoint object directly?
If its needed I'm using MySQL as the database backend.
Aggregation:
from django.db.models import Max
values = DataPoint.objects.annotate(max_result=Max('predresult__value'))
Now each element in values has a max_result attribute containing the max related result.

Django, query filtering from model method

I have these models:
def Foo(Models.model):
size = models.IntegerField()
# other fields
def is_active(self):
if check_condition:
return True
else:
return False
def Bar(Models.model):
foo = models.ForeignKey("Foo")
# other fields
Now I want to query Bars that are having active Foo's as such:
Bar.objects.filter(foo.is_active())
I am getting error such as
SyntaxError at /
('non-keyword arg after keyword arg'
How can I achieve this?
You cannot query against model methods or properties. Either use the criteria within it in the query, or filter in Python using a list comprehension or genex.
You could also use a custom manager. Then you could run something like this:
Bar.objects.foo_active()
And all you have to do is:
class BarManager(models.Manager):
def foo_active(self):
# use your method to filter results
return you_custom_queryset
Check out the docs.
I had similar problem: I am using class-based view object_list and I had to filter by model's method. (storing the information in database wasn't an option because the property was based on time and I would have to create a cronjob and/or... no way)
My answer is ineffective and I don't know how it's gonna scale on larger data; but, it works:
q = Model.objects.filter(...)...
# here is the trick
q_ids = [o.id for o in q if o.method()]
q = q.filter(id__in=q_ids)
You can't filter on methods, however if the is_active method on Foo checks an attribute on Foo, you can use the double-underscore syntax like Bar.objects.filter(foo__is_active_attribute=True)