如何在 Django Rest Framework 的一个视图中创建/更新/检索多个模型

问题描述 投票:0回答:1

我有一个商业模型和订单模型。企业可以在我们的网站上订购家具。用户创建帐户并下订单。由于他是新用户,因此与任何企业没有关联。在订单中,他会提供有关他的业务的信息以及与当前订单相关的一些信息。将使用给定信息创建新的业务记录和订单记录。订单表中的业务有一个外键。

如果他想创建第二个订单,因为他已经有一家企业,他将在表格中预先填写企业信息。当他给出订单数据并提交时,后端不会创建新的业务记录。它仅创建订单记录并存储业务参考。

如何在单个端点中实现此目的以创建更新和检索?


# models.py

class Order(models.Model):
    applicant = models.ForeignKey(User, on_delete=models.DO_NOTHING, related_name='Applicant', blank=True, null=True)
    business = models.ForeignKey(Business, on_delete=models.DO_NOTHING, related_name='Business', blank=True, null=True)
    code = models.CharField(verbose_name='Order Code', max_length=100, blank=True, null=True)
    chairs = models.IntegerField(verbose_name='Chairs', blank=True, null=True)
    tables = models.IntegerField(verbose_name='Tables', blank=True, null=True)
    delivery_type = models.CharField(verbose_name='Delivery Type', max_length=100, blank=True, null=True)
    payment_type = models.CharField(verbose_name='Payment Type', max_length=100, blank=True, null=True)

    STATUS_CHOICES = (
        ('CREATED', 'Created'),
        ('IN_PROGRESS', 'In Progress'),
        ('CANCELLED', 'Cancelled'),
        ('SHIPPED', 'Shipped'),
    )
    status = models.CharField(max_length=20, choices=STATUS_CHOICES, blank=True, null=True, default='CREATED')


class Business(models.Model):

    name = models.CharField(verbose_name='Legal Name', max_length=100, blank=True, null=True)
    code = models.CharField(verbose_name='Business Code', max_length=100, blank=True, null=True)
    website = models.CharField(verbose_name='Website URL', max_length=100, blank=True, null=True)
    address = models.TextField(verbose_name="Street Address 1", blank=True, null=True)
    city = models.CharField(verbose_name='City', max_length=250, blank=True, null=True)
    state = models.CharField(verbose_name='State', max_length=200, blank=True, null=True)
    country = models.CharField(verbose_name='Country', max_length=200, blank=True, null=True)



# serializers.py

import time



class BusinessSerializer(serializers.ModelSerializer):
    class Meta:
        model = Business
        fields = '__all__'
        
    def create(self, validated_data):
        timestamp = int(time.time())
        random_number = random.randint(100,999)
        validated_data['code'] = f'BUSINESS-{timestamp}'
        validated_data['status'] = 'CREATED'
        return super().create(validated_data)

class OrderSerializer(serializers.ModelSerializer):
    class Meta:
        model = Order
        fields = '__all__'
        
    def create(self, validated_data):
        timestamp = int(time.time())
        random_number = random.randint(100,999)
        validated_data['code'] = f'ORDER-{timestamp}'
        validated_data['status'] = 'CREATED'
        return super().create(validated_data)

# views.py

class BusinessOrderAPIView(generics.CreateAPIView):
    permission_classes = [IsAuthenticated]
    queryset = Order.objects.all()
    serializer_class = OrderSerializer

    def perform_create(self, serializer):

        business_data = self.request.data.get('business', {})
        business_id = business.get('id')
        if business_id:
            try:
                business = Business.objects.get(pk=business_id)
            except Business.DoesNotExist:
                business = Business.objects.create()
            business.name = business_data.get('name')
            business.website = business_data.get('website')
            business.address = business_data.get('address')
            business.city = business_data.get('city')
            business.state = business_data.get('state')
            business.country = business_data.get('country')
            business.save()

            order = serializer.save(business=business.pk)

这就是我的请求的样子

{
    
    "chairs": 3,
    "tables": 1,
    "delivery_type": "ONE_DAY",
    "payment_type": "CASH_ON_DELIVERY",
    "business": {
        "name": "Vin.AI",
        "website": "https://lol.com",
        "address": "My street",
        "city": "Gotham City",
        "state": "New York",
        "country": "USA",
    }
}

这是我收到的回复

{
    "business": [
        "Incorrect type. Expected pk value, received dict."
    ]
}
django django-rest-framework django-views django-rest-viewsets
1个回答
0
投票

问题很简单。您的序列化程序期望

business
字段作为 PK,而不是您在有效负载中发送的字典。然而,为了执行所需的操作,一些工作是必要的。另外,模型也有点奇怪,但我不会深入讨论。

目前,

Business
模型没有可以将
User
与其关联的字段。这意味着,您会知道谁制造了
Order
,但不知道是谁创造了
Business

根据你所说的,我认为一个

Business
属于一个
User
并且只有一个。 (当然,您可以通过一对多关系轻松修改它)。

因此,从对模型进行小修改开始,从

applicant
中删除
Order
并添加到
Business
(我猜是所有者):

class Business(models.Model):
    applicant = models.OneToOneField(
        User,
        on_delete=models.DO_NOTHING,
        primary_key=True
    )
    ...

另外,

BusinessSerializer
上有一个小错误,没有名为
status
的字段,删除该行:

class BusinessSerializer(serializers.ModelSerializer):
    class Meta:
        ...

    def create(self, validated_data):
        ...
        # validated_data["status"] = "CREATED"
        return super().create(validated_data)

解决这个问题的方法不止一种。但为了简单起见:

  1. 检查当前
    User
    是否有
    Business
  2. 如果没有,我们根据有效负载数据创建一个
class BusinessOrderAPIView(generics.CreateAPIView):
    permission_classes = [permissions.IsAuthenticated]
    queryset = Order.objects.all()
    serializer_class = OrderSerializer
    business_serializer = BusinessSerializer

    def create(self, request, *args, **kwargs):
        user_business = None
        try:
            user_business = request.user.business

        except ObjectDoesNotExist:
            business = request.data.pop("business")
            business["applicant"] = request.user.pk
            business_serializer = self.business_serializer(data=business)
            business_serializer.is_valid(raise_exception=True)
            user_business = business_serializer.save()

        request.data["business"] = user_business.pk
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        self.perform_create(serializer)
        headers = self.get_success_headers(serializer.data)
        return Response(
            serializer.data, status=status.HTTP_201_CREATED, headers=headers
        )

您可以通过多种形式修改此代码。如果您想保留原始格式,只需使用

try/except
来查询给定一些唯一标识符(例如
Business
name
)的
website

© www.soinside.com 2019 - 2024. All rights reserved.