-
Notifications
You must be signed in to change notification settings - Fork 7
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
Spec-to-serializer #76
Conversation
OK, with the latest change this PR is much more additive and optional. The change in behaviour of the existing Instead, I've introduced another higher-level utility function, This makes this change much more of a "handy added utils" type of thing, rather than a fundamental change to the behaviour of the |
…nship name to generate the serializer name
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.
🥳
@@ -30,7 +30,7 @@ pip install django-readers | |||
|
|||
## What is django-readers? | |||
|
|||
`django-readers` is both a **small library** (less than 500 lines of Python) and a **collection of recommended patterns** for structuring your code. It is intended to help with code that performs _reads_: querying your database and presenting the data to the user. It can be used with views that render HTML templates as well as [Django REST framework](https://www.django-rest-framework.org/) API views, and indeed anywhere else in your project where data is retrieved from the database. | |||
`django-readers` is both a **small library** and a **collection of recommended patterns** for structuring your code. It is intended to help with code that performs _reads_: querying your database and presenting the data to the user. It can be used with views that render HTML templates as well as [Django REST framework](https://www.django-rest-framework.org/) API views, and indeed anywhere else in your project where data is retrieved from the database. |
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.
Slight 😢 at the removal of (less than 500 lines of Python)
but all for the greater good!
This is quite a big change, but it should be entirely backwards-compatible and optional. It's isolated to the
rest_framework
"layer" ofdjango-readers
. If DRF isn't being used in a project, this change won't affect anything.The DRF layer of
django-readers
does not use Serializers at all. Instead it uses a class (ProjectionSerializer
) that quacked just enough like a real serializer to work with DRF's generic views.However, some bits of the DRF ecosystem (specifically schema generation, but I'm sure there are others) depend on having a serializer class for introspection to work.
The core of this change is a new utility function
serializer_class_for_spec
. Given a name prefix, a model class, and a spec, this function returns a "real" DRF serializer that is the same "shape" as the spec, including nested serializers to represent relationships.The fields on this serializer are not actually used during request/response handling (we still just project the object being serialized). Instead, the purpose of this is essentially to enable automatic schema generation (see #70) via introspection of views. But it may also make
django-readers
more compatible with any other parts of the DRF ecosystem that require actual serializer classes.A couple of other changes are needed to enable this:
Specifying field types
For spec fields that are simple model fields or relationships, we can use DRF's
ModelSerializer
machinery to automatically infer their types from the model. However, for custom pairs, we need a way to explicitly declare the return type. To enable this, a utility functionout
is provided. This can be used in two ways.As a decorator:
Or, with some special DSL-ish syntax, inline in a spec (for use with built-in library functions):
Dynamic behaviour
Second, if a spec is in any way "dynamic" (ie depends on the request in some way), the previously documented way to handle this was to override
get_spec
on your view class and return the spec, rather than using a staticspec
property:Of course, during introspection no
request
object is available, and so this approach wouldn't work. Instead, during request processing, the DRF layer indjango-readers
now pre-processes thespec
and any callable objects it finds are automatically called and passed therequest
object. So there's no need to overrideget_spec
at all:TODO
Open question (answered: see comments below):
Do we actually want to avoid changing the behaviour of
SpecMixin
here at all (other than pre-processing for callables), and instead simply documentspec_to_serializer_class
as a util for use in customAutoSchema
subclasses? My concerns are:get_serializer_class
returns a real Serializer, but this serializer isn't actually used during serializationSerializer
(as opposed to the tiny "fake serializer" that we used before).