Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/django/19.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框架:动态更新/创建多个对象,而不提供pk_Python_Django_Django Rest Framework_Django Views_Django Rest Viewsets - Fatal编程技术网

Python Django Rest框架:动态更新/创建多个对象,而不提供pk

Python Django Rest框架:动态更新/创建多个对象,而不提供pk,python,django,django-rest-framework,django-views,django-rest-viewsets,Python,Django,Django Rest Framework,Django Views,Django Rest Viewsets,我只是偶然发现了Django Rest框架遇到的最难的问题。让我先给你我的模型,然后解释: class Stampcardformat(models.Model): workunit = models.ForeignKey( Workunit, on_delete=models.CASCADE ) uuid = models.UUIDField( default=uuid.uuid4, e

我只是偶然发现了Django Rest框架遇到的最难的问题。让我先给你我的模型,然后解释:

class Stampcardformat(models.Model):
    workunit    = models.ForeignKey(
        Workunit,
        on_delete=models.CASCADE
    )
    uuid        = models.UUIDField(
        default=uuid.uuid4,
        editable=False,
        unique=True
    )
    limit       = models.PositiveSmallIntegerField(
        default=10
    )
    category    = models.CharField(
        max_length=255
    )


class Stampcard(models.Model):
    stampcardformat = models.ForeignKey(
        Stampcardformat,
        on_delete=models.CASCADE
    )
    user        = models.ForeignKey(
        User,
        on_delete=models.CASCADE
    )
    uuid        = models.UUIDField(
        default=uuid.uuid4,
        editable=False,
        unique=True
    )


class Stamp(models.Model):
    stampcardformat = models.ForeignKey(
        Stampcardformat,
        on_delete=models.CASCADE
    )
    stampcard = models.ForeignKey(
        Stampcard,
        on_delete=models.CASCADE,
        blank=True,
        null=True
    )
    uuid        = models.UUIDField(
        default=uuid.uuid4,
        editable=False,
        unique=True
    )
这些模型描述了一个简单的stampcard模型。如果一张stampcard通过foreignkey关联的邮票数量与stampcard格式的限制数量相同,则认为该stampcard已满。 我需要编写执行以下操作的视图:

  • 该视图包含一个邮票列表(见下文),其中包括 uuid's
  • 然后,它需要为每个给定的文件找到正确的stampcardformat 邮票
  • 接下来需要检查请求用户是否有stampcard 使用相应的stampcardformat

    a) 如果有,则需要检查stampcard是否已满

    i) 如果已满,则需要创建给定格式的新stampcard 并将stampcard foreignkey更新为已创建的stampcard

    ii)如果未满,则需要更新邮票stampcard foreignkey 给找到的stampcard

    b) 如果用户尚未获得给定用户的stampcard stampcardformat,它需要创建新的stampcard并更新 stampcard创建的stampcard的外键

  • 以下是邮票的请求正文列表:

    [
        {
            "stamp_uuid": "62c4070f-926a-41dd-a5b1-1ddc2afc01b2"
        },
        {
            "stamp_uuid": "4ad6513f-5171-4684-8377-1b00de4d6c87"
        },
        ...
    ]
    
    基于类的视图似乎不支持这种行为。我试图修改基于类的视图,但没有效果。除了很多点之外,我还失败了,因为视图抛出了错误:

    AssertionError: Expected view StampUpdate to be called with a URL keyword argument named "pk". Fix your URL conf, or set the `.lookup_field` attribute on the view correctly.
    
    编辑 对于其他上下文:我需要的url是没有pk,slug或任何东西。 所以url应该是这样的:

    /api/stampcards/stamps/ 
    
    并对其执行put(或任何具有主体且有效的请求)。 我写的路线是:

    url(r'^stamps/$', StampUpdate.as_view(), name='stamp-api-update'),
    
    编辑: 巨大的更新。所以我设法拼凑出一个可行的观点。 首先,我更新了stampcard模型,如下所示(我添加了一个新字段“完成”,以跟踪是否已满):

    然后我写了这样的观点:

    class StampUpdate(APIView):
        permission_classes = (IsAuthenticated,)
    
        def get_object(self, uuid):
            try:
                return Stamp.objects.get(uuid=uuid)
            except Stamp.DoesNotExist():
                raise Http404
    
        def put(self, request, format=None):
        for stamp_data in request.data:
            stamp = self.get_object(stamp_data['stamp_uuid'])
            if stamp.stampcard==None:
                user_stampcard = self.request.user.stampcard_set.exclude(done=True).filter(stampcardformat=stamp.stampcardformat)
                if user_stampcard.exists():
                    earliest_stampcard = user_stampcard.earliest('timestamp')
                    stamp.stampcard = earliest_stampcard
                    stamp.save()
                    if earliest_stampcard.stamp_set.count() == earliest_stampcard.stampcardformat.limit:
                        earliest_stampcard.done=True
                        earliest_stampcard.save()
                else:
                    new_stampcard = Stampcard(stampcardformat=stamp.stampcardformat, user=self.request.user)
                    new_stampcard.save()
                    stamp.stampcard = new_stampcard
                    stamp.save()
        new_stampcards = Stampcard.objects.exclude(done=True).filter(user=self.request.user)
        last_full_stampcard = Stampcard.objects.filter(user=self.request.user).filter(done=True)
        if last_full_stampcard.exists():
            last_full_stampcard_uuid=last_full_stampcard.latest('updated').uuid
            last_full_stampcard = Stampcard.objects.filter(uuid=last_full_stampcard_uuid)
            stampcards = new_stampcards | last_full_stampcard
        else:
            stampcards = new_stampcards
        print(stampcards)
        stampcard_serializer = StampcardSerializer(stampcards, many=True)
        return Response(stampcard_serializer.data)
    
    但我对该代码有两个问题:

  • 我的直觉告诉我,模型实例上调用save()的部分(例如,
    stamp.save()
    )对于api来说是非常不安全的。我无法让它先序列化数据。我的问题是:这样的观点行吗?或者我能改进什么?例如,它不使用基于类的泛型,但我不知道如何在这里使用它们
  • 如果用这种方法填好的话,我也很乐意把邮票卡还给你。但我还想排除所有不相关的StampCard,这就是我调用
    .exclude(done=True)
    的原因。一张不幸被填满的卡片已经完成了=尽管如此!如何将流程中填写的stampcards添加到返回值

  • 我不认为在PUT方法中使用
    stamp.save()
    是不安全的,因为根据定义,它假定更改对象的值

    为了只返回相关的stampcard,您可以将stampcard添加到这样的集合中

    class StampUpdateView(APIView):
        def get_object(self, uuid):
            try:
                return Stamp.objects.get(uuid=uuid)
            except Stamp.DoesNotExist():
                raise Http404
    
        def put(self, request, *args, **kwargs):
            stampcard_set = set()
            for stamp_data in request.data:
                stamp = self.get_object(stamp_data['stamp_uuid'])
    
                user_stampcard = request.user.stampcard_set.exclude(done=True).filter(stampcardformat=stamp.stampcardformat)
                if user_stampcard.exists():
                    stampcard = user_stampcard.earliest('timestamp')
                else:
                    stampcard = Stampcard(stampcardformat=stamp.stampcardformat, user=request.user)
                    stampcard.save()
    
                stamp.stampcard = stampcard
                stamp.save()
    
                if stampcard.stamp_set.count() == stampcard.stampcardformat.limit:
                    stampcard.done = True
                    stampcard.save()
    
                stampcard_set.add(stampcard)
    
            stampcard_serializer = StampcardSerializer(stampcard_set, many=True)
            return Response(stampcard_serializer.data)
    
    这样一来,是否已经归还了冲压件就无关紧要了


    还要注意的是,我在保存戳记时将代码中的限制检查行向下移动,因为如果限制设置为1,则必须在添加戳记后立即将stampcard设置为完成。

    感谢您的改进!我会尽快试一试。谢谢你向我保证,打电话给stampcard.save()确实没问题!
    class StampUpdateView(APIView):
        def get_object(self, uuid):
            try:
                return Stamp.objects.get(uuid=uuid)
            except Stamp.DoesNotExist():
                raise Http404
    
        def put(self, request, *args, **kwargs):
            stampcard_set = set()
            for stamp_data in request.data:
                stamp = self.get_object(stamp_data['stamp_uuid'])
    
                user_stampcard = request.user.stampcard_set.exclude(done=True).filter(stampcardformat=stamp.stampcardformat)
                if user_stampcard.exists():
                    stampcard = user_stampcard.earliest('timestamp')
                else:
                    stampcard = Stampcard(stampcardformat=stamp.stampcardformat, user=request.user)
                    stampcard.save()
    
                stamp.stampcard = stampcard
                stamp.save()
    
                if stampcard.stamp_set.count() == stampcard.stampcardformat.limit:
                    stampcard.done = True
                    stampcard.save()
    
                stampcard_set.add(stampcard)
    
            stampcard_serializer = StampcardSerializer(stampcard_set, many=True)
            return Response(stampcard_serializer.data)