我有以下模型:
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}
但不是event_id和serialnr_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}
答案 0 :(得分:2)
由于event
和serialnr
是EventHost
上的ForeignKeys,因此您需要发送已经存在的数据,因此我建议使用PrimaryKeyRelatedField
来发送数据,从而获得验证您的数据库中不存在的ID。
您将需要发送以下数据:
{event: 4, serialnr: 1234, other_filed: 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的库,可以更好地完成此任务。
https://github.com/Hipo/drf-extra-fields#presentableprimarykeyrelatedfield
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__'
答案 1 :(得分:0)
发生这种情况是因为您正在制作EventSerializer
和HostSerializer
,
将传递的值序列化为read_only
,这意味着它们仅在存在retrieve
动作而不是create
解决这个问题的方法就是从您的read_only
移除EventHostSerializer
矮人
类似于以下内容:
class EventHostSerializer(serializers.ModelSerializer):
event = EventSerializer() #read_only=True)
serialnr = HostSerializer() #read_only=True)
class Meta:
model = EventHost
fields = '__all__'
答案 2 :(得分:0)
我从 EventSerializer 和 HostSerializer 中删除了 read_only = True 参数,并打开了调试功能,以查看问题所在以及现在的HTTP POST请求会尝试创建新的主机和新事件。那不是我所需要的。我只需要引用事件并托管在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