Django REST框架:验证Serialiser列表更新(PUT),两个字段上没有pk和唯一索引
我花了几天的时间在这方面,并在房子周围阅读(我有好几次rtfm…也许我还不了解tfm)。接近一些答案,我担心最终问题在于我对Django/Serilizers(sic)如何工作的了解 我将从我的基本问题开始,让事情变得简单,而不是我为使其工作所做的任何尝试 我正在尝试执行以下操作:Django REST框架:验证Serialiser列表更新(PUT),两个字段上没有pk和唯一索引,django,rest,api,validation,Django,Rest,Api,Validation,我花了几天的时间在这方面,并在房子周围阅读(我有好几次rtfm…也许我还不了解tfm)。接近一些答案,我担心最终问题在于我对Django/Serilizers(sic)如何工作的了解 我将从我的基本问题开始,让事情变得简单,而不是我为使其工作所做的任何尝试 我正在尝试执行以下操作: (工作)从Django rest_框架API获取值列表 基于双索引,其中一个字段在URL中传递 (control_sys)并传入第二个字段的多个值 (JSON)提交给API的数据(transactionID) (不工
## Comms Queue
class CommsQueue(models.Model):
# primary key
# foreign key
control_sys = models.IntegerField("Control system foreign key (passive)", blank=True, null=True, default=None)
meter = models.IntegerField("Meter foreign key (passive)", blank=True, null=True, default=None)
# string
data = models.CharField("Comm data", max_length=200, blank=True, null=True, default=None)
# int
transactionID = models.BigIntegerField("Comms Transaction ID", blank=True, null=False)
source = models.IntegerField("Originating source for event", blank=True, null=False)
target = models.IntegerField("Target destination for event", blank=True, null=False, db_index=True)
priority = models.IntegerField("Comms priority", blank=True, default=0)
# url
URI = models.URLField("Comm URI",max_length=200, blank=True, null=True, default=None)
# bool
#comm_send = models.BooleanField("Event requires uplink/downlink", blank=False, default=True) # TODO delete?
comm_sent = models.BooleanField("Uplink/Downlink sent", blank=True, default=False)
complete_req = models.BooleanField("Require completion notice", blank=True, default=False)
complete = models.BooleanField("Event complete", blank=True, default=False)
# date
create_date = models.DateTimeField("Date created", auto_now=False, auto_now_add=True)
last_date = models.DateTimeField("Date accessed", auto_now=True, auto_now_add=False)
class Meta:
unique_together = (("control_sys","transactionID"),)
index_together = [("control_sys","transactionID"),]
def __unicode__(self):
return "Transaction ID: %s, Complete: %s" % (str(self.transactionID), str(self.complete))
CommsSerialiser(<QuerySet[
<CommsQueue: TransactionID: 313011,
Complete: False>,
<CommsQueue: TransactionID: 313013,
Complete: False>,
<CommsQueue: TransactionID: 313102,
Complete: False>
]>,
context={
u'request': <rest_framework.request.Requestobject>
},
data=[
{
u'control_sys': 710017,
u'complete': 1,
u'data': u'"{data innit}"',
u'URI': u'http: //172.16.32.40: 8000/api/0.1/comm/710017/313102/',
u'transactionID': 313102,
u'complete_req': 1
},
{
u'control_sys': 710017,
u'complete': 1,
u'data': u'"{data innit}"',
u'URI': u'http: //172.16.32.40: 8000/api/0.1/comm/710017/313011/',
u'transactionID': 313011,
u'complete_req': 1
},
{
u'control_sys': 710017,
u'complete': 1,
u'data': u'"{data arg}"',
u'URI': u'http: //172.16.32.40: 8000/api/0.1/comm/710017/313013/',
u'transactionID': 313013,
u'complete_req': 1
}
],
many=True):
control_sys = IntegerField(allow_null=True, label='Control system foreign key (passive)', max_value=2147483647, min_value=-2147483648, required=False)
meter = IntegerField(allow_null=True, label='Meter foreign key (passive)', max_value=2147483647, min_value=-2147483648, required=False)
data = CharField(allow_blank=True, allow_null=True, label='Comm data', max_length=200, required=False)
transactionID = IntegerField(label='Comms Transaction ID', max_value=9223372036854775807, min_value=-9223372036854775808, required=False)
source = IntegerField(label='Originating source for event', max_value=2147483647, min_value=-2147483648, required=False)
target = IntegerField(label='Target destination for event', max_value=2147483647, min_value=-2147483648, required=False)
priority = IntegerField(label='Comms priority', max_value=2147483647, min_value=-2147483648, required=False)
complete_req = IntegerField(read_only=False)
complete = IntegerField(read_only=False)
URI = ParameterisedHyperlinkedIdentityField(lookup_fields=(('control_sys', 'sysID'), ('transactionID', 'tID')), read_only=True, view_name='comms-detail')
系列化器:
class CommsSerialiser(serializers.HyperlinkedModelSerializer):
URI = ParameterisedHyperlinkedIdentityField(view_name="comms-detail", lookup_fields=(('control_sys', 'sysID'), ('transactionID', 'tID')), read_only=True)
# convert MySQL bool to int bool
complete_req = serializers.IntegerField(read_only=False)
complete = serializers.IntegerField(read_only=False)
class Meta:
model = CommsQueue
fields = ('control_sys', 'meter', 'data', 'transactionID', 'source', 'target', 'priority', 'complete_req', 'complete', 'URI')
validators = [
UniqueTogetherValidator(
queryset=CommsQueue.objects.all(),
fields=('control_sys', 'transactionID')
)
]
class CommsDetail(APIView):
"""
Retrieve, update or delete MULTIPLE comms from queue.
"""
# session permissions
permission_classes = (permissions.IsAuthenticated, IsAuthedCommQueue,)
def get_object(self, sysID, transactionID_list):
try:
# get comms queue for control unit ...allow retrieve of complete comms
comm_objects = CommsQueue.objects.filter(control_sys=sysID,transactionID__in=transactionID_list)
# Auth user for control unit
self.check_object_permissions(self.request, comm_objects[0])
# get object
return comm_objects
except ObjectDoesNotExist:
raise Http404
def get(self, request, sysID, format=None):
# build list of transaction ID to retrieve
transactionID_list = []
for transaction in request.data:
transactionID_list.append(transaction['transactionID'])
comms = self.get_object(sysID,transactionID_list)
serializer = CommsSerialiser(comms, context={'request': request}, many=True)
return Response(serializer.data)
def put(self, request, sysID, format=None):
# build list of transaction ID to retrieve
transactionID_list = []
for transaction in request.data:
transactionID_list.append(transaction['transactionID'])
print transaction
comms = self.get_object(sysID,transactionID_list)
serializer = CommsSerialiser(comms, data=request.data, context={'request': request}, many=True)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
查看:
class CommsSerialiser(serializers.HyperlinkedModelSerializer):
URI = ParameterisedHyperlinkedIdentityField(view_name="comms-detail", lookup_fields=(('control_sys', 'sysID'), ('transactionID', 'tID')), read_only=True)
# convert MySQL bool to int bool
complete_req = serializers.IntegerField(read_only=False)
complete = serializers.IntegerField(read_only=False)
class Meta:
model = CommsQueue
fields = ('control_sys', 'meter', 'data', 'transactionID', 'source', 'target', 'priority', 'complete_req', 'complete', 'URI')
validators = [
UniqueTogetherValidator(
queryset=CommsQueue.objects.all(),
fields=('control_sys', 'transactionID')
)
]
class CommsDetail(APIView):
"""
Retrieve, update or delete MULTIPLE comms from queue.
"""
# session permissions
permission_classes = (permissions.IsAuthenticated, IsAuthedCommQueue,)
def get_object(self, sysID, transactionID_list):
try:
# get comms queue for control unit ...allow retrieve of complete comms
comm_objects = CommsQueue.objects.filter(control_sys=sysID,transactionID__in=transactionID_list)
# Auth user for control unit
self.check_object_permissions(self.request, comm_objects[0])
# get object
return comm_objects
except ObjectDoesNotExist:
raise Http404
def get(self, request, sysID, format=None):
# build list of transaction ID to retrieve
transactionID_list = []
for transaction in request.data:
transactionID_list.append(transaction['transactionID'])
comms = self.get_object(sysID,transactionID_list)
serializer = CommsSerialiser(comms, context={'request': request}, many=True)
return Response(serializer.data)
def put(self, request, sysID, format=None):
# build list of transaction ID to retrieve
transactionID_list = []
for transaction in request.data:
transactionID_list.append(transaction['transactionID'])
print transaction
comms = self.get_object(sysID,transactionID_list)
serializer = CommsSerialiser(comms, data=request.data, context={'request': request}, many=True)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
“打印序列器”输出:
## Comms Queue
class CommsQueue(models.Model):
# primary key
# foreign key
control_sys = models.IntegerField("Control system foreign key (passive)", blank=True, null=True, default=None)
meter = models.IntegerField("Meter foreign key (passive)", blank=True, null=True, default=None)
# string
data = models.CharField("Comm data", max_length=200, blank=True, null=True, default=None)
# int
transactionID = models.BigIntegerField("Comms Transaction ID", blank=True, null=False)
source = models.IntegerField("Originating source for event", blank=True, null=False)
target = models.IntegerField("Target destination for event", blank=True, null=False, db_index=True)
priority = models.IntegerField("Comms priority", blank=True, default=0)
# url
URI = models.URLField("Comm URI",max_length=200, blank=True, null=True, default=None)
# bool
#comm_send = models.BooleanField("Event requires uplink/downlink", blank=False, default=True) # TODO delete?
comm_sent = models.BooleanField("Uplink/Downlink sent", blank=True, default=False)
complete_req = models.BooleanField("Require completion notice", blank=True, default=False)
complete = models.BooleanField("Event complete", blank=True, default=False)
# date
create_date = models.DateTimeField("Date created", auto_now=False, auto_now_add=True)
last_date = models.DateTimeField("Date accessed", auto_now=True, auto_now_add=False)
class Meta:
unique_together = (("control_sys","transactionID"),)
index_together = [("control_sys","transactionID"),]
def __unicode__(self):
return "Transaction ID: %s, Complete: %s" % (str(self.transactionID), str(self.complete))
CommsSerialiser(<QuerySet[
<CommsQueue: TransactionID: 313011,
Complete: False>,
<CommsQueue: TransactionID: 313013,
Complete: False>,
<CommsQueue: TransactionID: 313102,
Complete: False>
]>,
context={
u'request': <rest_framework.request.Requestobject>
},
data=[
{
u'control_sys': 710017,
u'complete': 1,
u'data': u'"{data innit}"',
u'URI': u'http: //172.16.32.40: 8000/api/0.1/comm/710017/313102/',
u'transactionID': 313102,
u'complete_req': 1
},
{
u'control_sys': 710017,
u'complete': 1,
u'data': u'"{data innit}"',
u'URI': u'http: //172.16.32.40: 8000/api/0.1/comm/710017/313011/',
u'transactionID': 313011,
u'complete_req': 1
},
{
u'control_sys': 710017,
u'complete': 1,
u'data': u'"{data arg}"',
u'URI': u'http: //172.16.32.40: 8000/api/0.1/comm/710017/313013/',
u'transactionID': 313013,
u'complete_req': 1
}
],
many=True):
control_sys = IntegerField(allow_null=True, label='Control system foreign key (passive)', max_value=2147483647, min_value=-2147483648, required=False)
meter = IntegerField(allow_null=True, label='Meter foreign key (passive)', max_value=2147483647, min_value=-2147483648, required=False)
data = CharField(allow_blank=True, allow_null=True, label='Comm data', max_length=200, required=False)
transactionID = IntegerField(label='Comms Transaction ID', max_value=9223372036854775807, min_value=-9223372036854775808, required=False)
source = IntegerField(label='Originating source for event', max_value=2147483647, min_value=-2147483648, required=False)
target = IntegerField(label='Target destination for event', max_value=2147483647, min_value=-2147483648, required=False)
priority = IntegerField(label='Comms priority', max_value=2147483647, min_value=-2147483648, required=False)
complete_req = IntegerField(read_only=False)
complete = IntegerField(read_only=False)
URI = ParameterisedHyperlinkedIdentityField(lookup_fields=(('control_sys', 'sysID'), ('transactionID', 'tID')), read_only=True, view_name='comms-detail')
CommsSerialiser(,
上下文={
你的‘请求’:
},
资料=[
{
控制系统:710017,
u'complete':1,
u'data':u'{data innit}',
u'URI':u'http://172.16.32.40:8000/api/0.1/comm/710017/313102/,
u'transactionID':313102,
完整的需求:1
},
{
控制系统:710017,
u'complete':1,
u'data':u'{data innit}',
u'URI':u'http://172.16.32.40:8000/api/0.1/comm/710017/313011/,
u'transactionID':313011,
完整的需求:1
},
{
控制系统:710017,
u'complete':1,
u'data':u'{data arg}',
u'URI':u'http://172.16.32.40:8000/api/0.1/comm/710017/313013/,
u'transactionID':313013,
完整的需求:1
}
],
多=真):
control\u sys=IntegerField(allow\u null=True,label='control system foreign key(被动)',最大值=2147483647,最小值=-2147483648,必选值=False)
meter=IntegerField(allow_null=True,label='meter外键(被动)',max_值=2147483647,min_值=-2147483648,required=False)
data=CharField(allow_blank=True,allow_null=True,label='Comm data',max_length=200,required=False)
transactionID=IntegerField(label='Comms Transaction ID',max_值=9223372036854775807,min_值=-9223372036854775808,必需=False)
source=IntegerField(label='origing source for event',max_value=2147483647,min_value=-2147483648,required=False)
target=IntegerField(label='target destination for event',max_value=2147483647,min_value=-2147483648,required=False)
优先级=整数字段(label='Comms priority',max_值=2147483647,min_值=-2147483648,必选=False)
完成请求=整数字段(只读=假)
完成=整数字段(只读=假)
URI=ParameterizedHyperlinkedEntityField(查找字段=('control\u sys','sysID'),('transactionID','tID')),只读=True,查看\u name='comms-detail')
错误会告诉您出了什么问题。事实上,queryset没有pk;只有queryset的成员才会这样。嗨@DanielRoseman,是的,这很有道理。我不明白的是,为什么在这种情况下,它会得到一个查询集。我向serlialiser传递了一个查询集,其中记录了many=True。因此,我认为它应该期待一个queryset而不是一个单一的模型实例,并且应该基于此对其进行验证?仍然没有实现这一点。现在看一下serialiser上的自定义验证或Django REST框架的使用