# wrong
...
def _deserialize(self, value, attr, context):
# "context" is actually the original "data" passed to "Schema(...).load"
# and not the "Schema(context=context).load(...)" (see docs link above)
pid = context.get('pid')
return pid.get('pid_value') if pid else missing
...
# correct
def _deserialize(self, value, attr, data):
pid = self.context.get('pid')
return pid.get('pid_value') if pid else missing
When addressing this, keep in mind that:
When doing a POST /api/records, there will be no request.view_args['pid_value'] and thus it won't be available in the loader schema's context, since the route doesn't have the PID yet, opposed to e.g. PUT /api/records/<pid(recid):pid_value>. The PID will be minted though and passed to the serializer and thus will be available in the context of Field._serializebecause of this guy.
Marshmallow has a pretty weird behaviour when it comes to loading/dumping fields that were not there originally. See a bunchof completelyconfused people trying to understand what went so terribly wrong in their lives... The closest thing to a solution is either using @post_load or this guy's custom Generated field. This is not optimal of course because in either way it requires educating developers on how to use marshmallow properly. The gist of it is:
default=<value or callable> is for providing a value when serializing
missing=<value or callable> is for providing a value when deserializing
Neither default or missing have access to context or data in any way...
Two solutions:
Modify our PersistentIdentifier field to some sort of Generator magic (seems a bit cleaner for the end-user)
The
.schemas.fields.PersistentIdentifier
marshmallow field, is assuming a wrong method signature when overridingField._deserialize
andField._serialize
:When addressing this, keep in mind that:
POST /api/records
, there will be norequest.view_args['pid_value']
and thus it won't be available in the loader schema's context, since the route doesn't have the PID yet, opposed to e.g.PUT /api/records/<pid(recid):pid_value>
. The PID will be minted though and passed to the serializer and thus will be available in the context ofField._serialize
because of this guy.GET /api/records/
endpoint) thecontext['pid']
is not ainvenio_pidstore.models.PersistentIdentifier
, but actually ainvenio_pidstore.fetchers.FetchedPID
. It haspid.pid_value
andpid.pid_type
, but none of methods/attributes that the SQLAlchemy model does.@post_load
or this guy's customGenerated
field. This is not optimal of course because in either way it requires educating developers on how to use marshmallow properly. The gist of it is:default=<value or callable>
is for providing a value when serializingmissing=<value or callable>
is for providing a value when deserializingdefault
ormissing
have access tocontext
ordata
in any way...PersistentIdentifier
field to some sort ofGenerator
magic (seems a bit cleaner for the end-user)@post_load
mixin