Absolute links in included relationship data
Hi, I've been struggling to make the following work:
class CommentSchema(Schema):
def __init__(self, prefix=None, *args, **kwargs):
super(CommentSchema, self).__init__(*args, **kwargs)
self.prefix = prefix
id = fields.Str()
content = fields.Str()
def get_resource_links(self, item):
return {
'self': '{} - some link'.format(self.prefix)
}
class Meta:
type_ = 'comments'
strict = True
self_url='/comments/{id}'
self_url_kwargs={'id': '<id>'}
class PostSchema(Schema):
def __init__(self, prefix, *args, **kwargs):
super(PostSchema, self).__init__(*args, **kwargs)
self.prefix = prefix
id = fields.Str(dump_only=True)
title = fields.Str()
comments = fields.Relationship(
include_resource_linkage=True,
type_='comments',
schema=CommentSchema # How to pass the prefix here?
)
class Meta:
type_ = 'posts'
strict = True
self_url = '/posts/{id}'
self_url_kwargs = { 'id': '<id>'}
Serializing a comment
This works as expected since I can pass the prefix to CommentSchema directly.
comment = comments=Model(id=123, content='blah')
data, errors = CommentSchema('something').dump(comment) # Passing `prefix=something`
print json.dumps(data, indent=4)
The resulting dictionary contains a links attribute with my custom links:
{
"data": {
"attributes": {
"content": "blah"
},
"type": "comments",
"id": "123",
"links": {
"self": "something - some link"
}
},
"links": {
"self": "something - some link"
}
}
Serializing a compound document
However when serializing a compound document:
comment = comments=Model(id=123, content='blah')
post = Model(id=123, title='something', comments=comment)
data, errors = PostSchema('prefix').dump(post)
print json.dumps(data, indent=4)
the resulting included shows the links prefixed with None:
{
"included": [
{
"attributes": {
"content": "blah"
},
"type": "comments",
"id": "123",
"links": {
"self": "None - some link"
}
}
],
"data": {
"relationships": {
"comments": {
"data": {
"type": "comments",
"id": "123"
}
}
},
"attributes": {
"title": "something"
},
"type": "posts",
"id": "123",
"links": {
"self": "/posts/123"
}
},
"links": {
"self": "/posts/123"
}
}
How can I pass extra args (prefix) to the relationships schema=CommaSchema option?
comments = fields.Relationship(
include_resource_linkage=True,
type_='comments',
# Invalid since `self.prefix` does not exist yet
schema=CommentSchema(self.prefix)
)
Maybe there's a better way to generate absolute links for relationship data, could you point me to an example if that's the case?
You can pass the prefix in the schema's context attribute. The relationship field inherits the context from the parent schema which was fixed in marshmallow-jsonapi==0.19.0.
class CommentSchema(Schema):
id = fields.Str()
content = fields.Str()
def get_resource_links(self, item):
prefix = self.context['prefix']
return {
'self': '{} - comment link'.format(prefix)
}
class Meta:
type_ = 'comments'
strict = True
self_url = '/comments/{id}'
self_url_kwargs = {'id': '<id>'}
class PostSchema(Schema):
id = fields.Str(dump_only=True)
title = fields.Str()
comments = fields.Relationship(
include_resource_linkage=True,
type_='comments',
schema=CommentSchema # How to pass the prefix here?
)
def get_resource_links(self, item):
prefix = self.context['prefix']
return {
'self': '{} - post link'.format(prefix)
}
class Meta:
type_ = 'posts'
strict = True
self_url = '/posts/{id}'
self_url_kwargs = {'id': '<id>'}
comments = {'id': 123, 'content': 'blah'}
post = {'id': 123, 'title': 'something', 'comments': comments}
data = PostSchema(context={'prefix': 'prefix'}, include_data=('comments',)).dump(post)
print(json.dumps(data, indent=4))
{
"data": {
"type": "posts",
"relationships": {
"comments": {
"data": {
"type": "comments",
"id": "123"
}
}
},
"id": "123",
"attributes": {
"title": "something"
},
"links": {
"self": "prefix - post link"
}
},
"links": {
"self": "prefix - post link"
},
"included": [
{
"type": "comments",
"attributes": {
"content": "blah"
},
"id": "123",
"links": {
"self": "prefix - comment link"
}
}
]
}