# 一些只參與反序列化的字段,可是不是與數據庫關聯的 # 在序列化類中規定,並在校驗字段時從校驗的參數字典中剔除 class PublishModelSerializer(serializers.ModelSerializer): # 自定義不入庫的 反序列化 字段 re_name = serializers.CharField(write_only=True) class Meta: model = models.Publish fields = ('name', 're_name', 'address') def validate(self, attrs): name = attrs.get('name') re_name = attrs.pop('re_name') # 剔除 if name != re_name: raise serializers.ValidationError({'re_name': '確認名字有誤'}) return attrs
# model類中自定義插拔的外鍵序列化字段,能夠採用外鍵關聯表的序列化類來完成深度查詢 class Book(BaseModel): # ... @property def publish_detail(self): from . import serializers data = serializers.PublishModelSerializer(self.publish).data return data
# 單查羣查、單刪羣刪、單增羣增、單改羣改
from django.conf.urls import url from . import views urlpatterns = [ # ... url(r'^v3/books/$', views.BookV3APIView.as_view()), url(r'^v3/books/(?P<pk>.*)/$', views.BookV3APIView.as_view()), ]
# 修改部分:取消book類 name 與 publish 聯合惟一, from django.db import models from utils.model import BaseModel class Book(BaseModel): name = models.CharField(max_length=64) price = models.DecimalField(max_digits=5, decimal_places=2) img = models.ImageField(upload_to='img', default='img/default.png') publish = models.ForeignKey(to='Publish', null=True, related_name='books', db_constraint=False, on_delete=models.DO_NOTHING, ) authors = models.ManyToManyField(to='Author', null=True, related_name='books', db_constraint=False, ) @property def publish_name(self): return self.publish.name @property def authors_info(self): author_list = [] for author in self.authors.all(): author_list.append({ 'name': author.name, 'age': author.age, 'mobile': author.detail.mobile }) return author_list @property def publish_bac(self): from . import serializers data = serializers.PublishModelSerializer(self.publish).data return data class Meta: db_table = 'old_boy_book' verbose_name = '書籍' verbose_name_plural = verbose_name # 聯合惟一 # unique_together = ('name', 'publish') def __str__(self): return self.name class Publish(BaseModel): name = models.CharField(max_length=64) address = models.CharField(max_length=64) class Meta: db_table = 'old_boy_publish' verbose_name = '出版社' verbose_name_plural = verbose_name def __str__(self): return self.name class Author(BaseModel): name = models.CharField(max_length=64) age = models.IntegerField() @property def mobile(self): return self.detail.mobile class Meta: db_table = 'old_boy_author' verbose_name = '做者' verbose_name_plural = verbose_name def __str__(self): return self.name class AuthorDetail(BaseModel): mobile = models.CharField(max_length=11) author = models.OneToOneField(to='Author', null=True, related_name='detail', db_constraint=False, on_delete=models.CASCADE ) class Meta: db_table = 'old_boy_author_detail' verbose_name = '做者詳情' verbose_name_plural = verbose_name def __str__(self): return '%s的詳情' % self.author.name
api/serializers.py
python
# 羣增與羣改反序列化實現 # 1)ModelSerializer默認不經過羣改功能,須要在Meta中設置 list_serializer_class # 2)自定義ListSerializer子類,重寫update方法,將子類綁定給 list_serializer_class # 3)重寫update方法中經過 表明要更新的對象們instance 及 提供的更新數據們validated_data # 獲得 更新後的對象們instance 返回 class BookV3ListSerializer(serializers.ListSerializer): def update(self, instance, validated_data): ''' :param instance: [book_obj1, ..., book_obj2] :param validated_data: [{更新數據的字段}, ..., {更新數據的字段}] :return: [book_new_obj1, ..., book_new_obj2] ''' for index, obj in enumerate(instance): # type: int, models.Book # 單個對象數據更新 - 一個個屬性更新值 for attr, value in validated_data[index].items(): # 對象有更新數據字典的key對應的屬性,才完成該屬性的值更新 if hasattr(obj, attr): setattr(obj, attr, value) # 信息同步到數據庫 obj.save() return instance class BookV3ModelSerializer(serializers.ModelSerializer): class Meta: model = models.Book fields = ('name', 'price', 'publish', 'authors', 'img', 'publish_name', 'authors_info') list_serializer_class = BookV3ListSerializer extra_kwargs = { 'publish': { 'required': True, 'write_only': True }, 'authors': { 'required': True, 'write_only': True }, 'img': { 'read_only': True } } def validate_name(self, value): if 'sb' in value: raise serializers.ValidationError('書名有敏感詞彙') return value def validate(self, attrs): name = attrs.get('name') publish = attrs.get('publish') if models.Book.objects.filter(name=name, publish=publish): raise serializers.ValidationError({'book': '書籍以存在'}) return attrs
api/views.py
git
class BookV3APIView(APIView): # 單查羣查 def get(self, request, *args, **kwargs): pk = kwargs.get('pk') if pk: book_obj = models.Book.objects.filter(is_delete=False, pk=pk).first() if not book_obj: return APIResponse(1, 'pk error') book_ser = serializers.BookV3ModelSerializer(book_obj) return APIResponse(0, 'ok', results=book_ser.data) book_query = models.Book.objects.filter(is_delete=False).all().order_by('-id') book_ser = serializers.BookV3ModelSerializer(book_query, many=True) return APIResponse(0, 'ok', results=book_ser.data) # 單增羣增 def post(self, request, *args, **kwargs): # 單增 /books/ data {} # 羣增 /books/ data [{}, ..., {}] request_data = request.data if isinstance(request_data, dict): data = [request_data, ] elif isinstance(request_data, list): data = request_data else: return APIResponse(1, '數據格式有誤') book_ser = serializers.BookV3ModelSerializer(data=data, many=True) if book_ser.is_valid(): book_obj_list = book_ser.save() return APIResponse(0, 'ok', results=serializers.BookV3ModelSerializer(book_obj_list, many=True).data ) else: return APIResponse(1, '添加失敗', results=book_ser.errors) """ 1)先肯定要更新的對象 主鍵們 與 數據們 2)經過校驗數據庫剔除 已刪除的對象 與 不存在的對象 主鍵們 => 剔除過程 => 能夠修改的對象們 數據們 => 剔除過程 => 能夠修改的對象們對應的數據們 3)反序列化及校驗過程 經過 => save() 完成更新 失敗 => ser_obj.errors 返回 """ # 單改羣改 def patch(self, request, *args, **kwargs): # 單改 /books/(pk)/ data {"name": "new_name", ...} # 羣改 /books/ data [{"pk": 1, "name": "new_name", ...}, ...,{"pk": n, "name": "new_name", ...}] # 結果: # pks = [1, ..., n] => book_query => instance # data = [{"name": "new_name", ...}, ..., {"name": "new_name", ...}] => data # 數據預處理 pk = kwargs.get('pk') request_data = request.data if pk: if not isinstance(request_data, dict): return APIResponse(1, '單改數據有誤') pks = [pk, ] data = [request_data, ] elif isinstance(request_data, list): try: pks = [] for dic in request_data: pks.append(dic.pop('pk')) data = request_data except: return APIResponse(1, '羣改數據有誤') else: return APIResponse(1, '數據格式有誤') # 將 已刪除的書籍 與 不存在的書籍 剔除 (提供修改的數據相對應也剔除) book_query = [] filter_data = [] for index, pk in enumerate(pks): book_obj = models.Book.objects.filter(is_delete=False, pk=pk).first() if book_obj: book_query.append(book_obj) filter_data.append(data[index]) # 反序列化完成數據的修改 book_ser = serializers.BookV3ModelSerializer(instance=book_query, data=filter_data, many=True, partial=True) if book_ser.is_valid(): book_obj_list = book_ser.save() return APIResponse(1, 'ok', results=serializers.BookV3ModelSerializer(book_obj_list, many=True).data ) else: return APIResponse(1, '更新失敗', results=book_ser.errors) # 單刪羣刪 def delete(self, request, *args, **kwargs): # 單刪 /books/(pk)/ # 羣刪 /books/ 數據包攜帶 pks => request.data pk = kwargs.get('pk') if pk: pks = [pk] else: pks = request.data.get('pks') if not pks: return APIResponse(1, '刪除失敗') book_query = models.Book.objects.filter(is_delete=False, pk__in=pks) if not book_query.update(is_delete=True): # 操做的記錄大於0就記錄刪除成功 return APIResponse(1, '刪除失敗') return APIResponse(0, '刪除成功')