在Django DRFs的`ListCreateAPIView` POST方法中,我们如何获得模型字段的pk?

时间:2018-06-18 12:14:25

标签: django django-rest-framework django-class-based-views

我有一个简单的ModelSerializer,如下所示:

class DBaaSOrderSerializer(serializers.ModelSerializer):
    class Meta:
        model = DBaaSOrder
        fields = '__all__'

以上还有一些validate方法与此问题无关。

现在,我在基于类的视图中使用上面的序列化程序,如下所示:

class DBaaSOrderView(generics.ListCreateAPIView):
    serializer_class = DBaaSOrderSerializer
    permission_classes = (permissions.IsAuthenticated,)

    def get_queryset(self):
        usd = UsdDBActions()
        orders = DBaaSOrder.objects.filter(user=self.request.user).order_by('updated_at')

        for change_ref, change_status, updated_at in orders.values_list('change_ref', 'change_status', 'updated_at'):
            usd_change_status = usd.get_rfc_status(change_ref)
            usd_change_updated_at = usd.get_last_mod_date(change_ref)

            if change_status != usd_change_status:
                orders.filter(change_ref=change_ref).update(change_status=usd_change_status)

            if updated_at != usd_change_updated_at:
                orders.filter(change_ref=change_ref).update(updated_at=usd_change_updated_at)

        return orders.filter(change_status__in=VALID_USD_STATUSES)[:MAX_ORDERS]

    @staticmethod
    def get_dns(value):
        dns_records = DNS.objects.all()
        for dns in dns_records:
            if dns.server in value and dns.domain in value:
                return dns

    @staticmethod
    def get_backup_plan(value):
        backup_plans = BackupPlan.objects.all()
        for backup_plan in backup_plans:
            if backup_plan.customer_policy_name in value and backup_plan.retention in value:
                return backup_plan

    def post(self, request, *args, **kwargs):
        data = request.data
        data['user'] = request.user.pk

        dns_record = self.get_dns(data['dns'])
        backup_plan = self.get_backup_plan(data['backup'])

        dns_record_pk = dns_record.pk
        backup_plan_pk = backup_plan.pk

        data['dns'] = dns_record_pk
        data['backup'] = backup_plan_pk

        serializer = DBaaSOrderSerializer(data=data)
        if serializer.is_valid():
            usd = UsdDBActions()
            data = request.data

            usd_data = {
                'organization': int(data['organization_pk']),
                'category': 'SSC.DBM.DB.ADD',
                'assignee': request.user.username,
            }

            response = usd.create_rfc(usd_data)

            try:
                result = response.json()

                if result['code'] == 200:
                    change_ref = int(response.json()['reference_number'])

                    data['user'] = request.user
                    data['change_ref'] = int(response.json()['reference_number'])
                    data['change_status'] = usd.get_rfc_status(change_ref)
                    data['dns'] = dns_record
                    data['backup'] = backup_plan

                    DBaaSOrder.objects.create(**data)

                    return Response({
                        'message': f"The RFC {data['change_ref']} has been successfully created!",
                        'code': 200
                    })

一切都按预期工作但我不喜欢的是我有2个方法get_dns()get_backup_plan()来获取dns或{{的实际模型对象1}}字段。有没有更简单的方法来做到这一点?

这样做的原因是:

  • 此处,backupserializer = DBaaSOrderSerializer(data=data)应包含该字段的data;
  • 此处,pkDBaaSOrder.objects.create(**data)应包含模型字段的实例;

更多,datadns是外键:

backup

主要模型如下:

class DNS(models.Model):
    server = models.CharField(max_length=64)
    domain = models.CharField(max_length=64)

    def __str__(self):
        return f'{self.server} - {self.domain}'


class BackupPlan(models.Model):
    customer_policy_name = models.CharField(max_length=64)
    retention = models.CharField(max_length=64)

    def __str__(self):
        return f'{self.customer_policy_name} - {self.retention}'

1 个答案:

答案 0 :(得分:1)

这里有两个相关的问题。首先是你把逻辑转向" 192.168.0.1 - test.domain.com"进入DNS的一个实例。其次是你如何进行数据库查找。

这种东西总是属于序列化器;这是负责将接收的数据转换为正确格式的代码。该特定逻辑属于验证方法;这些名称为validate_<fieldname>,因此我们需要validate_dnsvalidate_backup

目前进行数据库查找的方式效率很低。我们可以通过拆分输入然后使用该数据进行直接数据库查询来更简单地完成它。

为了完成所有这些工作,我们需要覆盖这些字段的定义以使它们成为CharFields,以便它们接受任意数据。然后,validate方法将把它们转换为实际的模型实例。

所以:

class DBaaSOrderSerializer(serializers.ModelSerializer):

    dns = serializers.CharField()
    backup = serializers.CharField()

    class Meta:
        model = DBaaSOrder
        fields = '__all__'

    def validate_dns(self, value):
        try:
            server, domain = value.split(' - ')
        except ValueError:
            raise serializers.ValidationError('not in correct format')
        try:
            instance = DNS.objects.get(server=server, domain=domain)
        except DNS.DoesNotExist:
            raise serializers.ValidationError('no matching DNS')
        return instance

    def validate_backup(self, value):
        ... similar to above...

现在你可以摆脱post中的自定义逻辑。