Skip to content

Instantly share code, notes, and snippets.

@lsowen
Created October 5, 2015 15:44
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lsowen/99dedd98227f518336a2 to your computer and use it in GitHub Desktop.
Save lsowen/99dedd98227f518336a2 to your computer and use it in GitHub Desktop.
django-rest-framework-json-api dynamic filter relationship

I needed to be able to filter which items of a ManyRelatedField were returned, based on some attributes of the request user. Normally, all items in the relationship are returned, however I was able to override the ManyRelatedField.to_attribute() function to enable additional filtering of the relationship.

from rest_framework.relations import MANY_RELATION_KWARGS, ManyRelatedField
from rest_framework import serializers
from rest_framework_json_api.relations import ResourceRelatedField
class CustomManyRelatedField(ManyRelatedField):
def get_attribute(self, instance):
# Override the default implementation of get_attribute
# Can't have any relationships if not created
if hasattr(instance, 'pk') and instance.pk is None:
return []
relationship = get_attribute(instance, self.source_attrs)
queryset = self.filter_relationship(instance, relationship)
return queryset.all() if (hasattr(queryset, 'all')) else queryset
def filter_relationship(self, instance, relationship):
user = self.context['request'].user
return relationship.filter("some additional logic here")
class CustomResourceRelatedField(ResourceRelatedField):
@classmethod
def many_init(cls, *args, **kwargs):
list_kwargs = {'child_relation': cls(*args, **kwargs) }
for key in kwargs.keys():
if key in MANY_RELATION_KWARGS:
list_kwargs[key] = kwargs[key]
return CustomManyRelatedField(**list_kwargs)
class BuildSerializer(serializers.ModelSerializer):
artifacts = CustomResourceRelatedField(queryset=BuildArtifact.objects, many=True)
class Meta:
model = Build
@emojiface-ops
Copy link

Thanks a million, this worked great! I modified slightly to filter out objects that have an "is_deleted" flag set to true (and changed super call to work with Python 2.x):

class IgnoreDeletedManyRelatedField(ManyRelatedField):

    def get_attribute(self, instance):
        # Override the default implementation of get_attribute
        # Can't have any relationships if not created
        if hasattr(instance, 'pk') and instance.pk is None:
            return []

        relationship = super(ManyRelatedField, self).get_attribute(
            instance)
        queryset = relationship.filter(is_deleted=False)
        return queryset.all() if (hasattr(queryset, 'all')) else queryset


class IgnoreDeletedResourceRelatedField(ResourceRelatedField):

    @classmethod
    def many_init(cls, *args, **kwargs):
        list_kwargs = {'child_relation': cls(*args, **kwargs) }
        for key in kwargs.keys():
            if key in MANY_RELATION_KWARGS:
                list_kwargs[key] = kwargs[key]
        return IgnoreDeletedManyRelatedField(**list_kwargs)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment