DJango REST框架:如何使用ModelViewSet

时间:2019-05-19 23:03:16

标签: python django django-rest-framework

我还是python / django的新手,目前我正尝试使用django rest框架添加REST API。这是我目前拥有的:

urls.py

actions_url = {'actions': {'get': 'list', 'post': 'create'}}
actions_obj = {'actions': {'get': 'retrieve', 'delete': 'destroy', 'put': 'update'}}

urlpatterns = [
   path('book', BookViewSet.as_view(**actions_url)),
   path('book/<str:isbn>', BookViewSet.as_view(**actions_obj))
]

models.py(该模型没有PK)

class Book(models.Model):
   BNAME = models.CharField(
       db_column='BNAME',
       max_length=30,
       default='')

   BISBN = models.CharField(
       db_column='BISBN',
       max_length=10,
       default='')

views.py

class BookSerializer(serializers.ModelSerializer):
   name = serializers.CharField(source="BNAME")
   isbn = serializers.CharField(source="BISBN")

       class Meta:
           model = models.Book
           fields = ('name', 'isbn')


class BookViewSet(viewsets.ModelViewSet)
   queryset = Book.objects.all()
   serializer_class = BookSerializer

   def list(self, request):
       return queryset

   def create(self, request):
       pass

   def retrieve(self, request, *args, **kwargs):
       pass

   def update(self, request, *args, **kwargs):
       pass

   def destroy(self, request, *args, **kwargs):
       pass

所以我的问题是:

  1. 例如,如果我不将def create(self, request)包括在BookViewSet中,那么我假设当我制作POST /book时它什么都不做?
  2. 我正在努力了解要放入createretrieveupdatedestroy中的内容。例如,如果我使用参数PUT /book/123制作了{ isbn: '123', name: 'test'},那么我需要在def update中做什么才能从请求中检索这些数据,然后将数据更新到数据库?
  3. 我想验证isbn并确保它唯一/不重复,然后再将记录保存/更新到数据库,该怎么办?我尝试阅读有关Validator的文章:https://www.django-rest-framework.org/api-guide/validators/,看起来我需要更新序列化程序:
class BookSerializer(serializers.ModelSerializer):
    name = serializers.CharField(source="BNAME")
    isbn = serializers.CharField(source="BISBN", validators=[<UniqueValidator(queryset=Book.objects.all())>])

        class Meta:
            model = models.Book
            fields = ('name', 'isbn')

这正确吗?

  1. 类似于上一个问题,但是现在我想确保isbnname两者都是唯一的,我认为这是我需要做的:
class BookSerializer(serializers.ModelSerializer):
    name = serializers.CharField(source="BNAME")
    isbn = serializers.CharField(source="BISBN")

        class Meta:
            model = models.Book
            fields = ('name', 'isbn')

        validators = [
            UniqueTogetherValidator(
                queryset=Book.objects.all(),
                fields=('name', 'isbn')
            )
        ]

这正确吗?

谢谢

1 个答案:

答案 0 :(得分:0)

  1. 您实现的create(self, request, *args, **kwargs)不会执行任何操作,因为该函数为空,甚至不会返回响应。

  2. 您不必在createlistretrieveupdatepartial_update和{{1} },因为您使用的是destroy类。 ModelViewSet为所有它们提供默认的实现。如果您确实想保留替代信息,则可以改用以下实现:

ModelViewSet

我们使用def create(self, request, *args, **kwargs): """You could add some documentation here""" return super().create(request, *args, **kwargs) 是因为它正在调用super()的父实现。

  1. 您的操作是正确的,我只想补充一点,我个人会在模型字段上放置create而不是将验证器添加到序列化器中。 Rest Framework非常聪明,序列化程序将检查模型字段并自动神奇地添加唯一的验证。如果您想避免在数据库上使用唯一索引,那么我认为unique=True的使用是正确的。

UniqueValidator

请记住,如果没有数据库上的唯一索引,您可能会遇到竞争状况。我的意思是,如果这些操作同时发生,则可以创建/更新两本书以具有相同的isbn。

  1. 同样,我将使用模型的BISBN = models.CharField(db_column='BISBN', max_length=10, default=None, unique=True)属性对模型上的多个字段进行验证,即
Meta.unique_together

但是,如果您不想为此在数据库上使用唯一索引,那么您使用class Book(models.Model): # fields... class Meta: unique_together = ("BNAME", "BISBN") 是正确的。

我认为还有另外一个花絮:

您查看的网址应该包含UniqueTogetherValidatorlookup_url_kwarg才能与网址定义中的isbn一起使用。

lookup_field

如果要处理多个url kwarg,则需要自定义class BookViewSet(ModelViewSet): lookup_url_kwarg = "isbn" # Use the 'isbn' from your url definition lookup_field = "BISBN" # Use the `BISBN` field on your database/model to perform the lookups # ... 方法。在下面的代码中,我使用get_queryset()来过滤查询集,然后让视图按名称查找书。

isbn