django : How to write alias in queryset - django

How can one write an alias for the column name in django query set.
Would be useful for union-style combinations of two linked field to the same foreign model (for instance).
for example in mysql :
select m as n, b as a from xyz
how can i do this in django query set ?
models.Table.objects.all().values('m', 'b')
Any help really appreciate it.

You can annotate the fields as you want, with the F expression:
from django.db.models import F
models.Table.objects.all().values('m', 'b').annotate(n=F('m'), a=F('b'))

Although this could have been done before by using extra(select={'n':'m','a':'b'}), I agree that this really should have been a part of values() itself.
To that end, and inspired by Alex's ticket, I have just posted a patch that adds this feature. I hope you'll find it useful!

Your reason in the comment makes no sense. Each field in the model has its own column in the database, and there's never any danger of mixing them up. You can of course tell a field to use a column name that's different from the field name:
myfield = models.CharField(max_length=10, db_column='differentname')
but I don't know if that will help you, because I still don't know what your problem is.

I'm presuming this isn't possible, so I've raised a ticket for the feature to be added, I think there is some merit to being able to do this. Please see the ticket for more information.
https://code.djangoproject.com/ticket/16735

you can also use .alias() in your queryset.
.alias(alias=SomeExpression()).annotate(
SomeOtherExpression('alias'))
.alias(alias=SomeExpression()).order_by('alias')
.alias(alias=SomeExpression()).update(field=F('alias'))
for your specific case, this would be the answer
models.Table.objects.all().alias(
n=F('m'), a=F('b')).values('m', 'a')
)

I really can't understand what you are trying to do however it sounds like what you are looking for is the extra queryset method. This for most purposes acts in the same manner as AS does in sql.

Related

Equivalence of Django queryset filteration

I've been using the following two interchangeably in a Django project:
Comments.objects.filter(writer=self.request.user).latest('id')
and
Comments.objects.get(writer=self.request.user)
Are they equivalent in practice? The docs don't seem to explicitly address this.
They are not equivalent at all, but this greatly depends on the particular model. We do not know the particulars of your model Comments, but if we assume that field writer is not unique:
For the first statement:
Comments.objects.filter(writer=self.request.user).latest('id')
Returns in essence the object with the largest id amongst a queryset of all comments with the particular writer. If one takes a look at the django.db.connections['default'].queries, will see that the resulting query is a SELECT .. ORDER_BY .. LIMIT .. statement.
For the second statement:
Comments.objects.get(writer=self.request.user)
Returns the particular record fot that writer. In case there are more than one, you get a MultipleObjectsReturned exception. If no object is found, you get a DoesNotExist exception. In the event that this would be a unique field or there would be a single object by chance, the resulting query would be a SELECT .. WHERE statement which is faster.
Regarding the documentation, if you take a look at the Options.get_latest_by reference, there is more information regarding the purpose of the latest function. Think of it more of a convenience provided by Django. It is nonetheless very important to understand how Django evaluates queries and the resulting SQL, and there are always many ways to achieve the same query so it is a matter of logic.
I don't know why you would think these are equivalent, or why the docs should address this specifically.
In the case where you only have one matching Comment, yes this will give the same result. But the first version will do it via a more complex query, with an added sort on id.
If you have more than one Comment for that writer - as seems likely - the second version will always give a MultipleObjectsReturned error.
filter gives all lines corresponding your filter.
latest gives the most recent line (highest id value)
For example:
Comments.objects.filter(writer=self.request.user).latest('id') gets in first place all Comments written by self.request.user and then latest get the newest from them.
get is made to get a unique line, so :
Comments.objects.get(writer=self.request.user) will give the comment written by self.request.user. There should be only one. If a user can write many comments then you have to use filter or maybe all. It depends on what you want exactly.
More info here

How to use count() in Flask-sqlalchemy

I am assisting a project which uses flask-sqlalchemy.
I would like a db query to count the number of records in the table.
Can I use table.query.filter_by(condition).count() directly?
Or is there anything that I need to add?
Please assist me. I am a begineer. Thanks in advance!
None of the given answers address flask-sqlalchemy specifically, where you would use exactly the example you gave:
Table.query.filter_by(condition).count()
You can perform .count() without filters:
Table.query.count()
You can also count using M2M relationships:
ParentTable.children.count()
And you can use any of these directly in your jinja templates like:
{{ Table.query.filter_by(condition).count() }}
Bonus points (for the performance minded):
.count() is a bit slow (especially with MySQL, thanks to a poor handling of subqueries), so instead, you can use a custom count that looks like this:
db.session.execute(Table.query.filter_by(condition).statement.with_only_columns([func.count()]).order_by(None)).scalar()
That's assuming db is your SQLAlchemy instance (ie, db = SQLAlchemy(app)). It's a mouthful, but it will save you a little bit of overhead on big queries.
Per this source, the following should work for you:
session.query(Class_name).filter_by(condition).count()
Class_name is the name of the mapped class for your table.
Yes, you can do that. But remember, that count() uses one more query, like this:
Select count(q.*) from (select * from table) q
However, you can make it more efficient by using only one query. You can use this:
from sqlalchemy.sql.functions import func
number = session.query(func.count(table.id).label('number').first().number
The SQL query will be like this:
Select count(table.id) as number from table
Simple is best:
accounts = db.session.execute('select count(id) as c from user').scalar()

Django 1.6 How to change a list to queryset or How to write this kind of query?

I want to get all the questinos with no answers.I use this:
all_questions=[q for q in Question.objects.all() if not q.answer_set.all()]
It works. But then I need to invoke order_by method with all_questions, so I need to change it to a queryset, how?
Or, is there a standard method like Question.objects.filter(answer_count=0) ? I find hard but no results.
Solution: Change answer_count__gt=0 to answer_count=0.
all_questions=Question.objects.annotate(answer_count=Count('answer')).filter(answer_count=0)
You should be able to use an annotation much more efficiently than doing one query per question.
Question.objects.annotate(answer_count=Count('answer')).filter(answer_count=0)
That said, you could just add the order_by directly into your Questions.objects.all() query. But like I said, it's much less efficient to do a query per question.

Filter Django objects where related object exists

This is bound to be a duplicate question but I can't find any others. I'm trying to get a list of photos that have complaints. I can't simply get complaints and deal with the related photos - I need a queryset of photos.
This should work but doesn't seem right:
Photo.objects.filter(complaint__id__gte=0)
This doesn't seem like the most efficient way:
Photo.objects.annotate(Count('complaint')).exclude(complaint__count=0)
Is there a better way?
how about ...
Photo.objects.filter(complaint__isnull=False)
from https://docs.djangoproject.com/en/dev/topics/db/queries/
I'm not sure which variant is the best, but that works as well.
Photo.objects.exclude(complaint=None)
Generated SQL query here is not the same as in case with .filter(complaint__isnull=False), but sense is identical.
Depending on the complexity of the relationship and filter logic you might need this (or this can turn out to be more readable):
complaints = Complaint.objects.filter(
# some complex filter here
Q(...) & Q(...) | Q(...)
)
Photo.objects.annotate(
has_complaints=Exists(complaints)
).filter(has_complaints=True)

In django, can one use F() objects to see if a constant contains strings from a field?

All,
I'm trying to basically do keyword notifications, so whenever an object with a name is created, anyone who wants to be notified of any of the words in this name will be.
e.g.
Records:
keyword: Hello
keyword: World
New Name: "Hello World"
Returns both records
I've created a query that correctly works for this in sqlite, and I know how to translate it across databases.
SELECT * FROM table t
WHERE "a constant string" LIKE "%" || t.field || "%";
I've determined that within django, one can use F() objects to compare one field to another field, like so:
Entry.objects.filter(n_comments__gt=F('n_pingbacks'))
Now anyone know how to replace the first field with a constant string? Like so:
Entry.objects.filter("constant string"__icontains=F('n_pingbacks'))
Or am I going about this backwards?
It doesn't look particularly pretty but it can be done all with standard filters.
from django.db.models import ExpressionWrapper, CharField, Value
Entry.objects.annotate(
my_const=ExpressionWrapper(Value("a constant string"),
output_field=CharField())
).filter(my_const__contains=F('n_pingbacks'))
You can do this by providing a dict of arguments, e.g.:
Entry.objects.filter(**{("%s__icontains" % constant_string):F('n_pingbacks')})
Try using '.extra' to select your const as field, than using myconst__contains, like:
queryset.extra(select={'myconst': "'this superstring is myconst value'"}).filter(myconst__contains=F('myfield'))
Do not forget to put constant value in apostrophes inside double qoutation marks.
But, will somebody help me put it into Q object? =)
UPD:
Suddenly, it fails because of the following issue:
https://code.djangoproject.com/ticket/13363
Maybe, they will fix it.
UPD: You can filter by fields that added with '.annotate', but I don't know, how to put constant here instead of aggregation. Maybe, with creation of custom aggreation function, like here:
http://coder.cl/2011/09/custom-aggregates-on-django/
UPD: I made custom aggregator, this logic seems to be correct, because the query I got from queryset is quite similar to I wanted it to be, but, unfortunately, there is another issue: 16731 (sorry not providing full url, not enough rep, see another ticket above).
UPD(last): I have managed to do this using monkeypatching of the following:
django.db.models.sql.Query.query_terms
django.db.models.fields.Field.get_prep_lookup
django.db.models.fields.Field.get_db_prep_lookup
django.db.models.sql.where.WhereNode.make_atom
Just defined custom lookup 'starts', which has reverse logic of 'startswith'
You should not try to fight with django ORM. It covers the most often things but your case is not the one. Just use extra to get what you need (or even raw).