假设我有两个模型,它们的序列化器是这样的:
class Billing(models.Model):
...
class Transaction(models.Model):
billing = models.ForeignKey(Billing, null=False, blank=False)
...
class TransactionSerializer(serializers.ModelSerializer):
billing = serializers.PrimaryKeyRelatedField(queryset=Billing.objects.all())
class Meta:
model = Transaction
fields = '__all__'
现在,我希望有一个端点将新交易发布到帐单中,如下所示:
post http://address/billings/{id}/transactions [{other fields except billing because the billing exists in the address}]
为此,我编写了这样的视图集:
class BillingTransactionList(generics.ListCreateAPIView):
serializer_class = TransactionSerializer
def get_queryset(self):
billing = get_object_or_404(Billing.objects.all(), pk=self.kwargs['pk'])
return Transation.objects.filter(billing=billing)
def perform_create(self, serializer):
billing = get_object_or_404(Billing.objects.all(), pk=self.kwargs['pk'])
return serializer.save(billing=billing)
但是,如果我从请求中获取的数据中不存在计费,则序列化程序将失败,因为它需要在请求的原始数据中进行计费。我有来自端点的账单,我只希望序列化程序接受数据,然后像在perform_create
中一样添加账单。
有一个向required=False
添加TransactionSerializer
的选项,但是我需要在required=True
的另一个地方使用此序列化器,还有另一种解决方案来编写另一个序列化器,但实际上例如,序列化程序是一个大类,我不想再次编写。我正在寻找一种简单的解决方案,以忽略计费数据的消失,让我随时定义它。
我正在使用django 1.11.3和DRF 3.8.2。
答案 0 :(得分:1)
我认为最好使用2种不同的序列化器(以它们具有父序列化器的方式,其中包含大多数常用代码)来执行操作。
但是如果您不想使用2个序列化器解决方案,则可以覆盖if ($conn->multi_query($sql) === TRUE) {
echo "Property Added: '$est_name'";
} else if (mysqli_errno($conn) !== 1062) {
print 'Error - Duplicate Entry!';
}
else {
echo "Error: " . $sql . "<br>" . $conn->error;
}
方法,如果to_internal_value
字段中的URL参数为空白,则可以选择billing
字段的url参数(pk)数据(而且,由于通用视图将自身传递给序列化程序,因此您可以访问序列化程序中的url参数)。所以:
class TransactionSerializer(serializers.ModelSerializer):
billing = serializers.PrimaryKeyRelatedField(queryset=Billing.objects.all())
class Meta:
model = Transaction
fields = '__all__'
def to_internal_value(self, data):
billing_pk_in_url = self.context['view'].kwargs.get('pk', None)
if 'billing' not in data: ## or any other condition that you want
data['billing'] = billing_pk_in_url
return super().to_internal_value(data)
现在,您甚至不必覆盖perform_create
方法:
class BillingTransactionList(generics.ListCreateAPIView):
serializer_class = TransactionSerializer
def get_queryset(self):
billing = get_object_or_404(Billing.objects.all(), pk=self.kwargs['pk'])
return Transation.objects.filter(billing=billing)
答案 1 :(得分:0)
您可以更改设计吗?我认为那会更容易。例如,由于billing
是Transaction
上的字段,因此您可以查询http://address/billings/transactions?billing_id= {billing_id}
在不存在该实例的情况下尝试获取ViewSet以支持详细信息操作似乎很困难。最好从另一种允许计费从一开始就可以为空的方式进行处理。
如果这不是一个选项,则如果URL中传递的ID可能不存在,则需要停止使用get_object_or_404
。您还应该这样更改TransactionSerializer
:
class TransactionSerializer(serializers.ModelSerializer):
billing = serializers.PrimaryKeyRelatedField(
queryset=Billing.objects.all(), allow_null=True, many=False)
...