Django REST框架:验证Serialiser列表更新(PUT),两个字段上没有pk和唯一索引

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) (不工

我花了几天的时间在这方面,并在房子周围阅读(我有好几次rtfm…也许我还不了解tfm)。接近一些答案,我担心最终问题在于我对Django/Serilizers(sic)如何工作的了解

我将从我的基本问题开始,让事情变得简单,而不是我为使其工作所做的任何尝试

我正在尝试执行以下操作:

  • 工作)从Django rest_框架API获取值列表 基于双索引,其中一个字段在URL中传递 (control_sys)并传入第二个字段的多个值 (JSON)提交给API的数据(transactionID)
  • 不工作)基于相同的值更新(放置)值列表 逻辑为GET(如上)
  • 还没有到这一步)创建(发布)基于 与GET相同的逻辑(如上)
  • 如图所示,GET语句正在工作。视图正在根据在URL中传递的TransactionID列表和控件sys(sysID)检索查询集。它将此消息传递给serialiser,并通过API返回数据

    更新(PUT)不工作。我的问题似乎是,我没有将模型的pk(id字段)传递给API,并且它在发布到API的数据中不可用。相反,我需要以与GET语句相同的方式检索查询集,并将其传递给更新,在尝试验证seriliser时,会出现以下错误:

    AttributeError:'QuerySet'对象没有属性'pk'

    验证器在的第155行上提出的

    我很困惑,因为我已经检查过了,queryset中的每个项目都有一个值id(当我引用pk时返回)。我还尝试更新视图中的数据以附加pk/id值,但没有效果

    我正在传递'many=True',以便seriliser知道它正在接收的是查询集,而不是单个模型实例

    迄今为止,我已尝试:

  • 将id和pk追加到request.data
  • 使用required=True/False和read_only=True/False将id和pk显式添加到seriliser的各种尝试
  • 子类化ListSerializer并使用META:list_serializer_类控制Serialiser的工作方式
  • 我知道验证失败了,但我不知道如何解决这个问题

    欢迎提出任何建议

    下面是一些参考信息。。。我会根据要求发布更多

    型号:

     ## 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框架的使用