I have use case where I need to get all objects where existing_field is the beginning of some string.
some string changes dynamically so I need a smart way to filter out objects.
My idea is to create annotated query like this:
MyModel.objects.annotate(annotated_field='some string').filter(annotated_field__startswith=F('existing_field'))
Currently it is failing with:
QuerySet.annotate() received non-expression(s): some string
Is there a way to annotate objects with string value?
Not sure what you're asking but try Value expression.
MyModel.objects.annotate(annotated_field=Value('some string', output_field=CharField())).filter(annotated_field__startswith=F('existing_field'))
For those who are still facing the problem with newer versions of Django will have to use ExpressionWrapper and probably F
from django.db.models import ExpressionWrapper, F
MyModel.objects.annotate(annotated_field=ExpressionWrapper(Value('some string', output_field=CharField()))).filter(annotated_field__startswith=F('existing_field'))
Related
I want to modify some_date_field value just for filtering purpose.
Like using models.Lookup or models.Transform but I dont want to make a raw sql expression.
For instance, using a raw ms sql expression I could write:
WHERE CONVERT(date, FORMAT(some_date_field, '2021MMdd')) >= #some_var
But I how I can do that with Django?
class SomeModel(models.Model):
some_date_field = models.DateField()
def replace_year(value):
return value.replace(year=2021)
SomeModel.objects.filter(
# replace_year(some_date_field)__gte=some_var
)
Is it possible?
You can use SomeModel.objects.filter({whatever you want to filter}).update(some_date_field={date_value})
if you have any issues see:
https://docs.djangoproject.com/en/3.2/ref/models/querysets/#django.db.models.query.QuerySet.update
If you are trying to bulk update all of the objects returned by a queryset and you are using Django 2.2 or greater you can use 'bulk_update'.
See here: Django Bulk Update
If you are dynamically updating values based off of another field check out F expressions they can be used with an 'update' on querysets.
See here: Update dynamically with F expressions
Something to note though, this won't use ModelClass.save method (so if you have some logic inside it won't be triggered).
Take a look at these answers here as well
you can use filter() and update() methods in django
Assuming we need to filter some known year which is the old_date variable and the new value contains in the new_date variable
# defing mehod to filter and update new date
def update_date(old_date, new_date):
SomeModel.objects.filter(some_date_field=old_date).update(some_date_field=new_date)
return None
you can find some examples using this link.
Hope this will be helpful for you.
I'm retrieving data from postgres DB with following code:
values = ('foo', 'bar', 'group')
FooBar.objects.order_by('-id').extra(select={'group': "'stackoverflow'"}).values(*values)
The code works fine but I've heard that using extra is not preferable and even django documentations says to “Use this method as a last resort.” So the question is how it's possible to avoid using extra to retrieve data?
You can try with Value() expressions. Basically when you need to represent the value of an integer, boolean, or string within an expression, you can wrap that value within a Value().
from django.db.models import Value, CharField
FooBar.objects.annotate(group=Value('stackoverflow', output_field=CharField())).values('foo', 'bar', 'group').order_by('-id')
I'm trying to achive an Aggregation Query and that's my code:
TicketGroup.objects.filter(event=event).aggregate(
total_group=Sum(F('total_sold')*F('final_price')))
I have 'total_sold' and 'final_price' in TicketGroup object and all what I want to do is sum and multiply values to get the total sold of all TicketGroups together.
All I get is this error:
Expression contains mixed types. You must set output_field
What I am doing wrong, since I'm calling 'total_group' as my output field?
Thanks!
By output_field Django means to provide field type for the result of the Sum.
from django.db.models import FloatField, F
total_group=Sum(F('total_sold')*F('final_price'), output_field=FloatField())
should do the trick.
I had to use something different in order to make my query work. Just output_field wont solve it. I needed a simple division between two aliases. These are output of two annotations.
from django.db.models import FloatField, ExpressionWrapper, F
distinct_people_with_more_than_zero_bill = Task.objects.filter(
billable_efforts__gt=0).values('report__title').annotate(
Count('assignee', distinct=True)).annotate(
Sum('billable_efforts'))
annotate(yy=ExpressionWrapper(F('billable_efforts__sum') / F('assignee__count'), output_field=FloatField()))
The key here is ExpressionWrapper.
Without this, you will get an error: received non-expression(s)
The hint came for Django documentation itself, which says:
If the fields that you’re combining are of different types you’ll need
to tell Django what kind of field will be returned. Since F() does not
directly support output_field you will need to wrap the expression
with ExpressionWrapper
Link: https://docs.djangoproject.com/en/2.2/ref/models/expressions/
How is it possible to run the following:
someQuerySet.filter(keyword='someKey')
someQuerySet.filter(keyword='someOtherKey')
I get InvalidQueryError: Duplicate query conditions whenever I try to do that. I know it's possible to filter by a list of values, but right now, I need to do individual filters.
Later edit:
I'm actually using:
someQuerySet.filter(keyword__ne='someKey')
someQuerySet.filter(keyword__ne='someOtherKey')
You could build up Q objects like this:
from django.db.models import Q
filters = Q(keyword='someKey')
…
filters = filters | Q(keyword='someOtherKey')
someQuerySet.filter(filters)
This will basically create a WHERE clause like this: WHERE keyword = 'someKey' OR keyword = 'someOtherKey'
I am doing this from memory, so let me know if this doesn't work, and I will look into some of my past code.
The reason for the error is because by default the queries parameters AND. So you are asking for keyword="SomeKey" AND keyword="SomeOtherKey" which can never be true.
You could use Q objects to or like: http://docs.mongoengine.org/en/latest/guide/querying.html#advanced-queries or do a $in where the value matches any in a list eg: keyword__in=["SomeKey", "SomeOtherKey"]
I've got an app where users create pages. I want to run a simple DB query that returns how many users have created more than 2 pages.
This is essentially what I want to do, but of course it's not the right method:
User.objects.select_related('page__gte=2').count()
What am I missing?
You should use aggregates.
from django.db.models import Count
User.objects.annotate(page_count=Count('page')).filter(page_count__gte=2).count()
In my case, I didn't use last .count() like the other answer and it also works nice.
from django.db.models import Count
User.objects.annotate( our_param=Count("all_comments")).filter(our_param__gt=12)
use aggregate() function with django.db.models methods!
this is so useful and not really crushing with other annotation aggregated columns.
*use aggregate() at the last step of calculation, it turns your queryset to dict.
below is my code snippet using them.
cnt = q.values("person__year_of_birth").filter(person__year_of_birth__lte=year_interval_10)\
.filter(person__year_of_birth__gt=year_interval_10-10)\
.annotate(group_cnt=Count("visit_occurrence_id")).aggregate(Sum("group_cnt"))