다음과 같은 모델이 있습니다.
class Category(models.Model):
parentCategory = models.ForeignKey('self', blank=True, null=True, related_name='subcategories')
name = models.CharField(max_length=200)
description = models.CharField(max_length=500)
serializer를 사용하여 모든 범주의 평면 json 표현을 얻을 수있었습니다.
class CategorySerializer(serializers.HyperlinkedModelSerializer):
parentCategory = serializers.PrimaryKeyRelatedField()
subcategories = serializers.ManyRelatedField()
class Meta:
model = Category
fields = ('parentCategory', 'name', 'description', 'subcategories')
이제 내가하고 싶은 것은 하위 카테고리 목록이 ID 대신 하위 카테고리의 인라인 json 표현을 갖는 것입니다. django-rest-framework로 어떻게할까요? 문서에서 찾으려고했지만 불완전한 것 같습니다.
답변
ManyRelatedField를 사용하는 대신 중첩 된 serializer를 필드로 사용합니다.
class SubCategorySerializer(serializers.ModelSerializer):
class Meta:
model = Category
fields = ('name', 'description')
class CategorySerializer(serializers.ModelSerializer):
parentCategory = serializers.PrimaryKeyRelatedField()
subcategories = serializers.SubCategorySerializer()
class Meta:
model = Category
fields = ('parentCategory', 'name', 'description', 'subcategories')
임의로 중첩 된 필드를 처리 하려면 문서 의 기본 필드 사용자 지정 부분을 살펴 봐야 합니다. 현재 직렬 변환기를 자체 필드로 직접 선언 할 수는 없지만 이러한 메서드를 사용하여 기본적으로 사용되는 필드를 재정의 할 수 있습니다.
class CategorySerializer(serializers.ModelSerializer):
parentCategory = serializers.PrimaryKeyRelatedField()
class Meta:
model = Category
fields = ('parentCategory', 'name', 'description', 'subcategories')
def get_related_field(self, model_field):
# Handles initializing the `subcategories` field
return CategorySerializer()
사실, 위의 내용은 옳지 않습니다. 이것은 약간의 해킹이지만 serializer가 이미 선언 된 후에 필드를 추가 할 수 있습니다.
class CategorySerializer(serializers.ModelSerializer):
parentCategory = serializers.PrimaryKeyRelatedField()
class Meta:
model = Category
fields = ('parentCategory', 'name', 'description', 'subcategories')
CategorySerializer.base_fields['subcategories'] = CategorySerializer()
재귀 적 관계를 선언하는 메커니즘을 추가해야합니다.
편집 : 이제 이러한 종류의 사용 사례를 특별히 다루는 타사 패키지를 사용할 수 있습니다. djangorestframework-recursive를 참조하십시오 .
답변
@wjin의 솔루션은 to_native 를 사용하지 않는 Django REST 프레임 워크 3.0.0으로 업그레이드 할 때까지 잘 작동 했습니다. . 다음은 약간 수정 된 DRF 3.0 솔루션입니다.
예를 들어 “응답”이라는 속성에 스레드 된 주석과 같이 자체 참조 필드가있는 모델이 있다고 가정합니다. 이 주석 스레드의 트리 표현이 있고 트리를 직렬화하려고합니다.
먼저 재사용 가능한 RecursiveField 클래스를 정의하십시오.
class RecursiveField(serializers.Serializer):
def to_representation(self, value):
serializer = self.parent.parent.__class__(value, context=self.context)
return serializer.data
그런 다음 serializer의 경우 RecursiveField를 사용하여 “replies”값을 직렬화합니다.
class CommentSerializer(serializers.Serializer):
replies = RecursiveField(many=True)
class Meta:
model = Comment
fields = ('replies, ....)
쉽고 간단하며 재사용 가능한 솔루션을 위해 4 줄의 코드 만 필요합니다.
참고 : 방향성 비순환 그래프 (FANCY!) 와 같이 데이터 구조가 트리보다 더 복잡한 경우 @wjin의 패키지를 사용해 볼 수 있습니다. 그의 솔루션을 참조하십시오. 하지만 MPTTModel 기반 트리에 대한이 솔루션에는 문제가 없었습니다.
답변
Django REST Framework 3.3.2에서 작동하는 또 다른 옵션 :
class CategorySerializer(serializers.ModelSerializer):
class Meta:
model = Category
fields = ('id', 'name', 'parentid', 'subcategories')
def get_fields(self):
fields = super(CategorySerializer, self).get_fields()
fields['subcategories'] = CategorySerializer(many=True)
return fields
답변
여기 게임이 늦었지만 여기에 내 해결책이 있습니다. Blah 유형의 자식이 여러 개있는 Blah를 직렬화한다고 가정 해 보겠습니다.
class RecursiveField(serializers.Serializer):
def to_native(self, value):
return self.parent.to_native(value)
이 필드를 사용하여 하위 개체가 많은 재귀 적으로 정의 된 개체를 직렬화 할 수 있습니다.
class BlahSerializer(serializers.Serializer):
name = serializers.Field()
child_blahs = RecursiveField(many=True)
DRF3.0에 대한 재귀 필드를 작성하고 pip https://pypi.python.org/pypi/djangorestframework-recursive/에 대해 패키징했습니다.
답변
나는이 결과를 serializers.SerializerMethodField
. 이것이 최선의 방법인지 확실하지 않지만 나를 위해 일했습니다.
class CategorySerializer(serializers.ModelSerializer):
subcategories = serializers.SerializerMethodField(
read_only=True, method_name="get_child_categories")
class Meta:
model = Category
fields = [
'name',
'category_id',
'subcategories',
]
def get_child_categories(self, obj):
""" self referral field """
serializer = CategorySerializer(
instance=obj.subcategories_set.all(),
many=True
)
return serializer.data
답변
또 다른 옵션은 모델을 직렬화하는 뷰에서 재귀하는 것입니다. 예를 들면 다음과 같습니다.
class DepartmentSerializer(ModelSerializer):
class Meta:
model = models.Department
class DepartmentViewSet(ModelViewSet):
model = models.Department
serializer_class = DepartmentSerializer
def serialize_tree(self, queryset):
for obj in queryset:
data = self.get_serializer(obj).data
data['children'] = self.serialize_tree(obj.children.all())
yield data
def list(self, request):
queryset = self.get_queryset().filter(level=0)
data = self.serialize_tree(queryset)
return Response(data)
def retrieve(self, request, pk=None):
self.object = self.get_object()
data = self.serialize_tree([self.object])
return Response(data)
답변
나는 최근에 같은 문제를 겪었고 지금까지 임의의 깊이에서도 작동하는 것처럼 보이는 해결책을 찾았습니다. 해결책은 Tom Christie의 작은 수정입니다.
class CategorySerializer(serializers.ModelSerializer):
parentCategory = serializers.PrimaryKeyRelatedField()
def convert_object(self, obj):
#Add any self-referencing fields here (if not already done)
if not self.fields.has_key('subcategories'):
self.fields['subcategories'] = CategorySerializer()
return super(CategorySerializer,self).convert_object(obj)
class Meta:
model = Category
#do NOT include self-referencing fields here
#fields = ('parentCategory', 'name', 'description', 'subcategories')
fields = ('parentCategory', 'name', 'description')
#This is not needed
#CategorySerializer.base_fields['subcategories'] = CategorySerializer()
하지만 어떤 상황 에서도 안정적으로 작동 할 수 있을지 모르겠지만 …