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

Add support for DRF-like Meta classes inside custom serializer #72

Open
wants to merge 8 commits into
base: master
Choose a base branch
from

Conversation

jacobstoehr
Copy link

If pulled, this would extend serpy with the ability to accept a Meta class inside the custom serializer class.
The syntax for this class is heavily borrowed from DRF's ModelSerializer, e.g. it needs a model (either Django or SQLAlchemy) and an exclude or fields attribute which tell serpy which fields to exclude or include in the serialization.

This was inspired by the need to serialize a very big Django model but with greater speed than what DRF provides. However, this had the drawback of also needing to specifiy each field to be serialized in the Serializer, instead of just inserting a Meta class and be done.

I have done some basic benchmarks, this does not negatively impact the standard serialization speed, because of the top level if meta: statement, which will just skip the code if no Meta class is provided. If the class has been provided, the serialization speed doesn't suffer, at least on my machine. I have not conducted any kind of statistical benchmarking, just quick tests using the UNIX time utility.

I wanted to keep this code inside the SerializerMeta, so that the implicit fields are calculated at startup time, not at serialization time. This however means all serializers inheriting from serpy.Serializer will have this ability, not like DRF where only serializers inheriting from rest_framework.serializers.ModelSerializer will have this ability.

This was achieved by adding a check if there is a `Meta` class present inside
the custom serializer.
Now, if that class exists, an attempt is made to get the model information for
both Django models as well as SQLAlchemy models. Others are not supported and
will raise a RuntimeError.
The `_field_map` is then updated accordingly, but MethodFields or custom `attr`
keyword arguments are not overwritten.
This makes it possible to not serialize certain fields.
By adding a `fields` parameter which can be either '__all__' or a list of fields
from the model.
And by making this `fields` attribute or the `exclude` attribute usable, but not
both at the same time.
Before, the `direct_fields` dict holding all fields declared in the custom
serializer was overwritten with all implicitly defined fields from the `Meta`
class inside the custom serializer.

That means if someone declared anything other than a standard Field for an
attribute of the model, this would have been overwritten with a standard Field
instance instead of keeping the explicitly declared field type, effectively
nullifying the effect of the explicit declaration.

Now, if someone was to declare a field explicitly, the SerializerMeta class
will not overwrite this field  with a standard Field instance in the
`direct_fields` dict, but will instead skip this field, thus preserving the
explicit declaration.

Also add some more comments explaining this in the code.
@coveralls
Copy link

Coverage Status

Coverage decreased (-18.0%) to 82.0% when pulling f0e578b on jacobstoehr:master into 0c58fb8 on clarkduvall:master.

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

Successfully merging this pull request may close these issues.

2 participants