I want to Filter across multiple tables in Django.
q = json.loads(request.body)
qs = Search.objects.filter(keyword__icontains=q['q']).all()
data = serialize("json", qs, fields=('keyword', 'user'))
That's one,
secondly, the user field is returning an integer value (pk) instead of maybe the username.
You can try getting 'user__username' instead of 'user'. It might work.
Related
I have two Django models Profile and Device with a ManyToMany relationship with one another like so:
class Profile(models.Model):
devices = models.ManyToManyField(Device, related_name='profiles')
I am trying to use annotate() and Count() to query on all profiles that have 1 or more devices like this:
profiles = Profile.objects.annotate(dev_count=Count('devices')).filter(dev_count__gt=1)
This is great, it gives me a QuerySet with all the profiles (4500+) with one or more devices, as expected.
Next, because of the M2M relationship, I would like to get a list of all the distinct devices among all the profiles from the previous queryset.
All of my failed attempts below return an empty queryset. I have read the documentation on values, values_list, and annotate but I still can't figure out how to make the correct query here.
devices = profiles.values('devices').distinct()
devices = profiles.values_list('devices', flat=True).distinct()
I have also tried to do it in one go:
devices = (
Profile.objects.values_list('devices', flat=True)
.annotate(dev_count=Count('devices'))
.filter(dev_count__gt=1)
.distinct()
)
You can not work with .values() since that that item appears both in the SELECT clause and the GROUP BY clause, so then you start mentioning the field, and hence the COUNT(devices) will return 1 for each group.
You can filter on the Devices that are linked to at least one of these Profiles with:
profiles = Profile.objects.annotate(
dev_count=Count('devices')
).filter(dev_count__gt=1)
devices = Device.objects.filter(profile__in=profiles).distinct()
For some SQL dialects, usually MySQL it is better to first materialize the list of profiles and not work with a subquery, so:
profiles = Profile.objects.annotate(
dev_count=Count('devices')
).filter(dev_count__gt=1)
profiles_list = list(profiles)
devices = Device.objects.filter(profile__in=profiles_list).distinct()
Given these models
class User(Model):
pass
class Post(Model):
by = ForeignKey(User)
posted_on = models.DateTimeField(auto_now=True)
I want to get the latest Posts, but not all from the same User, I have something like this:
posts = Post.objects.filter(public=True) \
.order_by('posted_on') \
.distinct("by")
But distinct doesn't work on mysql, I'm wondering if there is another way to do it?
I have seen some using values(), but values doesn't work for me because I need to do more things with the objects themselves
Since distinct will not work with MySQL on other fields then model id, this is possible way-around with using Subquery:
from django.db.models import Subquery, OuterRef
...
sub_qs = Post.objects.filter(user_id=OuterRef('id')).order_by('posted_on')
# here you get users with annotated last post
qs = User.objects.annotate(last_post=Subquery(sub_qs[:1]))
# next you can limit the number of users
Also note that ordering on posted_on field depends on your model constraints - perhaps you'll need to change it to -posted_on to order from newest on top.
order_by should match the distinct(). In you case, you should be doing this:
posts = Post.objects.filter(public=True) \
.order_by('by') \
.distinct('by')
.distinct([*fields]) only works in PostgresSQL.
For MySql Engine. This is MySQL documentation in Django:
Here's the difference. For a normal distinct() call, the database
compares each field in each row when determining which rows are
distinct. For a distinct() call with specified field names, the
database will only compare the specified field names.
For MySql workaround could be this:
from django.db.models import Subquery, OuterRef
user_post = Post.objects.filter(user_id=OuterRef('id')).order_by('posted_on')
post_ids = User.objects.filter(related_posts__isnull=False).annotate(post=Subquery(user_post.values_list('id', flat=True)[:1]))).values_list('post', flat=True)
posts = Post.objects.filter(id__in=post_ids)
I have a table called user_info. I want to get names of all the users. So the table has a field called name. So in sql I do something like
SELECT distinct(name) from user_info
But I am not able to figure out how to do the same in django. Usually if I already have certain value known, then I can do something like below.
user_info.objects.filter(name='Alex')
And then get the information for that particular user.
But in this case for the given table, I want to get all the name values using django ORM just like I do in sql.
Here is my django model
class user_info(models.Model):
name = models.CharField(max_length=255)
priority = models.CharField(max_length=1)
org = models.CharField(max_length=20)
How can I do this in django?
You can use values_list.
user_info.objects.values_list('name', flat=True).distinct()
Note, in Python classes are usually defined in InitialCaps: your model should be UserInfo.
You can use values_list() as given in Daniel's answer, which will provide you your data in a list containing the values in the field. Or you can also use, values() like this:
user_info.object.values('name')
which will return you a queryset containing a dictionary. values_list() and values() are used to select the columns in a table.
Adding on to the accepted answer, if the field is a foreign key the id values(numerical) are returned in the queryset. Hence if you are expecting other kinds of values defined in the model of which the foreign key is part then you have to modify the query like this:
`Post.objects.values_list('author__username')`
Post is a model class having author as a foreign key field which in turn has its username field:
Here, "author" field was appended with double undersocre followed by the field "name", otherwise primary key of the model will be returned in queryset. I assume this was #Carlo's doubt in accepted answer.
I have a model with a field that is a list.
For example:
mymodel.sessions = [session1, session2]
I need a query to get all mymodels that session1 is exist their sessions.
The model`s field looks like that
sessions = models.ForeignKey("Session", related_name="abstracts",
null=True, blank=True)
Thank you !
You can use reverse lookups that go back along the foreign key to query for values in the related model.
MyModel.objects.filter(sessions__id=1)
That will filter all MyModels that have a foreign key to a session with an id of 1.
For more information see https://docs.djangoproject.com/en/1.10/topics/db/queries/#lookups-that-span-relationships
From the Django docs for filter:
filter(**kwargs)
Returns a new QuerySet containing objects that match the given lookup parameters.
You can filter on a ForeignKey relationship using the id, if you have it:
The field specified in a lookup has to be the name of a model field. There’s one exception though, in case of a ForeignKey you can specify the field name suffixed with _id. In this case, the value parameter is expected to contain the raw value of the foreign model’s primary key.
In your instance, this would like the following:
mymodel.objects.filter(sessions_id=4)
If you want to filter on any other field in the Sessions model, simply use a double underscore with the field. Some examples:
mymodel.objects.filter(sessions__name='session1')
mymodel.objects.filter(sessions__name__contains='1')
I'd like to have several fields in my form being rendered as ChoiceFields which get their content from the database.
I was thinking something like:
class SeriesForm(ModelForm):
series = forms.ChoiceField(choices=Series.objects.all())
class Meta:
model = Series
exclude = ('model', 'date_added',)
But the field series is now not appearing at all in my form. What am I missing?
After trying the solution (using the ModelChoiceField), I'm still seeing the same issue. Here is my code:
series = forms.ModelChoiceField(queryset=Series.objects.values('series'),
empty_label=" ")
Use a ModelChoiceField instead.