DRF在接收请求时检查数据库中是否已存在对象

时间:2018-03-06 15:40:09

标签: django django-rest-framework

我有按名称和位置定义的产品。每个产品都有一对唯一的名称/位置。

我正在编写一个能够创建产品的视图,我想首先检查它是否存在于DB中。 如果是,那么将ID保留在某处以将其返回到我的前端应用程序。 如果否,则创建它并获取ID。

根据我的研究,覆盖perform_create方法应该是解决方案,但我无法弄清楚如何。

任何帮助都将不胜感激。

urls.py

from django.conf.urls import url
from main.views import product_view

urlpatterns = [
    url(r'^products/$', product_view.ProductCreate.as_view()),
    url(r'^products/(?P<pk>[0-9]+)/$', product_view.ProductDetail.as_view()),
]

product_view.py

from rest_framework import generics
from rest_framework import permissions

from main.models import Product
from main.serializers import ProductSerializer


class ProductCreate(generics.CreateAPIView):
    """
    Create a new product.
    """

    permission_classes = (permissions.IsAuthenticated,)

    serializer_class = ProductSerializer
    queryset = Product.objects.all()

    def perform_create(self, serializer):
    if serializer.is_valid():
        product_name = serializer.validated_data['product_name']
        product_location = serializer.validated_data['product_location']

        if product_name != '':
            product_list = Product.objects.filter(
                product_name=product_name, product_location=product_location)

            if not product_list:
                product = create_product(product_name, product_location)
            else:
                product = product_list[0]

            serializer = ProductSerializer(product)
            return Response(serializer.data)
        else:
            return Response(data={'message': 'Empty product_name'}, status=status.HTTP_400_BAD_REQUEST)
    else:
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


class ProductDetail(generics.RetrieveUpdateAPIView):
    """
    Retrieve, update or delete a product.
    """

    permission_classes = (permissions.IsAuthenticated,)

    serializer_class = ProductSerializer
    queryset = Product.objects.all()

serializer.py

from django.contrib.auth.models import User
from rest_framework import serializers
from main.models import Product


class ProductSerializer(serializers.ModelSerializer):

    class Meta:
        model = Product
        fields = ('id',
              'product_name',
              'product_shop',
              'product_url',
              'product_img',
              'product_location')

修改

产品型号:

class Product(models.Model):
    product_name = models.CharField(max_length=200, blank=True)
    product_shop = models.CharField(max_length=200, blank=True)
    product_url = models.CharField(max_length=400, blank=False)
    product_img = models.CharField(max_length=400, blank=True)
    product_location = models.CharField(max_length=200, blank=False)
    product_creation_date = models.DateTimeField(default=datetime.now, blank=True)
    productgroup = models.ForeignKey(ProductGroup, blank=True, null=True, on_delete=models.CASCADE)

    def __str__(self):
        return '#' + str(self.pk) + ' ' + self.product_name + ' (' + self.product_shop + ')'

根据产品名称和位置自动创建产品。一个特定的功能是处理创建和履行数据。

我在前端应用中获得的结果是使用此代码丢失了一些数据。 以下是使用httpie:

的示例
  • 请求:http POST http://127.0.0.1:8000/products/ product_name =&#34;产品测试&#34; product_location =&#34; LOC1&#34; product_img =&#34; www.myimg.com&#34;

  • 结果: HTTP / 1.0 201已创建 允许:POST,OPTIONS 内容长度:247 Content-Type:application / json 日期:2018年3月8日星期四,格林威治标准时间13:58:18 服务器:WSGIServer / 0.2 CPython / 3.5.3 变化:接受 X-Frame-Options:SAMEORIGIN

{     &#34; product_location&#34;:&#34; Loc1&#34;,     &#34; product_name&#34;:&#34;产品测试&#34;,     &#34; product_img&#34;:&#34; www.myimg.com&#34; }

在DB中,产品存在且具有product_shop和product_url的值,当然还有ID。

编辑2

我做了一些测试并记录了尽可能多的东西。

这是我的perform_create函数和记录器的结果:

def perform_create(self, serializer):
        if serializer.is_valid():
            product_name = serializer.validated_data['product_name']
            product_location = serializer.validated_data['product_location']

            if product_name != '':
                product_list = Product.objects.filter(
                    product_name=product_name, product_location=product_location)

                if not product_list:
                    product = create_product(product_name, product_location)
                else:
                    product = product_list[0]

                logger.info('product id : ' + str(product.id)) # Generated automatically
                logger.info('product name : ' + product.product_name) # From the request
                logger.info('product url : ' + product.product_url) # Generated by my create_product function

                serializer = ProductSerializer(product)

                logger.info('serializer.data['id'] : ' + str(serializer.data['id']))
                return Response(serializer.data)
            else:
                return Response(data={'message': 'Empty product_name'}, status=status.HTTP_400_BAD_REQUEST)
        else:
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

以下是结果,它们很好:

产品编号:3713

产品名称:产品1

产品网址:/ products / Product1 /...

serializer.data [&#39; id&#39;]:3713

在请求的结果中,我现在只有product_url和product_location ....

还有其他方法可以实现我的目标吗?

2 个答案:

答案 0 :(得分:2)

首先需要检查序列化程序是否有效。然后你可以调用serializer.save()来创建新对象,或者只是创建新的序列化器对象并传递给它已经存在的产品:

def perform_create(self, serializer):
    if serializer.is_valid():
        product_name = serializer.validated_data['product_name']
        product_location = serializer.validated_data['product_location']

        if product_name != '':
            product_list = Product.objects.filter(
                product_name=product_name, product_location=product_location)

            if not product_list:
                product = serializer.save()
            else:
                product = product_list[0]
                serializer = ProductSerializer(product)
            return Response(serializer.data)   
        else:
            return Response(data={'message': 'Empty product_name'},
                        status=status.HTTP_400_BAD_REQUEST)
    else:
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

如果序列化程序的数据无效,则必须返回serializer.errors

答案 1 :(得分:0)

好的,所以我解决了我的问题,不使用perform_create。我回到了一个简单的APIView,并根据需要定义了POST方法。现在工作得很好。

class ProductCreate(APIView):
    """
    Create a new product.
    """

    permission_classes = (permissions.IsAuthenticated,)

    def post(cls, request, format=None):
        serializer = ProductSerializer(data=request.data)
        if serializer.is_valid():
           ............
相关问题