How to get missing data using Django model query? - python

In Django, there is the filter() method to filter data. So I can pass an array of data and get the filtered results like this model.objects.filter(id__in=id_array).
Is there a way to get missing data using Django model query?
How to get a list of id_array elements which don't exist in the database?

You can't ask the database for things it doesn't have. However, you can ask it for all the things it does have, and then get a set containing the difference. Something like:
ids = model.objects.filter(id__in=id_array).distinct().values_list('id', flat=True)
missing_values = set(id_array) - ids

Related

Django: Store Q query objects for repeatable search?

In my Django based web app users can perform a search; the query consists of several dynamically constructed complex Q objects.
Depending on the user search parameters, the search will query a variable number of columns and also can stretch over multiple models.
The user should be able to save her search to repeat it at some later point.
For that I'd like to store the Q objects (I guess) in a database table.
Is this good practice? How would you approach this?
Thanks in advance.
If you have just one or a fixed number of Q objects as part of the filter, you can save the argument passed to Q as a dict.
.e.g This:
Q(buy_book__entity__type=ENTITY.INTERNAL)
Is equivalent to this:
q_filter = {"buy_book__entity__type": ENTITY.INTERNAL}
Q(**q_filter)
You can save q_filter in your datastore.

Django ORM: Filter results by values from list, limit answers per value?

I'm using Django 2.0 and have a Content model with a ForeignKey(User, ...). I also have a list of user IDs for which I'd like to fetch that Content, ordered by "newest first", but only up to 25 elements per user. I know I can do this:
Content.objects.filter(user_id__in=[1, 2, 3, ...]).order_by('-id')
...to fetch all the Content objects created by each of these users, plus I'll get it all sorted with newest elements first. But I'd like to fetch up to 25 elements for each of these users (some users might create hundreds of these objects, some might create zero). There's of course the dumb way:
for user in [1, 2, 3, ...]:
Content.objects.filter(user_id=user).order_by('-id')[:25]
This however hits the database as many times as there's objects in the user ID list, and that goes quite high (around 100 or so per page view). Is there any way to optimize this case? (I've tried looking around select_related, but that seems to fetch as many related models as possible.)
There are plenty of ways to form a greatest-n-per-group query, but in this case you could form a union of top-n queries of all users:
contents = Content.objects.\
none().\
union(*[Content.objects.
filter(user_id=uid).
order_by('-id')[:25] for uid in user_ids],
all=True)
Using prefetch_related() you could then produce a queryset that fetches the users and injects an attribute of latest content:
users = User.objects.\
filter(id__in=user_ids).\
prefetch_related(models.Prefetch(
'content_set',
queryset=contents,
to_attr='latest_content'))
Does it actually hit the database that many times? I have not looked at the raw SQL but according to the documentation it is equivalent to the LIMIT clause and it also states "Generally, slicing a QuerySet returns a new QuerySet – it doesn’t evaluate the query".
https://docs.djangoproject.com/en/2.0/topics/db/queries/#limiting-querysets
I would be curious to see the raw SQL if you are looking at it and it does NOT do this as I use this paradigm.

how to query a multiple column in django

I have a problem in displaying specific columns in my model in django...
I have read in the documentation in about the queryset feature of django.
my question is that it is also possible in django to run just like this query?
select name, age, address from person;
can anyone can give me an idea, i also try it like this
Mymodel.objects.get(name, age, address)
but there are error in the parameter of name, age and address...
thanks...
If you want only some columns use only:
Mymodel.objects.only('name', 'age', 'address')
If you don't want some columns use defer:
Mymodel.objects.defer('some_big_field')
You can still access field you haven't queried, but it will cost you one mode DB hit.
Also you can use values and values_list methods, but instead of model instances they return list of dicts and list of lists respectively.
there are a few different ways. django normally wraps the data in model instances, which is part of the point of the orm. you deal with objects and django deals with the database. so
for person in MyMydel.objects.all():
do_something_with(person.name)
having said that, if you only want certain attributes, e.g. for performance, you can use values
MyMode.objects.values('name', 'age', 'address')
which returns a list of dicts with those values

Checking for group membership (Many to Many in Django)

I have two models in Django: groups and entries. Groups has a many-to-many field that connects it to entries. I want to select all entries that have a group (as not all do!) and be able to access their group.title field.
I've tried something along the lines of:
t = Entries.objects.select_related().exclude(group=None)
and while this returns all entries that have groups, I can't do t[0].groups to get the title. Any ideas on how this could be done?
Edit: more info
When ever I use Django's shell to inspect what is returned in t (in this example), t[0].group does not exist. The only way I can access this is via t[0].group_set.all()[0].title, which seems inefficient and like I'm doing something incorrectly.
You don't show the model code, so I can't be sure, but instead of t[0].groups, I think you want:
for g in t[0].groups.all():
print g.title

django - convert a list back to a queryset [duplicate]

This question already has answers here:
A QuerySet by aggregate field value
(3 answers)
Closed 8 years ago.
I have a handful of records that I would like to sort based on a computed value. Got the answer over here... like so:
sorted(Profile.objects.all(), key=lambda p: p.reputation)
on a Profile class like this:
class Profile(models.Model):
...
#property
def reputation(self):
...
Unfortunately the generic view is expecting a queryset object and throws an error if I give it a list.
Is there a way to do this that returns a queryset
or...
Can I convert a list to a queryset somehow? Couldn't find anything like that in the django docs.
I am hoping not to denormalize the data, but I guess I will if I have to.
Update / Answer:
it seems that the only way to get a queryset back is if you can get all of your logic into the sql queries.
When that is not possible, (I think) you need to denormalize the data
Ok...this post is now old BUT what you could do is get all the ids of the objects in your list, then perform a model.objects.filter(pk__in=list_of_ids)
There is no point in converting a data list back to a query. A query object never holds data; it just represents a query to the database. It would have to fetch everything again if you made your list to a query, and that would be redundant and very bad performance-wise.
What you can do:
Describe how the reputation field is calculated; it's probably possible to order the data in the database somehow.
Modify the view to not require a query object. If it needs to do additional filtering etc. this should be done before any ordering, since the ordering will take less time with less entries (and less data will be fetched from the database.) So you could send the filtered query object to the sort function just before you send it to the template (which shouldn't care whether it's a query or a list.)

Categories