Django OrderBy using ManyToMany table - django

I have the models:
class Category(models.Model):
description = models.CharField(unique=True, max_length=200)
class Car(models.Model):
categorys = models.ManyToManyField(Category)
Constantly new cars are added.
I'd like to get the last 20 categories that had a car of her type added.
I got to set up a filter, but when I got to order by I could not get it anymore.
Since I can not close any logic I will not put what I have tried here.
Updating
I add 3 cars:
Car 1 have 2 categories (cat1 and cat2)
Car 2 have 3 categories (cat2, cat20, cat3)
Car 3 have 2 categories (cat4, cat1, cat90)
I need to get:
cat1, cat2, cat3, cat4, cat20, cat90 and others...

So you have this models:
class Category(models.Model):
description = models.CharField(unique=True, max_length=200)
class Car(models.Model):
categorys = models.ManyToManyField(Category)
According to this phrase:
I'd like to get the last 20 categories that had a car of her type
added.
at first we have to find the car:
car = Car.objects.get("""your parameters""")
Then we have to find categories:
category = car.category_set.all()[:20]
Try this
UPD
When you get all Cars and Category that you need, you can get to any of category object.
categories = Cars.objects.filter("""your filter""").select_related('categorys')
for category in categories.categorys_set():
print(category.description)

I use extra() function to solve the problem.
See code blow:
class School(models.Model):
...
tag = models.ManyToManyField(Tag)
def tags(self):
meta = self.tag.through._meta
db_table = meta.db_table
primary_key = meta.pk.name
order_by = [db_table + '.' + primary_key]
return list(self.tag.extra(order_by=order_by).values_list('name', flat=True))
By adding order by to sql statement to make results order by pk of through (if not specified django will create a table for you automaticly) table.
Hope this will be helpful.

Related

Queryset Django - according to parameters date in weight compartment

I'm trying to get a result where my data from the database is sorted first by weight and then by date.
My models.py look like this:
class Example(models.Model):
date_created = models.DateTimeField(auto_now_add=True)
weight = models.PositiveIntegerField(default=1, validators=[MinValueValidator(1), MaxValueValidator(3)])
If I add in my object:
class Meta:
ordering = ['-date_created ']
and in the queryset will filter out after the weight I get the result as in the picture below?
How to get such a result using only query, or only using the class in the models.py file? The picture shows what I would like to get.
Just add another list element:
class Meta:
ordering = ['-weight', 'date_created']
So first it will order by weight descending and then by date_created ascending.
More you can find in Django docs.

Subquery many-to-many relation in Django 1.9

I have such models:
class Genre(models.Model):
name = models.TextField(null=True, blank=True)
min_age = models.IntegerField(default=0)
max_age = models.IntegerField(default=0)
objects = GenreManager()
class Meta:
get_latest_by = 'id'
class Book(models.Model):
name = models.TextField(null=True, blank=True)
genres = models.ManyToManyField(Genre, related_name='genres')
suggested_age = models.IntegerField(default=0)
objects = BookManager()
and I want to query it in such way: there can be duplicates (when min/max age changes, new object will be saved to db), but I want to get the latest one, so I come up with:
class GenreManager(models.Manager):
def get_latest_genre_obj(self, genre):
return self.get_queryset().filter(name=genre).latest()
to be able to retrieve one. Now, I want to get books, using Genre object from above - I need min and max age values in my query. I've tried something like this:
class BookManager(models.Manager):
def get_books_from_genre(self, genre):
genre = Genre.objects.get_latest_genre_obj(genre)
return self.get_queryset().annotate(actual_genre=genre).filter(actual_genre__min_age__gte=F('suggested_age'), actual_genre__max_age__lte=F('suggested_age'))
But it looks like I cannot annotate object to other object:
AttributeError: 'Genre' object has no attribute 'resolve_expression'
So, how to query it like I want to? I thought about Subquery() as I thought it can help me, but it's Django 1.11 feature andI'm using 1.9 version. To sum up what I want to achieve: from genres, retrieve newest (with highest id) object with particular name and use it's fields while querying for books - so I need to have access to it's fields.
I think you need to remove annotate from the code, and use it like this:
If you want Books for a specific genre:
class BookManager(models.Manager):
def get_books_from_genre(self, genre):
genre_object = Genre.objects.get_latest_genre_obj(genre)
return self.get_queryset().filter(genres=genre_object)
Now if you want to have books from multiple genre with same name, then you can try like this:
class BookManager(models.Manager):
def get_books_from_genre(self, genre):
return self.get_queryset().filter(genres__name=genre, genres__min_age__gte=F('suggested_age'), genres__max_age__lte=F('suggested_age'))

django query with prefetch_related

I am struggling to get at the data I need from a prefetch-related query.
I have a table of events (the calendar table), a table of members and an attendee table which links the two.
My models look like:
class Member(models.Model):
firstname = models.CharField(max_length=40)
lastname = models.CharField(max_length=50)
email = models.EmailField(blank=True, verbose_name ='e-mail')
phone = models.CharField(max_length=40)
membershipnum = models.CharField(max_length=40)
class Attendee(models.Model):
memberid = models.ForeignKey(Member, on_delete=models.SET(0), related_name="attendingmembers")
calendarid = models.ForeignKey(Calendar, on_delete=models.SET(0))
attended = models.BooleanField(default=0)
paid = models.BooleanField(default=0)
class Meta:
db_table = 'attendee'
For a particular event I want a list of attending members with the attended and paid fields from the attendee table.
In my view I have
attendees = Member.objects.filter(attendingmembers__calendarid_id=id).prefetch_related('attendingmembers')
I am getting the right members, but I don't know if this is the best way to do it? And I can't figure out how to get at the attendee fields.
If I do
for thisone in attendees:
print(thisone)
print(thisone.attendingmembers)
I get the expected return from the first print, but the second just gives me
myapp.Attendee.None
Any advice much appreciated.
You still need .all() to get the list of items of your relation:
for this one in attendees:
print(thisone.attendingmembers.all())
Btw, do you wish to get all attendingmembers or only the ones with the right calendar_id ?
attendees = Member.objects.filter(attendingmembers__calendar_id=id).prefetch_related('attendingmembers')
# return all Members having at least one attendingmember with calendar_id=id, and prefetch all of their attendingmembers
attendees = Member.objects.filter(attendingmembers__calendar_id=id).prefetch_related(Prefetch('attendingmembers', queryset=Attendee.objects.filter(calendar_id=id)))
# return all Members having at least one attendingmember with calendar_id=id, and prefetch their attendingmembers matching the filter
The documentation shows you how to use the to_attr argument in the Prefetch objects ;)

Behaviour of django order_by

I have 3 models:
class Parent(models.Model):
name = models.CharField()
class StudentDriver(models.Model):
parent = models.ForeignKey(Parent, on_delete=models.CASCADE)
class Car(models.Model):
student_driver = models.ForeignKey(StudentDriver, on_delete=models.CASCADE)
Why is it, that if I do the following, the order_by is not honoured (my qs will not be ordered by the student_driver.parent_id)? And is there a way I can get it ordered? I need it for a groupby.
for car in Car.objects.order_by('student_driver__parent'):
print(car.student_driver.parent)
If I do:
for car in Car.objects.order_by('student_driver'):
print(car.student_driver)
it works no problem (the qs is ordered by student_driver_id). Seems to be the ForeignKey link, but I can't figure it out.
I think it works:
for car in Car.objects.all().order_by('student_driver__parent__id'):
print(car.student_driver.parent.id)

Django two parameter filter query with foreign key

My Django models look like this:
class User(models.Model):
userid = models.CharField(max_length=26,unique=True)
#some more fields that are currently not relevant
class Followers(models.Model):
user = models.ForeignKey('User',related_name='usr')
coins = models.IntegerField()
followers = models.CharField(max_length=26, null=True, blank=True)
I would now like to make a filter query in my Followers table selecting every entry where users have ID x and followers have ID y (I expect to get one result from the query).
To visualize what I have tried and know won't work is this:
queryfilter = Followers.object.filter(followers=fid, user=uid)
and this:
queryfilter = Followers.object.filter(followers=fid, user__userid=uid)
In the end I would like to access the coins:
c = queryfilter.coins
It may be possible that I cannot do it with one single query and need two, since I am trying to do a filter query with two tables involved.
Firstly, I have modified your 'Followers' model (for naming convention).
models.py
class Follower(models.Model):
user = models.ForeignKey('User', related_name='followers')
coins = models.IntegerField()
key = models.CharField(max_length=26, null=True, blank=True)
Your queryset should be ..
views.py
#coins
coins = Follower.objects.filter(key=fid, user__userid=uid).get().coins