I want to remove objects with the same field value from a queryset. I've seen some related answers here, but none of them use the annotate and Min feature and I don't know if that approach is even possible.
Imagine I have a 'Book' model with a 'Library' model FK. A Library could have multiple Books with the same title.
How can I obtain a list of Books from that Library with different titles and lower price?
I've tried different approaches with no success:
models.py
class Library(models.Model):
name = models.CharField(_('Library name'), max_length=255)
location = models.ForeignKey(Location, on_delete=models.CASCADE)
class Book(models.Model):
name = models.CharField(_('Title'), max_length=255)
author = models.CharField(_('Author'), max_length=255)
editorial = models.CharField(_('Editorial'), max_length=255)
price = models.FloatField(_('Price'), default=0)
library = models.ForeignKey(Library, on_delete=models.CASCADE, related_name='libraries',
related_query_name='libraries')
Queryset
Book.objects.annotate(count_id=Count('title'), min_price=Min('price')).filter(library__id=21, price=F('min_price')).values_list('title')
Example:
Having this objects | ID | Title | Price | |:---- |:------:| :-----| | 1 | Trainspotting | 3 | | 2 | The Catcher in the rye | 2 | | 3 | Trainspotting | 1 | | 4 | Lord of the Rings | 5 | | 5 | Trainspotting | 5 |
I want to obtain the following queryset:
| ID | Title | Price |
|---|---|---|
| 2 | The Catcher in the rye | 2 |
| 3 | Trainspotting | 1 |
| 4 | Lord of the Rings | 5 |
EDIT:
Using the distinct=True in Count gives me the following results:
In this case my Library contains two Trainspotting books with the same price and two titles of 'The Catcher in the Rye' with prices 2 and 4.
Here I'm printing the annotated fields within the name to see what's could be wrong: Book.objects.annotate(count_id=Count('title', distinct=True), min_price=Min('price')).filter(library__id=21, price=F('min_price')).values_list('name', 'min_price', 'count_id')
The QS I obtain is the following:
<QuerySet [('Trainspotting', 1.0, 1), ('Trainspotting', 1.0, 1), ('The Catcher in the Rye', 2.0, 1), ('The Catcher in the Rye', 4.0, 1)]>
Thanks you very much for your help!