八、drf单、群增删查改

drf单、群增删查改

一、单群增

① models.py

from django.db import models


class BaseModel(models.Model):
    is_delete = models.BooleanField(default=False)

    # auto_now_add = True 只要记录创建,不需要手动插入时间,自动版当前时间插入
    create_time = models.DateTimeField(auto_now_add=True)
    # auto_now = True 只要更新,就会把当前时间插入
    last_update_time = models.DateTimeField(auto_now=True)
    # 此处的Datetime.datetime.now不需要加括号,加括号和不加括号有很大的区别
    # create_time = models.DateTimeField(default=Datetime.datetime.now)

    class Meta:
        # 单个字段,有索引,有唯一
        # 多个字段,又联合索引,联合唯一
        abstract = True # 抽象表,不在数据库中创建实际表


class Book(BaseModel):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32,verbose_name="书名")
    price = models.DecimalField(max_digits=5,decimal_places=2,verbose_name="价格")

    # 一对多关系一旦确立,关联字段写在多的一边
    # to_field 默认不写,关联到Publish主键
    # db_constraint = False 逻辑上的关联,实质上没有外键联系,增删不会受外键影响,但是orm查询不影响
    publish = models.ForeignKey(to="Publish",on_delete=models.DO_NOTHING,db_constraint=False)

    # 多对多关系,跟作者  关联字段写在查询次数多的一方

    # 什么时候使用自动,什么时候使用手动? 第三张表只有关联字段,用自动;  第三张表有扩展字段,需要手动写
    # 不能写on_delete 因为使用自动的话,这是orm帮我们建的关系表,不会真正作用到数据库中
    authors = models.ManyToManyField(to="Author",db_constraint=False)

    class Meta:
        verbose_name_plural = "书表" # admin中表名的显示

    def __str__(self):
        return self.name

    @property
    def publish_name(self):
        return self.publish.name

    def author_list(self):
        # 拿到所有作者
        author_list = self.authors.all()
        ll = []
        for author in author_list:
            ll.append({'name':author.name,'sex':author.get_sex_display()})
        return ll
        # 列表推导式,太长了就别用了
        # return [{'name':author.name,'sex':author.get_sex_display()} for author in author_list]


class Publish(BaseModel):
    name = models.CharField(max_length=32,verbose_name="出版社")
    addr = models.CharField(max_length=32,verbose_name="地址")

    class Meta:
        verbose_name_plural = "出版社"

    def __str__(self):
        return self.name

class Author(BaseModel):
    name = models.CharField(max_length=32,verbose_name="作者")
    sex = models.IntegerField(choices=((1,"男"),(2,'女'),),verbose_name="性别")

    # 一对一关系,关联字段写在查询频率高的那一方
    # OneToOneField本质就是ForeignKey + unique,自己手动写也可以
    author_Detail = models.OneToOneField(to="AuthorDetail",db_constraint=False,on_delete=models.CASCADE)

    class Meta:
        verbose_name_plural = "作者表"

    def __str__(self):
        return self.name


class AuthorDetail(BaseModel):
    mobile = models.CharField(max_length=11,verbose_name="手机号")

    class Meta:
        verbose_name_plural = "作者详情表"

    def __str__(self):
        return self.mobile


# 表断关联
# 1.表之间没有外键关联,但是有外键逻辑关联(有充当外键的字段)
# 2.断关系后不会影响数据查询效率,但是会极大提高数据库增删改效率(不影响增删改查操作)
# 3.断关系一定要通过逻辑保证表支架数据安全
# 4.断关联
# 5.级联关系
    # <1> 作者没了,详情也没了:on_delete = models.CASCADE
    # <2> 出版社没了,书还是那个出版社出版:on_delete = models.DO_NOTHING
    # <3> 部门没了,员工没有部门(空不能):null = True ,on_delete = models.SET_NULL
    # <4> 部门没了,员工进入默认部门(默认值):default = 0,on_delete = models.SET_DEFAULT

② ser.py

from api import models
from rest_framework import serializers


# 写一个类,继承ListSerializer,重写修改数据时需要执行的update方法
class BookListSerializer(serializers.ListSerializer):
    # def create(self, validated_data):
    # 这是重写新增数据时需要执行的方法
    # print(validated_data)
    # return super().create(validated_data)
    def update(self, instance, validated_data):
        # 这是重写修改数据时需要执行的方法
        # instance = book_list,数据格式是:[book1,book2,book3]
        # validated_data = modify_data,数据格式是:[{name:jason,price:12},{name:jason,price:12}]

        # 此处的self.child是BookSerializer对象,但是需要在BookSerializer中的Meta中配置一句话
        # list_serializer_class = BookListSerializer
        print("----》",instance)
        print("---->",validated_data)

        # ll = []
        # for i,si_data in enumerate(validated_data):
        #     result = self.child.update(instance[i],si_data)
        #     ll.append(result)
        # return ll
        """上面的方法和下面的方法一致"""
        return [
            self.child.update(instance[i], attrs) for i, attrs in enumerate(validated_data)

            # self.child.update(instance[i], attrs) for i, attrs in enumerate(validated_data)
            # def update(self, instance = instance[i], validated_data = attrs):
            #   pass
        ]


# 如何序列化的是数据库的表,尽量用ModelSerializer
class BookSerializer(serializers.ModelSerializer):
    # depth:控制的是在前端展示的外键数据
    # 因为数据库中的有些数据不需要在前端展示,所以需要在后端处理展示的信息

    # 方式一:只序列化可以,反序列化会出现问题
    # publish = serializers.CharField(source="publish.name")

    # 方式二:在models中写方法
    # ...

    class Meta:
        list_serializer_class = BookListSerializer
        model = models.Book
        # fields = "__all__"
        # 控制前端展示的数据信息,用得少
        # depth = 0

        fields = ('id','name', 'price', 'authors', 'publish', 'publish_name', 'author_list')
        extra_kwargs = {
            'publish': {'write_only': True},
            'publish_name': {"read_only": True},
            'authors': {'write_only': True},
            'author_list': {"read_only": True},
        }

③ urls.py

# 使用了路由分发
from django.conf.urls import url
from api import views

urlpatterns = [
    # 此处一定要记得,特殊的路由放在上面,避免匹配到 
    url(r'books/(?P<pk>\d+)', views.BookAPIView.as_view()),
    url(r'books/', views.BookAPIView.as_view()),
]

④ views.py

"""单查群查、单增群增、单改群改、单删群删"""
class BookAPIView(APIView):
    # 增加一条和多条数据
    def post(self, request, *args, **kwargs):
        # 具备增单条和增多条的功能
        if isinstance(request.data, dict):  # 如果request.data 是一个套字段信息的字典,就是增一条数据 {}
            book_ser = ser.BookSerializer(data=request.data)
            book_ser.is_valid(raise_exception=True)
            book_ser.save()
            return Response(data=book_ser.data)
        elif isinstance(request.data, list):  # 如果request.data 是一个套字段信息的多个字典的列表,就是增多条数据 [{},{},{}]
            # 此时的book_ser是ListSerializer对象
            book_ser = ser.BookSerializer(data=request.data, many=True)
            print(type(book_ser))
            book_ser.is_valid(raise_exception=True)
            book_ser.save()
            # 此时的book_ser.save()是谁的方法?
            '''
            此时的book_ser是ListSerializer对象,所以save()方法是ListSerializer的save()的方法
            批量新增-----》ListSerializer------》create()方法
            
            # 源码中的方法
            def create(self,validated_data):
                # self.create是bookSerializer对象
                return [
                    self.child.create(attr) for attr in validated_data
                ]
            '''
            return Response(data=book_ser.data)

二、单群删

① models.py

from django.db import models


class BaseModel(models.Model):
    is_delete = models.BooleanField(default=False)

    # auto_now_add = True 只要记录创建,不需要手动插入时间,自动版当前时间插入
    create_time = models.DateTimeField(auto_now_add=True)
    # auto_now = True 只要更新,就会把当前时间插入
    last_update_time = models.DateTimeField(auto_now=True)
    # 此处的Datetime.datetime.now不需要加括号,加括号和不加括号有很大的区别
    # create_time = models.DateTimeField(default=Datetime.datetime.now)

    class Meta:
        # 单个字段,有索引,有唯一
        # 多个字段,又联合索引,联合唯一
        abstract = True # 抽象表,不在数据库中创建实际表


class Book(BaseModel):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32,verbose_name="书名")
    price = models.DecimalField(max_digits=5,decimal_places=2,verbose_name="价格")

    # 一对多关系一旦确立,关联字段写在多的一边
    # to_field 默认不写,关联到Publish主键
    # db_constraint = False 逻辑上的关联,实质上没有外键联系,增删不会受外键影响,但是orm查询不影响
    publish = models.ForeignKey(to="Publish",on_delete=models.DO_NOTHING,db_constraint=False)

    # 多对多关系,跟作者  关联字段写在查询次数多的一方

    # 什么时候使用自动,什么时候使用手动? 第三张表只有关联字段,用自动;  第三张表有扩展字段,需要手动写
    # 不能写on_delete 因为使用自动的话,这是orm帮我们建的关系表,不会真正作用到数据库中
    authors = models.ManyToManyField(to="Author",db_constraint=False)

    class Meta:
        verbose_name_plural = "书表" # admin中表名的显示

    def __str__(self):
        return self.name

    @property
    def publish_name(self):
        return self.publish.name

    def author_list(self):
        # 拿到所有作者
        author_list = self.authors.all()
        ll = []
        for author in author_list:
            ll.append({'name':author.name,'sex':author.get_sex_display()})
        return ll
        # 列表推导式,太长了就别用了
        # return [{'name':author.name,'sex':author.get_sex_display()} for author in author_list]


class Publish(BaseModel):
    name = models.CharField(max_length=32,verbose_name="出版社")
    addr = models.CharField(max_length=32,verbose_name="地址")

    class Meta:
        verbose_name_plural = "出版社"

    def __str__(self):
        return self.name

class Author(BaseModel):
    name = models.CharField(max_length=32,verbose_name="作者")
    sex = models.IntegerField(choices=((1,"男"),(2,'女'),),verbose_name="性别")

    # 一对一关系,关联字段写在查询频率高的那一方
    # OneToOneField本质就是ForeignKey + unique,自己手动写也可以
    author_Detail = models.OneToOneField(to="AuthorDetail",db_constraint=False,on_delete=models.CASCADE)

    class Meta:
        verbose_name_plural = "作者表"

    def __str__(self):
        return self.name


class AuthorDetail(BaseModel):
    mobile = models.CharField(max_length=11,verbose_name="手机号")

    class Meta:
        verbose_name_plural = "作者详情表"

    def __str__(self):
        return self.mobile


# 表断关联
# 1.表之间没有外键关联,但是有外键逻辑关联(有充当外键的字段)
# 2.断关系后不会影响数据查询效率,但是会极大提高数据库增删改效率(不影响增删改查操作)
# 3.断关系一定要通过逻辑保证表支架数据安全
# 4.断关联
# 5.级联关系
    # <1> 作者没了,详情也没了:on_delete = models.CASCADE
    # <2> 出版社没了,书还是那个出版社出版:on_delete = models.DO_NOTHING
    # <3> 部门没了,员工没有部门(空不能):null = True ,on_delete = models.SET_NULL
    # <4> 部门没了,员工进入默认部门(默认值):default = 0,on_delete = models.SET_DEFAULT

② ser.py

from api import models
from rest_framework import serializers


# 写一个类,继承ListSerializer,重写修改数据时需要执行的update方法
class BookListSerializer(serializers.ListSerializer):
    # def create(self, validated_data):
    # 这是重写新增数据时需要执行的方法
    # print(validated_data)
    # return super().create(validated_data)
    def update(self, instance, validated_data):
        # 这是重写修改数据时需要执行的方法
        # instance = book_list,数据格式是:[book1,book2,book3]
        # validated_data = modify_data,数据格式是:[{name:jason,price:12},{name:jason,price:12}]

        # 此处的self.child是BookSerializer对象,但是需要在BookSerializer中的Meta中配置一句话
        # list_serializer_class = BookListSerializer
        print("----》",instance)
        print("---->",validated_data)

        # ll = []
        # for i,si_data in enumerate(validated_data):
        #     result = self.child.update(instance[i],si_data)
        #     ll.append(result)
        # return ll
        """上面的方法和下面的方法一致"""
        return [
            self.child.update(instance[i], attrs) for i, attrs in enumerate(validated_data)

            # self.child.update(instance[i], attrs) for i, attrs in enumerate(validated_data)
            # def update(self, instance = instance[i], validated_data = attrs):
            #   pass
        ]


# 如何序列化的是数据库的表,尽量用ModelSerializer
class BookSerializer(serializers.ModelSerializer):
    # depth:控制的是在前端展示的外键数据
    # 因为数据库中的有些数据不需要在前端展示,所以需要在后端处理展示的信息

    # 方式一:只序列化可以,反序列化会出现问题
    # publish = serializers.CharField(source="publish.name")

    # 方式二:在models中写方法
    # ...

    class Meta:
        list_serializer_class = BookListSerializer
        model = models.Book
        # fields = "__all__"
        # 控制前端展示的数据信息,用得少
        # depth = 0

        fields = ('id','name', 'price', 'authors', 'publish', 'publish_name', 'author_list')
        extra_kwargs = {
            'publish': {'write_only': True},
            'publish_name': {"read_only": True},
            'authors': {'write_only': True},
            'author_list': {"read_only": True},
        }

③ urls.py

# 使用了路由分发
from django.conf.urls import url
from api import views

urlpatterns = [
    # 此处一定要记得,特殊的路由放在上面,避免匹配到 
    url(r'books/(?P<pk>\d+)', views.BookAPIView.as_view()),
    url(r'books/', views.BookAPIView.as_view()),
]

④ views.py

"""单查群查、单增群增、单改群改、单删群删"""
class BookAPIView(APIView):
    # 删除一条和多条数据
    def delete(self,request,*args,**kwargs):
        # 多条单条一起删除
        pk = kwargs.get('pk')
        pks = []
        if pk:
            """删除一条数据"""
            # 此处的pk是前端在url路径后面拼接的数据pk
            # append进pks是为了后面一起删除数据
            print(pk)
            pks.append(pk)
        else:
            """删除多条数据"""
            # 此处的pks是前端在body中传入的需要删除的数据的pk
            # 前端传回来的数据格式是{'pks':[1,2,3]}
            # 直接赋值给pks是为了后面一起删除数据

            pks = request.data.get('pks')
        # 数据并不是真正的删除,只是将is_delete字段改成False而已
        # result 是返回受影响的字段数,是一个int类型
        result = models.Book.objects.filter(pk__in=pks,is_delete=False).update(is_delete=True)
        if result > 0:
            return Response(data='删除成功')
        else:
            return Response(data="删除失败")


三、单群查

① models.py

from django.db import models


class BaseModel(models.Model):
    is_delete = models.BooleanField(default=False)

    # auto_now_add = True 只要记录创建,不需要手动插入时间,自动版当前时间插入
    create_time = models.DateTimeField(auto_now_add=True)
    # auto_now = True 只要更新,就会把当前时间插入
    last_update_time = models.DateTimeField(auto_now=True)
    # 此处的Datetime.datetime.now不需要加括号,加括号和不加括号有很大的区别
    # create_time = models.DateTimeField(default=Datetime.datetime.now)

    class Meta:
        # 单个字段,有索引,有唯一
        # 多个字段,又联合索引,联合唯一
        abstract = True # 抽象表,不在数据库中创建实际表


class Book(BaseModel):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32,verbose_name="书名")
    price = models.DecimalField(max_digits=5,decimal_places=2,verbose_name="价格")

    # 一对多关系一旦确立,关联字段写在多的一边
    # to_field 默认不写,关联到Publish主键
    # db_constraint = False 逻辑上的关联,实质上没有外键联系,增删不会受外键影响,但是orm查询不影响
    publish = models.ForeignKey(to="Publish",on_delete=models.DO_NOTHING,db_constraint=False)

    # 多对多关系,跟作者  关联字段写在查询次数多的一方

    # 什么时候使用自动,什么时候使用手动? 第三张表只有关联字段,用自动;  第三张表有扩展字段,需要手动写
    # 不能写on_delete 因为使用自动的话,这是orm帮我们建的关系表,不会真正作用到数据库中
    authors = models.ManyToManyField(to="Author",db_constraint=False)

    class Meta:
        verbose_name_plural = "书表" # admin中表名的显示

    def __str__(self):
        return self.name

    @property
    def publish_name(self):
        return self.publish.name

    def author_list(self):
        # 拿到所有作者
        author_list = self.authors.all()
        ll = []
        for author in author_list:
            ll.append({'name':author.name,'sex':author.get_sex_display()})
        return ll
        # 列表推导式,太长了就别用了
        # return [{'name':author.name,'sex':author.get_sex_display()} for author in author_list]


class Publish(BaseModel):
    name = models.CharField(max_length=32,verbose_name="出版社")
    addr = models.CharField(max_length=32,verbose_name="地址")

    class Meta:
        verbose_name_plural = "出版社"

    def __str__(self):
        return self.name

class Author(BaseModel):
    name = models.CharField(max_length=32,verbose_name="作者")
    sex = models.IntegerField(choices=((1,"男"),(2,'女'),),verbose_name="性别")

    # 一对一关系,关联字段写在查询频率高的那一方
    # OneToOneField本质就是ForeignKey + unique,自己手动写也可以
    author_Detail = models.OneToOneField(to="AuthorDetail",db_constraint=False,on_delete=models.CASCADE)

    class Meta:
        verbose_name_plural = "作者表"

    def __str__(self):
        return self.name


class AuthorDetail(BaseModel):
    mobile = models.CharField(max_length=11,verbose_name="手机号")

    class Meta:
        verbose_name_plural = "作者详情表"

    def __str__(self):
        return self.mobile


# 表断关联
# 1.表之间没有外键关联,但是有外键逻辑关联(有充当外键的字段)
# 2.断关系后不会影响数据查询效率,但是会极大提高数据库增删改效率(不影响增删改查操作)
# 3.断关系一定要通过逻辑保证表支架数据安全
# 4.断关联
# 5.级联关系
    # <1> 作者没了,详情也没了:on_delete = models.CASCADE
    # <2> 出版社没了,书还是那个出版社出版:on_delete = models.DO_NOTHING
    # <3> 部门没了,员工没有部门(空不能):null = True ,on_delete = models.SET_NULL
    # <4> 部门没了,员工进入默认部门(默认值):default = 0,on_delete = models.SET_DEFAULT

② ser.py

from api import models
from rest_framework import serializers


# 写一个类,继承ListSerializer,重写修改数据时需要执行的update方法
class BookListSerializer(serializers.ListSerializer):
    # def create(self, validated_data):
    # 这是重写新增数据时需要执行的方法
    # print(validated_data)
    # return super().create(validated_data)
    def update(self, instance, validated_data):
        # 这是重写修改数据时需要执行的方法
        # instance = book_list,数据格式是:[book1,book2,book3]
        # validated_data = modify_data,数据格式是:[{name:jason,price:12},{name:jason,price:12}]

        # 此处的self.child是BookSerializer对象,但是需要在BookSerializer中的Meta中配置一句话
        # list_serializer_class = BookListSerializer
        print("----》",instance)
        print("---->",validated_data)

        # ll = []
        # for i,si_data in enumerate(validated_data):
        #     result = self.child.update(instance[i],si_data)
        #     ll.append(result)
        # return ll
        """上面的方法和下面的方法一致"""
        return [
            self.child.update(instance[i], attrs) for i, attrs in enumerate(validated_data)

            # self.child.update(instance[i], attrs) for i, attrs in enumerate(validated_data)
            # def update(self, instance = instance[i], validated_data = attrs):
            #   pass
        ]


# 如何序列化的是数据库的表,尽量用ModelSerializer
class BookSerializer(serializers.ModelSerializer):
    # depth:控制的是在前端展示的外键数据
    # 因为数据库中的有些数据不需要在前端展示,所以需要在后端处理展示的信息

    # 方式一:只序列化可以,反序列化会出现问题
    # publish = serializers.CharField(source="publish.name")

    # 方式二:在models中写方法
    # ...

    class Meta:
        list_serializer_class = BookListSerializer
        model = models.Book
        # fields = "__all__"
        # 控制前端展示的数据信息,用得少
        # depth = 0

        fields = ('id','name', 'price', 'authors', 'publish', 'publish_name', 'author_list')
        extra_kwargs = {
            'publish': {'write_only': True},
            'publish_name': {"read_only": True},
            'authors': {'write_only': True},
            'author_list': {"read_only": True},
        }

③ urls.py

# 使用了路由分发
from django.conf.urls import url
from api import views

urlpatterns = [
    # 此处一定要记得,特殊的路由放在上面,避免匹配到 
    url(r'books/(?P<pk>\d+)', views.BookAPIView.as_view()),
    url(r'books/', views.BookAPIView.as_view()),
]

④ views.py

"""单查群查、单增群增、单改群改、单删群删"""
class BookAPIView(APIView):
    # 查询一条和多条数据
    def get(self, request, *args, **kwargs):
        # 查询单个和查询所有,合到一起
        if kwargs.get('pk', None): # 查询一条数据
            book_obj = models.Book.objects.filter(pk=kwargs.get('pk'), is_delete=False).first()
            book_ser = ser.BookSerializer(instance=book_obj)
            return Response(data=book_ser.data)
        else: # 此处是查询所有
            book_list_obj = models.Book.objects.all().filter(is_delete=False)
            book_list_ser = ser.BookSerializer(instance=book_list_obj, many=True)
            return Response(data=book_list_ser.data)

四、单群改

① models.py

from django.db import models


class BaseModel(models.Model):
    is_delete = models.BooleanField(default=False)

    # auto_now_add = True 只要记录创建,不需要手动插入时间,自动版当前时间插入
    create_time = models.DateTimeField(auto_now_add=True)
    # auto_now = True 只要更新,就会把当前时间插入
    last_update_time = models.DateTimeField(auto_now=True)
    # 此处的Datetime.datetime.now不需要加括号,加括号和不加括号有很大的区别
    # create_time = models.DateTimeField(default=Datetime.datetime.now)

    class Meta:
        # 单个字段,有索引,有唯一
        # 多个字段,又联合索引,联合唯一
        abstract = True # 抽象表,不在数据库中创建实际表


class Book(BaseModel):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32,verbose_name="书名")
    price = models.DecimalField(max_digits=5,decimal_places=2,verbose_name="价格")

    # 一对多关系一旦确立,关联字段写在多的一边
    # to_field 默认不写,关联到Publish主键
    # db_constraint = False 逻辑上的关联,实质上没有外键联系,增删不会受外键影响,但是orm查询不影响
    publish = models.ForeignKey(to="Publish",on_delete=models.DO_NOTHING,db_constraint=False)

    # 多对多关系,跟作者  关联字段写在查询次数多的一方

    # 什么时候使用自动,什么时候使用手动? 第三张表只有关联字段,用自动;  第三张表有扩展字段,需要手动写
    # 不能写on_delete 因为使用自动的话,这是orm帮我们建的关系表,不会真正作用到数据库中
    authors = models.ManyToManyField(to="Author",db_constraint=False)

    class Meta:
        verbose_name_plural = "书表" # admin中表名的显示

    def __str__(self):
        return self.name

    @property
    def publish_name(self):
        return self.publish.name

    def author_list(self):
        # 拿到所有作者
        author_list = self.authors.all()
        ll = []
        for author in author_list:
            ll.append({'name':author.name,'sex':author.get_sex_display()})
        return ll
        # 列表推导式,太长了就别用了
        # return [{'name':author.name,'sex':author.get_sex_display()} for author in author_list]


class Publish(BaseModel):
    name = models.CharField(max_length=32,verbose_name="出版社")
    addr = models.CharField(max_length=32,verbose_name="地址")

    class Meta:
        verbose_name_plural = "出版社"

    def __str__(self):
        return self.name

class Author(BaseModel):
    name = models.CharField(max_length=32,verbose_name="作者")
    sex = models.IntegerField(choices=((1,"男"),(2,'女'),),verbose_name="性别")

    # 一对一关系,关联字段写在查询频率高的那一方
    # OneToOneField本质就是ForeignKey + unique,自己手动写也可以
    author_Detail = models.OneToOneField(to="AuthorDetail",db_constraint=False,on_delete=models.CASCADE)

    class Meta:
        verbose_name_plural = "作者表"

    def __str__(self):
        return self.name


class AuthorDetail(BaseModel):
    mobile = models.CharField(max_length=11,verbose_name="手机号")

    class Meta:
        verbose_name_plural = "作者详情表"

    def __str__(self):
        return self.mobile


# 表断关联
# 1.表之间没有外键关联,但是有外键逻辑关联(有充当外键的字段)
# 2.断关系后不会影响数据查询效率,但是会极大提高数据库增删改效率(不影响增删改查操作)
# 3.断关系一定要通过逻辑保证表支架数据安全
# 4.断关联
# 5.级联关系
    # <1> 作者没了,详情也没了:on_delete = models.CASCADE
    # <2> 出版社没了,书还是那个出版社出版:on_delete = models.DO_NOTHING
    # <3> 部门没了,员工没有部门(空不能):null = True ,on_delete = models.SET_NULL
    # <4> 部门没了,员工进入默认部门(默认值):default = 0,on_delete = models.SET_DEFAULT

② ser.py

from api import models
from rest_framework import serializers


# 写一个类,继承ListSerializer,重写修改数据时需要执行的update方法
class BookListSerializer(serializers.ListSerializer):
    # def create(self, validated_data):
    # 这是重写新增数据时需要执行的方法
    # print(validated_data)
    # return super().create(validated_data)
    def update(self, instance, validated_data):
        # 这是重写修改数据时需要执行的方法
        # instance = book_list,数据格式是:[book1,book2,book3]
        # validated_data = modify_data,数据格式是:[{name:jason,price:12},{name:jason,price:12}]

        # 此处的self.child是BookSerializer对象,但是需要在BookSerializer中的Meta中配置一句话
        # list_serializer_class = BookListSerializer
        print("----》",instance)
        print("---->",validated_data)

        # ll = []
        # for i,si_data in enumerate(validated_data):
        #     result = self.child.update(instance[i],si_data)
        #     ll.append(result)
        # return ll
        """上面的方法和下面的方法一致"""
        return [
            self.child.update(instance[i], attrs) for i, attrs in enumerate(validated_data)

            # self.child.update(instance[i], attrs) for i, attrs in enumerate(validated_data)
            # def update(self, instance = instance[i], validated_data = attrs):
            #   pass
        ]


# 如何序列化的是数据库的表,尽量用ModelSerializer
class BookSerializer(serializers.ModelSerializer):
    # depth:控制的是在前端展示的外键数据
    # 因为数据库中的有些数据不需要在前端展示,所以需要在后端处理展示的信息

    # 方式一:只序列化可以,反序列化会出现问题
    # publish = serializers.CharField(source="publish.name")

    # 方式二:在models中写方法
    # ...

    class Meta:
        list_serializer_class = BookListSerializer
        model = models.Book
        # fields = "__all__"
        # 控制前端展示的数据信息,用得少
        # depth = 0

        fields = ('id','name', 'price', 'authors', 'publish', 'publish_name', 'author_list')
        extra_kwargs = {
            'publish': {'write_only': True},
            'publish_name': {"read_only": True},
            'authors': {'write_only': True},
            'author_list': {"read_only": True},
        }

③ urls.py

# 使用了路由分发
from django.conf.urls import url
from api import views

urlpatterns = [
    # 此处一定要记得,特殊的路由放在上面,避免匹配到 
    url(r'books/(?P<pk>\d+)', views.BookAPIView.as_view()),
    url(r'books/', views.BookAPIView.as_view()),
]

④ views.py

"""单查群查、单增群增、单改群改、单删群删"""
class BookAPIView(APIView):
    # 修改一条和多条数据
    def put(self, request, *args, **kwargs):
        if kwargs.get('pk', None):  # 修改一条数据
            # kwargs中如果没有pk这个键,就返回None,也就是不会走if中的代码
            book_obj = models.Book.objects.filter(pk=kwargs.get("pk")).first()
            book_ser = ser.BookSerializer(instance=book_obj, data=request.data)
            book_ser.save()
            return Response(request.data)
        else:  # 改多条数据
            """第一种方式,序列化器的代码不需要修改"""

            # book_list = []  # 此时book_list类似于[book1,book2,book3]格式的数据
            # modify_data = []  # 此时的modify_data类似于[{name:jason,price:12},{name:jason,price:12}]格式的数据
            # for item in request.data:  # 此时request.data是一个列表套字典格式的数据
            #     pk = item.pop('id')
            #     book = models.Book.objects.filter(pk=pk).first()
            #     book_list.append(book)
            #     modify_data.append(item)
            #
            # for i,si_data in modify_data:
            #     book_ser = ser.BookSerializer(instance=book_list[i],data=si_data)
            #     book_ser.is_valid(raise_exception=True)
            #     book_ser.save()
            #     return Response(data="成功")

            """第二种方式:复杂点,并且需要配合序列化器,实现的代码全都写在序列化器中"""
            # print(request.data)
            # return Response(request.data)
            # 前端传过来的数据格式:[{id:1,name:jason,price:12},{id:1,name:jason,price:12},{id:1,name:jason,price:12}]
            # 处理后的数据 对象列表instance = [book1,book2,book3] 修改的数据列表data = [{name:jason,price:12},{name:jason,price:12}]
            book_list = []  # 此时book_list类似于[book1,book2,book3]格式的数据
            modify_data = []  # 此时的modify_data类似于[{name:jason,price:12},{name:jason,price:12}]格式的数据
            for item in request.data:  # 此时request.data是一个列表套字典格式的数据
                pk = item.pop('id')
                book = models.Book.objects.filter(pk=pk).first()
                book_list.append(book)
                modify_data.append(item)
            # 序列化
            book_list_ser = ser.BookSerializer(instance=book_list, data=modify_data, many=True)
            # 校验数据
            book_list_ser.is_valid(raise_exception=True)
            # 保存数据
            book_list_ser.save()  # 此时的save()方法是ListSerializer的update方法,但是我们现在自己写一个update方法,使用哪自己的方法
            return Response(book_list_ser.data)
posted @ 2021-01-26 15:55  今天捡到一百块钱  阅读(273)  评论(0编辑  收藏  举报