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
솔루션에 대단히 감사합니다!
나는 같은 시나리오에 직면했다. 내가 찾은 가장 좋은 해결책은 a를 사용하고 SerializerMethodField
해당 메서드 쿼리 를 사용 하고 원하는 값을 반환하는 것입니다. 을 request.user
통해 해당 방법 으로 에 액세스 할 수 있습니다 self.context['request'].user
.
그래도 이것은 약간의 해킹처럼 보입니다. 나는 DRF를 처음 접했기 때문에 더 많은 경험을 가진 사람이 참여할 수 있습니다.
get 대신 filter를 사용해야합니다. 그렇지 않으면 여러 레코드가 반환되면 Exception이 발생합니다.
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 메서드를 덮어 쓸 수 있습니다.
기본적으로 to_representation 메소드는 중첩 된 쿼리 세트에서 data.all ()을 호출합니다. 따라서 메서드가 호출되기 전에 효과적으로 data = data.filter (** your_filters)를 만들어야합니다. 그런 다음 하위 클래스 화 된 ListSerializer를 중첩 된 serializer의 메타에 list_serializer_class로 추가해야합니다.
- ListSerializer 하위 클래스, _representation 덮어 쓰기 및 super 호출
- 중첩 된 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)
I like this method because it keeps your API consistent under the hood with the api over HTTP.
class ZoneSerializer(serializers.HyperlinkedModelSerializer):
current_user_zone_permission = ZonePermissionSerializer()
class Meta:
model = Zone
fields = ('name', 'current_user_zone_permission')
Hopefully this helps some people!
Note: The names don't need to match, you can still use the source kwarg if you need/want to.
Edit: I just realised that the function on the model doesn't have access to the user or the request. So perhaps a custom model field / ListSerializer would be more suited to this task.
I would do it in one of two ways.
1) Either do it through prefetch in your view:
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) Or do it though the .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
ReferenceURL : https://stackoverflow.com/questions/16821684/how-can-i-apply-a-filter-to-a-nested-resource-in-django-rest-framework
'programing tip' 카테고리의 다른 글
OCaml 프로젝트를 구성하고 빌드하는 데 선호되는 방법은 무엇입니까? (0) | 2020.12.26 |
---|---|
Quartz.NET 구성 파일에 대한 문서는 어디에 있습니까? (0) | 2020.12.26 |
Android에서 최고의 REST 클라이언트 프레임 워크 / 유틸리티 (0) | 2020.12.26 |
Scala : mapValues가 뷰를 생성하는 이유는 무엇이며 안정적인 대안이 있습니까? (0) | 2020.12.26 |
AsyncTask와 Thread / Runnable의 차이점 (0) | 2020.12.26 |