Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

handle meta information on HyperlinkedRelatedField #1018

Closed
jokiefer started this conversation in Ideas
Discussion options

Scenario

In case of using the HyperlinkedRelatedField](https://django-rest-framework-json-api.readthedocs.io/en/stable/usage.html#hyperlinkedrelatedfield) no data will be rendered. Also no meta information is rendered.

If you want to use the HyperlinkedRelatedField to increase performance, there is no possibility to add a meta object to that relation.

Enhancement

In my case i've got a WmsService Model:

class WebMapService(OgcService):
 objects = WebMapServiceManager()

Which is referenced by many layers:

class Layer(LayerMetadata, ServiceElement, MPTTModel):
 ...
 service = models.ForeignKey(to=WebMapService,
 on_delete=models.CASCADE,
 editable=False,
 related_name="layers",
 related_query_name="layer",
 verbose_name=_("service"),
 help_text=_("the extras service where this element is part of"))
 ....

With a custom manager i can collect the meta information optimized with low performance constraints:

class WebMapServiceManager(models.Manager):
 def with_meta(self):
 return self.annotate(
 layer_count=Coalesce(models.Count("layer"), 0)
 )

Now the meta information is present in the queryset of the view:

class WebMapServiceViewSet(NestedViewSetMixin, ModelViewSet):
 ...
 queryset = WebMapService.objects.with_meta()
 serializer_class = WebMapServiceSerializer
 ...

I could use the meta information from the queryset for the HyperlinkedRelatedField:

class WebMapServiceSerializer(ModelSerializer):
 ...
 layers = HyperlinkedRelatedField(
 queryset=Layer.objects,
 many=True, # necessary for M2M fields & reverse FK fields
 related_link_view_name='registry:wms-layers-list',
 related_link_url_kwarg='parent_lookup_service',
 self_link_view_name='registry:wms-relationships',
 required=False,
 meta_attrs={'layer_count': 'count'},
 )
 included_serializers = {
 'layers': LayerSerializer,
 }
 class Meta:
 model = WebMapService
 fields = "__all__"

Same behavior could be used for SerializerMethodResourceRelatedField, cause there is also no possibility to pass meta information. SerializerMethodResourceRelatedField will only return the data object.

You must be logged in to vote

Replies: 3 comments 4 replies

Comment options

It seems this is related to #406

You must be logged in to vote
2 replies
Comment options

The specification in terms of links states that there may be a meta field within the links.

So what you could do is you could have an new class LayerHyperlinkedRelatedField. In that class overwrite get_links and add the meta field you like. I haven't tested this but just an idea. That might help you solve your current issue.

Comment options

Thanks a lot for your suggestion. That does the trick.

Code example:

class ExtendedHyperlinkedRelatedField(HyperlinkedRelatedField):
 def __init__(self, self_link_view_name=None, related_link_view_name=None, meta_attrs=None, **kwargs):
 super().__init__(self_link_view_name=self_link_view_name,
 related_link_view_name=related_link_view_name, **kwargs)
 self.meta_attrs = meta_attrs
 def get_links(self, obj=None, lookup_field="pk"):
 links = super().get_links(obj=obj, lookup_field=lookup_field)
 if self.meta_attrs:
 meta = {}
 for lookup, name in self.meta_attrs.items():
 meta.update({name: getattr(obj, lookup)})
 links.update({'meta': meta})
 return links
class WebMapServiceSerializer(ModelSerializer):
 ...
 layers = ExtendedHyperlinkedRelatedField(
 queryset=Layer.objects,
 many=True, # necessary for M2M fields & reverse FK fields
 related_link_view_name='registry:wms-layers-list',
 related_link_url_kwarg='parent_lookup_service',
 self_link_view_name='registry:wms-relationships',
 required=False,
 meta_attrs={'layer_count': 'count'}
 )
 ...

Response:

{
...
 "relationships": {
 "layers": {
 "links": {
 "self": "https://localhost/api/v1/registry/wms/09f4376b-f9dd-44b4-a672-57a79afad8f2/relationships/layers",
 "related": "https://localhost/api/v1/registry/wms/09f4376b-f9dd-44b4-a672-57a79afad8f2/layers/",
 "meta": {
 "count": 274
 }
 }
 },
...
}
Comment options

Any suggestion how to adapt this approach to adding a meta field on the data part of a relationship instead of the links part? In particular for a SerializerMethodResourceRelatedField.

(Also commented this on an issue (#406), but I guess discussion may have more chance on receiving an answer)

You must be logged in to vote
0 replies
Comment options

@YetAnotherWebDeveloper I developed a workaround for me in my project.

I use the common ResourceRelatedField fields (Then meta and data is provided).
On view level then i prefetch the needed id`s if the relation is not included. See my get_queryset function for example.

This fixes the n+1 query problem for this fields ;-)

@sliverc maybe this could be default behavior to increase the performance for non included related data fields.

You must be logged in to vote
2 replies
Comment options

Thanks for helping, do you mean that ResourceRelatedField meta functionality is possible/supported like this?

{
...
 "relationships": {
 "books": {
 "data": [
 { "type": "Book", "id": "1", "meta": { "category": "A" } },
 { "type": "Book", "id": "2", "meta": { "category": "B" } },
 ]
 }
 }
}
Comment options

I missmatched your problem. My initial post was the first workaround for my performance issue with ResourceRelatedField.

Currently there is still no support for meta on field level. Only on resource level you can add meta information.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Category
Ideas
Labels
None yet
2 participants

AltStyle によって変換されたページ (->オリジナル) /