Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/django/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python Django REST框架:反序列化外键失败(多对多)_Python_Django_Python 3.x_Django Rest Framework_Deserialization - Fatal编程技术网

Python Django REST框架:反序列化外键失败(多对多)

Python Django REST框架:反序列化外键失败(多对多),python,django,python-3.x,django-rest-framework,deserialization,Python,Django,Python 3.x,Django Rest Framework,Deserialization,我有以下型号: models.py: class Host(models.Model): serialnr = models.IntegerField(primary_key=True) ...some other fields... class Event(models.Model): id = models.AutoField(primary_key=True) hosts = models.ManyToManyField(Host, through='Ev

我有以下型号:

models.py:

class Host(models.Model):
    serialnr = models.IntegerField(primary_key=True)
    ...some other fields...

class Event(models.Model):
    id = models.AutoField(primary_key=True)
    hosts = models.ManyToManyField(Host, through='EventHost')
    ...some other fields...

class EventHost(models.Model):
    serialnr = models.ForeignKey(Host, on_delete=models.PROTECT)
    event = models.ForeignKey(Event, on_delete=models.CASCADE)
    ...some other fields...
    class Meta:
        unique_together = ("serialnr", "event")
serializers.py:

class EventSerializer(serializers.ModelSerializer):
    class Meta:
        model = Event
        fields = '__all__'

class HostSerializer(serializers.ModelSerializer):
    class Meta:
        model = Host
        fields = '__all__'

class EventHostSerializer(serializers.ModelSerializer):
    event =  EventSerializer(read_only=True)
    serialnr = HostSerializer(read_only=True)

    class Meta:
        model = EventHost
        fields = '__all__'

views.py

class EventViewSet(viewsets.ModelViewSet):
    queryset = Event.objects.order_by('-date')
    serializer_class = EventSerializer

class HostViewSet(viewsets.ModelViewSet):
    queryset = Host.objects.order_by('-serialnr')
    serializer_class = HostSerializer

class EventHostViewSet(viewsets.ModelViewSet):
    queryset = EventHost.objects.order_by('-start_date')
    serializer_class = EventHostSerializer

我将通过HTTP POST发送以下JSON:

{event: {id: 4}, serialnr: {serialnr: 1234}, other_filed: 20} 
但并非如日志中所示,事件id和序列号id未反序列化:

psycopg2.errors.NotNullViolation: null value in column "event_id" violates not-null constraint
DETAIL:  Failing row contains (12, 20, null, null).
我可以用HTTP GET读取数据,但不能用POST写入。我应该如何构造适当的序列化程序使其工作

另外,当我尝试发送JSON时,如下图所示,它失败了:

{event_id: 4, serialnr_id: 1234, other_filed: 20} 

发生这种情况是因为您正在创建
EventSerializer
HostSerializer
, 将传递的值序列化为
只读
,这意味着它们仅在执行
检索
操作时有效,而不是执行
创建

解决此问题的方法是从
EventHostSerializer

例如:

class EventHostSerializer(serializers.ModelSerializer):
    event =  EventSerializer() #read_only=True)
    serialnr = HostSerializer() #read_only=True)

    class Meta:
        model = EventHost
        fields = '__all__'

我已经从EventSerializerHostSerializer中删除了read_only=True参数,并打开了debug以查看有什么问题,现在我的HTTP POST请求做了什么,它试图创建新主机和新事件。这不是我需要的。我只需要引用event和host就可以在eventhost表中创建新条目

只是做个记录。当我使用django shell添加新的eventhost实例时,它可以工作:

>>> from myapp.models import Host, Event, EventHost
>>> from myapp.serializers import HostSerializer, EventSerializer, EventHostSerializer
myeventhost = EventHost.objects.create(event_id=4, serialnr_id=1234, otherparam=20)
>>> serializedmyeventhost = EventHostSerializer(myeventhost)
>>> serializedmyeventhost.data
{'id': 29, 'event': OrderedDict([('id', 4), ...etc

由于
event
serialnr
EventHost
上的外键,您需要发送已经存在的数据,因此我建议使用
PrimaryKeyRelatedField
这样,如果您发送的id在数据库中不存在,您将得到验证

您需要发送如下数据:
{事件:4,序列号:1234,其他文件:20}

并将序列化程序更改为:

from rest_framework.relations import PrimaryKeyRelatedField


class EventHostSerializer(serializers.ModelSerializer):
    event = PrimaryKeyRelatedField(queryset=Event.objects.all())
    serialnr = PrimaryKeyRelatedField(queryset=Host.objects.all())

    class Meta:
        model = EventHost
        fields = '__all__'

    # add this(if needed) to get event/serialnr representation instead of primary keys 
    # might be usefull for you when you retrieve the object back (in list/retrieve operations)
    def to_representation(self, instance):
        ret = super().to_representation(instance)
        ret['event'] = EventSerializer(context=self.context).to_representation(instance.event)
        ret['serialnr'] = HostSerializer(context=self.context).to_representation(instance.serialnr)
        return ret
稍后编辑:

我发现有一个名为django extra fields的库以更好的方式实现了这一点


我已经试过了,但是我得到了:错误的请求:/api/v1/eventhosts/[06/Feb/2020 09:45:17]“POST/api/v1/eventhosts/HTTP/1.1”400166。有没有办法追踪我的请求出了什么问题?我用HTTP POST嵌套或扁平发送的JSON格式应该是什么?
from drf_extra_fields.relations import PresentablePrimaryKeyRelatedField


class EventHostSerializer(serializers.ModelSerializer):
    event = PresentablePrimaryKeyRelatedField(
        queryset=Event.objects.all(), presentation_serializer=EventSerializer
    )
    serialnr = PresentablePrimaryKeyRelatedField(
        queryset=Host.objects.all(), presentation_serializer=HostSerializer
    )

    class Meta:
        model = EventHost
        fields = '__all__'