-
Notifications
You must be signed in to change notification settings - Fork 271
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
Handle 'lookup_field' containing relationships for path parameters #509
Handle 'lookup_field' containing relationships for path parameters #509
Conversation
Codecov Report
@@ Coverage Diff @@
## master #509 +/- ##
==========================================
+ Coverage 98.58% 98.60% +0.02%
==========================================
Files 57 57
Lines 5710 5801 +91
==========================================
+ Hits 5629 5720 +91
Misses 81 81
Continue to review full report at Codecov.
|
378e79e
to
9f96136
Compare
I think this PR needs more work - it doesn't correctly handle cases where you have |
9f96136
to
88f923f
Compare
OK, I've got to the bottom of it.
So, I've updated my patch to drop tests where I've also added a note above about other limitations. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Excellent PR! the introspection rabbit hole goes deeper and deeper 😄
I was a bit worried about using the "internal" names_to_path
, but model._meta.get_field
isn't exactly a public interface either. so works for me. from my current understanding it should cover a superset of cases without any regressions.
regarding the __date
: i can live with that. if somebody is annoyed by it, they can still use @extend_schema
to fix it up. in any case, this is an improvement.
regarding lookup_url_kwarg
: maybe we can iterate on this afterwards. fine by me for now.
@@ -460,6 +462,17 @@ def dummy_property(obj) -> str: | |||
return dummy_property | |||
|
|||
|
|||
def follow_model_field_lookup(model, lookup): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is very neat! sadly we couldn't use this for follow_field_source
. the whole thing is a lot easier if you don't leave the SQL domain.
router.register('journal', JournalEntryViewset) | ||
|
||
schema = generate_schema(None, patterns=router.urls) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would have liked a comment to note that this is actually not 100% correct but expected for the time being.
i fixed up the comment and one formatting gripe my OCD complained about. I would ask you to review this additional change. does it make sense for you and does it work for that removed test? i personally do not use this as much and my confidence there is not that strong.
i would argue that this is not really a problem. The viewset only provides the last one and everything else is "injected" (e.g. drf-nested-routers). if you set the + if getattr(self.view, 'lookup_url_kwarg', None) == variable:
+ model_field_name = getattr(self.view, 'lookup_field', variable)
+ else:
+ model_field_name = variable
model = get_view_model(self.view)
- model_field = follow_model_field_lookup(model, variable)
+ model_field = follow_model_field_lookup(model, model_field_name)
|
Thanks for fixing up the patch and merging it, sorry for the slow reply. Regarding the last question - I re-added a version of the earlier test, it does work with your code with a small adjustment - see #524 |
This PR fixes introspection cases like:
and similar, which previously would just default to
string
type with a warning.It also fixes cases where a lookup type like
contains
oriexact
was used. These are valid in DRF as can be seen from the tests - https://github.com/encode/django-rest-framework/blob/9ce541e90990307e06da1b7f5a2576406366a5e5/tests/test_routers.py#L41Strategy
The strategy I used was to trace how these are handled by DRF, which is ultimately just a call to
QuerySet.filter
- see https://github.com/encode/django-rest-framework/blob/9ce541e90990307e06da1b7f5a2576406366a5e5/rest_framework/generics.py#L95Eventually these get parsed by Query.names_to_path. So I have just wrapped up that logic with a helper function. That
Query
class is an undocumented internal in Django. However, I think this approach is going to be more robust than attempting to duplicate that logic ourselves. Any breakage in this internal API should be easy to spot with good tests (that I have added).In terms of output, I've found that both
lookup_field = 'fkrelation'
andlookup_field = 'fkrelation__id'
will produce correct introspection of types, but the latter will also give you a good description, due to a difference in how the lookup terminates. It would be nice if we automatically got the good description for both cases, but after looking at the output fromnames_to_path
, I'm not sure it is worth the additional complexity and fragility it might produce.Tests are added for the new cases handled, and a regression test for the warning in case of a missing field. There are still some cases possibly not handled, especially if you are using
QuerySet.annotate
and dolookup_field
on the added field.Limitations
lookup_url_kwarg
!=lookup_field
, noted in the comment below.recorded_at
timestamp field, and uselookup_field = 'recorded_at__year'
(which is probably kind of unlikely for a API lookup since it won't be unique), then with this patch it will act as if you specified justrecorded_at
and assume a date-formatted string, instead of an integer.iexact
, which don't change the type, there will be no problem.