如何使用Django RF从一个端点创建多个模型

pdkcd3nj  于 2023-03-20  发布在  Go
关注(0)|答案(3)|浏览(96)

我想有一个单一的端点,接受POST请求,并创建一个“订单”,可以是两种类型之一。用户应该能够提交一个订单(任何类型)作为JSON,并创建一个新的订单。
在后台,创建了两个模型。一个是“基本订单”模型,用于描述一些常见特征;另一个是“A类订单”或“B类订单”,用于描述该订单的特定特征。实际的订单类型及其字段要复杂得多,因此这里仅描述为A和B以及一些字符字段。
但是一般的想法是使用同一个端点创建两个模型,一个是BaseOrder模型,另一个是由提交的order_type字段确定的类型的模型。
我认为条件部分(确定顺序)应该不会太难,但是我不确定如何从同一个端点创建两个独立的模型,即使它总是同一类型。
型号:

class BaseOrder(models.Model):
    name = models.CharField(max_length=80)
    timestamp = models.DateTimeField(null=False)

    class OrderType(models.TextChoices):
        TYPEA = "A", "Placeholder A"
        TYPEB = "B", "Placeholder B"

    order_type = models.CharField(
        max_length=16,
        verbose_name="Order Type",
        choices=OrderType.choices,
    )

class TypeAOrder(models.Model):
    a_field1 = models.CharField(max_length=80)
    a_field2 = models.CharField(max_length=80)
    a_field3 = models.CharField(max_length=80)

class TypeBOrder(models.Model):
    b_field1 = models.CharField(max_length=80)
    b_field2 = models.CharField(max_length=80)

对包含类型A订单的/order端点的POST请求可能如下所示:

{
  "name": "test order",
  "timestamp": "2022-08-01T12:32:10Z",
  "ordertype": "A"
  "a_field1": "important"
  "a_field2": "data"
  "a_field3": "something"
},

这样做会创建两个独立的模型,BaseOrder模型和TypeAOrder模型。
我发现this library似乎可以在GET请求中组合模型,但似乎不能创建模型。

ffx8fchx

ffx8fchx1#

在视图中使用if/else条件
1.始终创建基础模型
1.检查if/else条件中的ordertype并相应地创建子模型。
此外,在“基础”模型和子模型之间建立一对一关系。

m1m5dgzv

m1m5dgzv2#

假设您正在使用django-rest-framework for REST API,您可以通过类似下面的方式来实现这一点。
1.序列化程序,用于验证类型A和B模型数据。

class TypeASerializer(serializers.ModelSerializer):
    class Meta:
        model = TypeAOrder
        fields = ['a_field1', 'a_field2', 'a_field3']

class TypeBSerializer(serializers.ModelSerializer):
    class Meta:
        model = TypeBOrder
        fields = ['b_field1', 'b_field2']

1.具有自定义逻辑的BaseOrder序列化器

class BaseOrderSerializer(serializers.ModelSerializer):
    type_a_order = TypeASerializer(required=False)
    type_b_order = TypeBSerializer(required=False)

    class Meta:
        model = BaseOrder
        fields = ['name', 'timestamp', 'order_type', 'type_a_order', 'type_b_order']

    def create(self, validated_data):
        order_type = validated_data.pop('order_type')
        type_a_data = validated_data.pop('type_a_order', {})
        type_b_data = validated_data.pop('type_b_order', {})
        base_order = BaseOrder.objects.create(order_type=order_type, **validated_data)

        if order_type == BaseOrder.OrderType.TYPEA:
            TypeAOrder.objects.create(base_order=base_order, **type_a_data)
        elif order_type == BaseOrder.OrderType.TYPEB:
            TypeBOrder.objects.create(base_order=base_order, **type_b_data)

        return base_order

1.定义将使用基顺序序列化程序的视图
CreateAPIView将处理def create(....)部分。

class OrderView(generics.CreateAPIView):
    queryset = BaseOrder.objects.all()
    serializer_class = BaseOrderSerializer

1.注册API视图

from django.urls import path
from .views import OrderView

urlpatterns = [
    path('order/', OrderView.as_view(), name='create_order'),
]

1.添加测试用例

from rest_framework import status
from rest_framework.test import APITestCase
from django.urls import reverse
from datetime import datetime
import pytz

class OrderViewTestCase(APITestCase):
    def test_create_order_type_a(self):
        url = reverse('create_order')
        data = {
            "name": "test order",
            "timestamp": "2022-08-01T12:32:10Z",
            "order_type": "A",
            "type_a_order": {
                "a_field1": "important",
                "a_field2": "data",
                "a_field3": "something"
            }
        }
        response = self.client.post(url, data, format='json')
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        self.assertEqual(response.data['name'], data['name'])
        self.assertEqual(response.data['timestamp'], data['timestamp'])
        self.assertEqual(response.data['order_type'], data['order_type'])
        self.assertEqual(response.data['type_a_order']['a_field1'], data['type_a_order']['a_field1'])
        self.assertEqual(response.data['type_a_order']['a_field2'], data['type_a_order']['a_field2'])
        self.assertEqual(response.data['type_a_order']['a_field3'], data['type_a_order']['a_field3'])

    def test_create_order_type_b(self):
        url = reverse('create_order')
        data = {
            "name": "test order",
            "timestamp": "2022-08-01T12:32:10Z",
            "order_type": "B",
            "type_b_order": {
                "b_field1": "important",
                "b_field2": "data"
            }
        }
        response = self.client.post(url, data, format='json')
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        self.assertEqual(response.data['name'], data['name'])
        self.assertEqual(response.data['timestamp'], data['timestamp'])
        self.assertEqual(response.data['order_type'], data['order_type'])
        self.assertEqual(response.data['type_b_order']['b_field1'], data['type_b_order']['b_field1'])
        self.assertEqual(response.data['type_b_order']['b_field2'], data['type_b_order']['b_field2'])

    def test_create_order_invalid_payload(self):
        url = reverse('create_order')
        data = {
            "name": "test order",
            "timestamp": "2022-08-01T12:32:10Z",
            "order_type": "C",  # Invalid order type
            "type_b_order": {
                "b_field1": "important",
                "b_field2": "data"
            }
        }
        response = self.client.post(url, data, format='json')
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

更多参考

kiayqfof

kiayqfof3#

还有其他的实现方法,但是,使用ModelSerializerAPIView的一个简单的例子:
serializers.py

class BaseOrderSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.BaseOrder
        fields = ['name', 'timestamp', 'order_type']

class TypeAOrderSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.TypeAOrder
        fields = ['a_field1', 'a_field2', 'a_field3']

class TypeBOrderSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.TypeBOrder
        fields = ['b_field1', 'b_field2']

views.py

class OrderAPIView(APIView):
    def post(self, request):
        base_order = BaseOrderSerializer(data=request.data)
        base_order.is_valid(raise_exception=True)

        if base_order.validated_data['order_type'] == 'A':
            serializer = TypeAOrderSerializer(data=request.data)
            serializer.is_valid(raise_exception=True)
            serializer.save()

        elif base_order.validated_data['order_type'] == 'B':
            serializer = TypeBOrderSerializer(data=request.data)
            serializer.is_valid(raise_exception=True)
            serializer.save()

        base_order.save()
        return Response(serializer.data)

相关问题