Django嵌套的序列化器没有序列化内部模型

时间:2018-04-17 13:12:37

标签: python django django-rest-framework

我尝试使用action向Django2中的ViewSet添加自定义django-rest-framework。问题是我的序列化程序没有序列化嵌套模型,从而给我错误:

{
    "labels": [
        {
            "non_field_errors": [
                "Invalid data. Expected a dictionary, but got Label."
            ]
        },
        {
            "non_field_errors": [
                "Invalid data. Expected a dictionary, but got Label."
            ]
        }
    ]
}

我有两个有M:N关系的模型。

标签型号:

class Label(models.Model):
    name = models.CharField(max_length=30, help_text='Name of Label')
    desc = models.CharField(max_length=200, help_text='Description of Label')

    def __str__(self):
        return self.name

LabelSet模型:

class LabelSet(models.Model):
    labels = models.ManyToManyField(Label, blank=True, help_text='ManyToMany field of corresponding labels')
    name = models.CharField(max_length=30, help_text='Name of Label Set')
    desc = models.CharField(max_length=200, help_text='Description of Label Set')

    def __str__(self):
        return self.name

机器型号:

class Machine(models.Model):
    name = models.CharField(max_length=30, help_text='Name of machine')
    desc = models.CharField(max_length=200, help_text='Description of machine')
    location = models.ForeignKey(Location, null=True, blank=True, on_delete=models.CASCADE, help_text='ID of machine location')
    labelset = models.ForeignKey(LabelSet, null=True, blank=True, on_delete=models.DO_NOTHING, help_text='ID of set of labels relevant for this machine')

    def __str__(self):
        return self.name

串行器:

class LabelSerializer(serializers.ModelSerializer):
    class Meta:
        model = Label
        fields = '__all__'

class LabelSetSerializer(serializers.ModelSerializer):
    qs = Label.objects.all().values()
    labels = LabelSerializer(qs, many=True)
    class Meta:
        depth = 1
        model = LabelSet
        fields = ('name', 'desc', 'labels')

viewsets.py中的自定义操作(我想按机器检索可用标签,因此路径为/machines/{id}/labels

class MachineViewSet(viewsets.ModelViewSet):
    '''
    A viewset used for retrieving and editing Machine instances.
    '''
    #permission_classes = (DRYPermissions,)
    serializer_class = MachineSerializer
    queryset = Machine.objects.all()

    # /api/v1/machines/{machine_id}/labels
    @action(detail=True)
    def labels(self, request, pk=None):
        # Get labelset id
        ls = Machine.objects.get(pk=pk).labelset

        # Get LabelSet instance
        serializer = LabelSetSerializer(data=model_to_dict(ls))
        if serializer.is_valid():
            return Response(serializer.data)
        else:
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

端点工作正常,但在查询/machines/1/labels时,我得到的响应是第一个片段:

  

"数据无效。期待一本字典,但得到了标签。"

我完全没有想法,甚至尝试在qs = Label.objects.all().values()Serializer制作字典,但没有运气。

感谢@Jerin Peter George,现在的输出是:

HTTP 200 OK
Allow: GET, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "name": "TestSet",
    "desc": "asd",
    "labels": [
        {
            "id": 1,
            "name": "OK",
            "desc": "desc"
        },
        {
            "id": 2,
            "name": "Broken",
            "desc": "asd"
        }
    ]
}

所以/api/v1/machines/1/labels有效,但突然/api/v1/machines/没有。 (502 Bad Gateway with error TypeError: 'LabelSet' object is not iterable

APP级别网址:

from django.conf.urls import url
from devices.viewsets import *
from rest_framework.routers import DefaultRouter

router = DefaultRouter()
router.register(r'devices', DeviceViewSet, base_name='device')
router.register(r'projects', ProjectViewSet, base_name='project')
router.register(r'locations', LocationViewSet, base_name='location')
router.register(r'industries', IndustryViewSet, base_name='industry')
router.register(r'companies', CompanyViewSet, base_name='companies')
router.register(r'project_types', ProjectTypeViewSet, base_name='project_type')
router.register(r'device_types', DeviceTypeViewSet, base_name='device_type')
router.register(r'machines', MachineViewSet, base_name='machine')
router.register(r'records', RecordViewSet, base_name='record')
router.register(r'labels', LabelViewSet, base_name='label')
router.register(r'labelsets', LabelSetViewSet, base_name='label_set')
urlpatterns = router.urls

应用级别urls.py

from django.contrib import admin
from django.conf.urls import url
from django.urls import include, path
from rest_framework.documentation import include_docs_urls
from rest_framework_expiring_authtoken import views
from devices.views import AudioUploadView

API_PREFIX = 'api/v1/'

urlpatterns = [
    url(API_PREFIX + 'docs/', include_docs_urls(title='API Docs')),
    url(API_PREFIX + 'admin/', admin.site.urls),
    url(API_PREFIX + 'api-token-auth/', views.obtain_expiring_auth_token),
    path(API_PREFIX, include('devices.urls'))
]

编辑:已解决 显然我向MachineSerializer

添加了一个嵌套的序列化程序
class MachineSerializer(serializers.ModelSerializer):
    labelsets = LabelSetSerializer(many=True)
    class Meta:            
        model = Machine
        fields = '__all__'

删除行labelsets = LabelSetSerializer(many=True)就行了。 这就是错误的来源,现在一切都按预期工作,谢谢:)

1 个答案:

答案 0 :(得分:1)

将您的labels()替换为以下代码段,

@action(detail=True)
def labels(self, request, pk=None):
    # Get labelset id
    ls = Machine.objects.get(pk=pk).labelset

    # Get LabelSet instance
    serializer = LabelSetSerializer(ls)
    return Response(serializer.data)