I have a somewhat complicated model, so I will do my best to give an example that simplifies my current state, and my need.
I have a queryset:
qs = MyModel.objects.all()
Each instance in this queryset, has a many-2-many field to another model, let's call it 'First_M2M'. First_M2M has a foreign key to another model, and a many-2-many to yet another model (FkModel and Second_M2M, respectively):
qs[0].first_m2m.fk_model.name # This is a string.
qs[0].first_m2m.second_m2m.all() # This is a many2many manager.
The Second_M2M has another many-2-many relationship, Third_M2M:
qs[0].first_m2m.second_m2m[0].third_m2m.all() # Also a m2m manager.
Now that's what I'm trying to do: I want to order my qs, based on a value from one of the second_m2m instances. However, I need to choose which instance is it, and this is done by querying a field in the fk_model (to determine the first_m2m instance) AND a field in one of the instances in the third_m2m (this will determine the second_m2m).
In order to make it even more interesting, the value to order by, is YAML.
Here's what I tried to do:
qs.annotate(val_to_filter_by=Case(
When(
first_m2m__fk_model__name='foo',
first_m2m__second_m2m__third_m2m__some_field='bar'),
then='first_m2m__second_m2m__value_field',
default=Value(None),
output_field=YAMLField()
)
).order_by(val_to_filter)
I believe what I got wrong is the querying, that is not coherent enough for Django to determine which instance it should take. But I can't find my problem.
Any help will be much appreciated.
Solved it...
I had a mistake with my 'then. It was part of my 'Case' instead of the 'When'. Here is the solution:
qs.annotate(val_to_filter=Case(
When(
first_m2m__fk_model__name='foo',
first_m2m__second_m2m__third_m2m__some_field='bar',
then=F('first_m2m__second_m2m__value_field')
),
default=Value(''),
output_field=YAMLField()
)).order_by(val_to_filter)
UPDATE: Didn't solve it...
Although I got the right query, and it worked, I am getting ALL instances of the second_m2m, instead of a single instance. Still not sure how to get exactly what I need, seems like Django is not my friend in this case.
UPDATE2: Changed 'default=None' and added
.exclude(val_to_filter=None)
right before the ordering. Seems to work...