Python Django Rest框架:动态更新/创建多个对象,而不提供pk
我只是偶然发现了Django Rest框架遇到的最难的问题。让我先给你我的模型,然后解释: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
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已满。
我需要编写执行以下操作的视图:
[
{
"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)
但我对该代码有两个问题:
stamp.save()
)对于api来说是非常不安全的。我无法让它先序列化数据。我的问题是:这样的观点行吗?或者我能改进什么?例如,它不使用基于类的泛型,但我不知道如何在这里使用它们.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)