Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Complex Operations #271

Closed
olasfar opened this issue Sep 6, 2018 · 1 comment
Closed

Complex Operations #271

olasfar opened this issue Sep 6, 2018 · 1 comment
Labels

Comments

@olasfar
Copy link

olasfar commented Sep 6, 2018

Hey guys,

Is there a way to do some complex queries like for instance:

"((model2__field_1=1) & (model2__field_2=2)) & ((model2__field_1=3) & (model2__field_2=4))"?

The Django's queryset should look like :

Model1.objects.filter(
    model2__field_1=1,
    model2__field_2=2
).filter(
    model2__field_1=3,
    model2__field_2=4
)

Which will result in SQL to something like :

SELECT * FROM model_1
INNER JOIN model_2 ON (...)
INNER JOIN model_2 ON (...)
WHERE (...)

Or should we write something manual with the django-filter library?

Please advice.
Thx

@rpkilby
Copy link
Collaborator

rpkilby commented Sep 6, 2018

There are two parts to this question:

  • How FilterSets handle relationships (and how this is changed in the upcoming 1.0 release)
  • How the complex backend functions

In general, your desired queryset isn't trivial to generate, given that django-filter always chains filter calls. To get a combined filter would require django-filter to reimplement itself using Q objects. While this approach would generate the desired queryset, it would sacrifice the ability to use other parts of the queryset API, such as annotations and ordering. As a result, the generated querysets look like:

MyModel.objects \
    .filter(related__fielda=1) \
    .filter(related__fieldb=2)

instead of

MyModel.objects.filter(
    related__fielda=1,
    related__fieldb=2,
)

The master branch/upcoming 1.0 release completely reimplements how RelatedFilters are handled, structuring relationships like so:

MyModel.objects.filter(
    related=RelatedModel.objects
                        .filter(fielda=1)
                        .filter(fieldb=2)
    )

This is functionally similar to the desired query, but retains the existing API such that users can still use the other parts of the queryset API (e.g., you can actually filter on related annotations, which was not possible previously).

More discussion on the queries and the SQL they generate can be found in #99 (comment). The above querysets map to the q1, q2, and q3 examples.


For the complex operations backend, it's not currently possible to nest queries, as it's a bit out of scope for the moment. However I don't think this is an issue. You should be able to do:

(model2__field_1=1&model2__field_2=2) & (model2__field_1=3&model2__field_2=4)

which should generate the following:

q1 = Model1.objects.filter(
    model2=Model2.objects
                 .filter(field_1=1)
                 .filter(field_2=2)
)
q2 = Model1.objects.filter(
    model2=Model2.objects
                 .filter(field_1=3)
                 .filter(field_2=4)
)

result = q1 & q2

I'm closing this since it's a usage question, but please feel free to continue asking questions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants