ProgramingTip

Django REST 프레임 워크의 중첩 된 리소스에 필터를 적용해야합니까?

bestdevel 2020. 12. 27. 19:40
반응형

Django REST 프레임 워크의 중첩 된 리소스에 필터를 적용해야합니까?


내 앱에는 다음 모델이 있습니다.

class Zone(models.Model):
    name = models.SlugField()

class ZonePermission(models.Model):
    zone = models.ForeignKey('Zone')
    user = models.ForeignKey(User)
    is_administrator = models.BooleanField()
    is_active = models.BooleanField()

Django REST 프레임 워크를 사용하여 영역 세부 정보와 해당 영역에 대한 중첩 된 리소스를 반환하는 리소스를 만듭니다. 출력은 다음과 같아야합니다.

{
    "name": "test", 
    "current_user_zone_permission": {
        "is_administrator": true, 
        "is_active": true
    }
} 

다음과 같이 serializer를 만들었습니다.

class ZonePermissionSerializer(serializers.ModelSerializer):
    class Meta:
        model = ZonePermission
        fields = ('is_administrator', 'is_active')

class ZoneSerializer(serializers.HyperlinkedModelSerializer):
    current_user_zone_permission = ZonePermissionSerializer(source='zonepermission_set')

    class Meta:
        model = Zone
        fields = ('name', 'current_user_zone_permission')

문제는 특정 영역을 포함 할 때 중첩 된 리소스가 해당 영역에 대한 권한이있는 모든 사용자에 대한 ZonePermission 레코드를 반환 하는 것입니다. request.user중첩 된 리소스 에 필터를 적용하는 방법이 있습니까?

BTW 나는이를 HyperlinkedIdentityField위해 (http 요청을 최소화하기 위해) 사용하고 싶지 않습니다 .

해결책

이것은 아래 답변을 기반으로 구현 한 솔루션입니다. serializer 클래스에 다음 코드를 추가했습니다.

current_user_zone_permission = serializers.SerializerMethodField('get_user_zone_permission')

def get_user_zone_permission(self, obj):
    user = self.context['request'].user
    zone_permission = ZonePermission.objects.get(zone=obj, user=user)
    serializer = ZonePermissionSerializer(zone_permission)
    return serializer.data

솔루션에 대단히 감사합니다!


나는 같은 시나리오에 직면했다. 내가 사용하고있는 SerializerMethodField해당 메소드 쿼리 를 사용 하고 원하는 값을 반환하는 것입니다. request.user통해 해당 방법 으로 액세스 할 수 있습니다 self.context['request'].user.

그래도 약간의 해킹처럼 보입니다. 나는 DRF를 처음 접했기 때문에 더 많은 경험을 가진 사람이 참여할 수 있습니다.


대신 필터를 받으세요. 복수의 번호가 반환되면 예외가 발생합니다.

current_user_zone_permission = serializers.SerializerMethodField('get_user_zone_permission')

def get_user_zone_permission(self, obj):
    user = self.context['request'].user
    zone_permission = ZonePermission.objects.filter(zone=obj, user=user)
    serializer = ZonePermissionSerializer(zone_permission,many=True)
    return serializer.data

이제 여기에서 어디 방법을 사용하여 ListSerializer를 하위 클래스로 만들 수 있습니다. https://stackoverflow.com/a/28354281/3246023

ListSerializer를 하위 클래스로 생성하여 표현할 수 있습니다.

기본적으로 to_representation 메소드는 중첩 된 쿼리 세트에서 data.all ()을 호출합니다. 따라서 메소드가 호출되기 전에 데이터 = data.filter (** your_filters)를 호출합니다. 그런 다음 하위 클래스 화 된 ListSerializer를 중첩 된 serializer의 메타에 list_serializer_class로 추가해야합니다.

  1. ListSerializer 하위 클래스, _representation 프로그램 쓰기 및 수퍼 호출
  2. 중첩 된 Serializer의 메타 list_serializer_class로 서브 클래 싱 된 ListSerializer를 추가합니다.

여러 위치에서 QuerySet / 필터를 사용하는 경우 모델 에서 getter 함수를 다음 Serializer / Field에 대한 'source'kwarg를 사용하는 경우도 있습니다. DRF는get_attribute 함수를 사용할 때 찾으면 자동으로 함수 / 호출 가능을 호출 합니다.

class Zone(models.Model):
    name = models.SlugField()

    def current_user_zone_permission(self):
        return ZonePermission.objects.get(zone=self, user=user)

이 방법은 HTTP를 통한 API를 사용하여 API를 내부에서 일관되게 유지하기 때문에 좋아합니다.

class ZoneSerializer(serializers.HyperlinkedModelSerializer):
    current_user_zone_permission = ZonePermissionSerializer()

    class Meta:
        model = Zone
        fields = ('name', 'current_user_zone_permission')

바라건대 이것은 어떤 사람들에게 도움이되기를 바랍니다!

참고 : 이름이 일치 할 필요 는 없습니다 . 필요하거나 원하는 경우 소스 kwarg를 계속 사용할 수 있습니다.

편집 : 방금 모델의 기능이 사용자 나 요청에 액세스 할 수 없다는 것을 깨달았습니다. 따라서 사용자 지정 모델 필드 / ListSerializer가이 작업에 더 적합 할 것입니다.


두 가지 방법 중 하나로 할 것입니다.

1)보기에서 미리 가져 오기를 통해 수행합니다.

    serializer = ZoneSerializer(Zone.objects.prefetch_related(
        Prefetch('zone_permission_set', 
            queryset=ZonePermission.objects.filter(user=request.user), 
            to_attr='current_user_zone_permission'))
        .get(id=pk))

2) 또는 .to_representation을 통해 수행하십시오.

class ZoneSerializer(serializers.HyperlinkedModelSerializer):

    class Meta:
        model = Zone
        fields = ('name',)

    def to_representation(self, obj):
        data = super(ZoneSerializer, self).to_representation(obj)
        data['current_user_zone_permission'] = ZonePermissionSerializer(ZonePermission.objects.filter(zone=obj, user=self.context['request'].user)).data
        return data

참조 URL : https://stackoverflow.com/questions/16821684/how-can-i-apply-a-filter-to-a-nested-resource-in-django-rest-framework

반응형