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. |
tfranzel
left a comment
There was a problem hiding this comment.
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.
| return dummy_property | ||
|
|
||
|
|
||
| def follow_model_field_lookup(model, lookup): |
There was a problem hiding this comment.
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.
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
stringtype with a warning.It also fixes cases where a lookup type like
containsoriexactwas 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
Queryclass 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.annotateand dolookup_fieldon the added field.Limitations
lookup_url_kwarg!=lookup_field, noted in the comment below.recorded_attimestamp 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_atand assume a date-formatted string, instead of an integer.iexact, which don't change the type, there will be no problem.