• Model操作


    1 创建表

    1.1 Meta 源信息

    from django.db import models
    class UserInfo(models.Model):
        username = models.CharField(max_length=32)
        password = models.CharField(max_length=32)
        cls = models.ForeinKey(CLS)
        class Meta:
            #1 数据库中生成的表名称 默认 app名称 + 下划线 + 类名
            db_table = "table_name" #自己指定创建的表名
            
            #2 Django Admin 中显示的表名称
            verbose_name='user' #在Django admin后台显示时表名是users
            
            #3 verbose_name加s
            verbose_name_plural='user' #若果这个字段也是user那么4中表名才显示user
            
            #4 联合唯一索引
            unique_together = (("name", "cls"),)
            
            #5 联合索引 (缺点是最左前缀,写SQL语句基于password时不能命中索引,查找慢)
            # 如:select * from tb where password = ‘xx’ 就无法命中索引
            index_together = [
                ("name", "cls"),
            ]

    1.2 常用字段

    from django.db import models
    
    class UserGroup(models.Model):
        uid = models.AutoField(primary_key=True)
        
        name = models.CharField(max_length=32,null=True, blank=True)
        email = models.EmailField(max_length=32)
        text = models.TextField()
        
        ctime = models.DateTimeField(auto_now_add=True) # 只有添加时才会更新时间
        uptime = models.DateTimeField(auto_now=True)     # 只要修改就会更新时间
        
        ip1 = models.IPAddressField()                     # 字符串类型,Django Admin以及ModelForm中提供验证 IPV4 机制
        
        ip2 = models.GenericIPAddressField()             # 字符串类型,Django Admin以及ModelForm中提供验证 Ipv4和Ipv6
    
        active = models.BooleanField(default=True)
        data01 = models.DateTimeField()                 # 日期+时间格式 YYYY-MM-DDHH:MM[:ss[.uuuuuu]][TZ
        data02 = models.DateField()                     # 日期格式 YYYY-MMDD
        data03 = models.TimeField()                     # 时间格式
        HH:MM[:ss[.uuuuuu]]
        age = models.PositiveIntegerField()                # 正小整数 0 ~ 32767
        balance = models.SmallIntegerField()             # 小整数 -32768 ~ 32767
        money = models.PositiveIntegerField()             # 正整数 0 ~ 2147483647
        bignum = models.BigIntegerField()                 # 长整型(有符号的)-9223372036854775808 ~ 9223372036854775807
        user_type_choices = (
            (1, "超级用户"),
            (2, "普通用户"),
            (3, "普普通用户"),
        )
        user_type_id = models.IntegerField(choices=user_type_choices, default=1)

    1.3 参数

    null                     # 数据库中字段是否可以为空
    blank                     # 表单验证可以为空
    default                 # 数据库中字段的默认值
    primary_key             # 数据库中字段是否为主键
    db_index                 # 数据库中字段是否可以建立索引
    unique                     # 数据库中字段是否可以建立唯一索引

    2 一对多

    2.1 一对多基本增删改查

    2.1.1 models.py
    from django.db import models 
    class UserInfo(models.Model): 
        name = models.CharField(max_length=64,unique=True) 
        ut = models.ForeignKey(to='UserType') 
        
    class UserType(models.Model): 
        type_name = models.CharField(max_length=64,unique=True)
    2.1.2 views.py
    from django.shortcuts import render,HttpResponse 
    from app01 import models 
    
    def orm(request): 
        # 1 创建 
        
        # 创建数据方法一
        models.UserInfo.objects.create(name='root', ut_id=2)
        
        # 创建数据方法二 
        obj = models.UserInfo(name='root', ut_id=2) obj.save() 
        
        # 创建数据库方法三(传入字典必须在字典前加两个星号) 
        dic = {'name': 'root', 'ut_id': 2} 
        models.UserInfo.objects.create(**dic) 
        
        # 2 删除 
        models.UserInfo.objects.all().delete()                   # 删除所有 
        models.UserInfo.objects.filter(name='root').delete()  # 删除指定 
        
        # 3 更新 
        models.UserInfo.objects.all().update(ut_id=1)
        models.UserInfo.objects.filter(name='zhangsan').update(ut_id=4) 
        
        # 4.查找 
        # 4.1 正向查找 user_obj.ut.type_name 
        print( models.UserInfo.objects.get(name='zhangsan').ut.type_name ) 
        print( models.UserInfo.objects.filter(ut__type_name='student') ) 
        
        # 4.2 反向查找 type_obj.userinfo_set.all() 
        print( models.UserType.objects.get(type_name='student').userinfo_set.all() ) 
        print( models.UserType.objects.get(type_name='student').userinfo_set.filter(name='zhangs an') )
        
        return HttpResponse('orm')

    2.2 一对多查找更多操作

    2.2.1 models.py
    from django.db import models
    class UserType(models.Model):
        user_type_name = models.CharField(max_length=32)
        def __str__(self):
            return self.user_type_name #只有加上这个,Django admin才会显示表名
        
    class User(models.Model):
        username = models.CharField(max_length=32)
        pwd = models.CharField(max_length=64)
        ut = models.ForeignKey(
        to='UserType',
        to_field='id',
        # 1、反向操作时,使用的连接前缀,用于替换【表名】
        # 如: models.UserGroup.objects.filter(a__字段名         =1).values('a__字段名')
            
        related_query_name='a',
            #2、反向操作时,使用的字段名,用于代替 【表名_set】 如: obj.b_set.all()
        # 使用时查找报错
        # related_name='b',
        )
    2.2.2 views.py
    from django.shortcuts import HttpResponse
    from app01 import models
    def orm(request):
        # 1 正向查找
        # 1.1 正向查找user表用户名    
        print(models.User.objects.get(username='zhangsan').username)                # zhangsan
        #1.2 正向跨表查找用户类型     
        print(models.User.objects.get(username='zhangsan').ut.user_type_name) #
    student
        #1.3 双下划线正向跨表正向查找
        print( models.User.objects.all().values('ut__user_type_name','username') )
        
        # 2 反向查找
        # 2.1:【表名_set】,反向查找user表中用户类型为student 的所有用户
        print( models.UserType.objects.get(user_type_name='student').user_set.all() )
        # [<User: lisi>, <User: wangwu>]
        # 2.2:【a__字段名】反向查找user表中张三在UserType表中的类型:([<UserType:
    teacher>])
        print( models.UserType.objects.filter(a__username='zhangsan') )
        # student
        # 这里的a是user表的ForeignKey字段的参数:related_query_name='a'
        # 2.3: 双下划线跨表反向查找
        print( models.UserType.objects.all().values('a__username', 'user_type_name'))
        
        # 3 自动创建User表和UserType表中的数据
        '''
        username = [{'username':'zhangsan','pwd':'123','ut_id':'1'},
        {'username':'lisi','pwd':'123','ut_id':'1'},
        {'username':'wangwu','pwd':'123','ut_id':'1'},]
        user_type = [{'user_type_name':'student'},{'user_type_name':'teacher'},]
        for type_dic in user_type:
        models.UserType.objects.create(**type_dic)
        for user_dic in username:
        models.User.objects.create(**user_dic)
        '''
        return HttpResponse('orm')

    2.3 一对多使用values和values_list结合双下划线跨表查询

    from django.shortcuts import HttpResponse
    from app01 import models
    ​
    def orm(request):
        # 第一种:values-----获取的内部是字典 拿固定列数
        # 1.1 正向查找: 使用ForeignKey字段名ut结合双下划线查询
            models.User.objects.filter(username='zhangsan').values('username',
        'ut__user_type_name')
        # 1.2 向查找: 使用ForeignKey的related_query_name='a',的字段
        models.UserType.objects.all().values('user_type_name', 'a__username')
        
        # 第二种:values_list-----获取的是元组 拿固定列数
        # 1.1 正向查找: 使用ForeignKey字段名ut结合双下划线查询
        stus = models.User.objects.filter(username='zhangsan').values_list('username','ut__user_type_name')
        # 1.2 反向查找: 使用ForeignKey的related_query_name='a',的字段
        utype = models.UserType.objects.all().values_list('user_type_name','a__username')
        
        # 3 自动创建User表和UserType表中的数据
    '''
    username = [{'username':'zhangsan','pwd':'123','ut_id':'1'},
    {'username':'lisi','pwd':'123','ut_id':'1'},
    {'username':'wangwu','pwd':'123','ut_id':'1'},]
    user_type = [{'user_type_name':'student'},{'user_type_name':'teacher'},]
    for type_dic in user_type:
    models.UserType.objects.create(**type_dic)
    for user_dic in username:
    models.User.objects.create(**user_dic)
    '''return HttpResponse('orm')

    2.4 一对多ForeignKey可选参数

    1、to,                                           # 要进行关联的表名
    2、to_field=None,                                # 要关联的表中的字段名称
    3、on_delete=None,                               # 当删除关联表中的数据时,当前表与其关
    联的行的行为
    - models.CASCADE                                 # 删除关联数据,与之关联也删除
    - models.DO_NOTHING                              # 删除关联数据,引发错误
    IntegrityError
    - models.PROTECT                                 # 删除关联数据,引发错误
    ProtectedError
    - models.SET_NULL                                # 删除关联数据,与之关联的值设置为
    null(前提FK字段需要设置为可空)
    - models.SET_DEFAULT                             # 删除关联数据,与之关联的值设置为默认值(前提FK字段需要设置默认值)
    - models.SET                                     # 删除关联数据,
    4、related_name=None                             # 反向操作时,使用的字段名,用于代替
    【表名_set】 如: obj.表名_set.all()
                                                     # 在做自关联时必须指定此字段,防止查找冲突
    5、delated_query_name=None,                      # 反向操作时,使用的连接前缀,用于替换
    【表名】
    # 如:models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名')

    3.Django多对多表结构操作

    3.1 第一种: ManyToManyField

    • 自己不创建第三张关系表,有m2m字段: 根据queryset对象增删改查(推荐)

    from django.db import models
    ​
    class UserInfo(models.Model):
        username = models.CharField(max_length=32)
        def __str__(self):
            return self.username
    ​
        
    class UserGroup(models.Model):
        group_name = models.CharField(max_length=64)
        user_info = models.ManyToManyField(to='UserInfo',related_query_name='m2m')
        
        def __str__(self):
            return self.group_name
    • 查询

    from django.shortcuts import HttpResponse
    from app01 import models
    ​
    def orm(request):
        user_info_obj = models.UserInfo.objects.get(username='zhangsan')
        user_info_objs = models.UserInfo.objects.all()
        group_obj = models.UserGroup.objects.get(group_name='group_python')
    ​
        自己创建第三张关系表,无 m2m 字段,自己链表查询
        group_objs = models.UserGroup.objects.all()
        # 添加: 正向
        group_obj.user_info.add(user_info_obj)
        group_obj.user_info.add(*user_info_objs)
        # 删除:正向
        group_obj.user_info.remove(user_info_obj)
        group_obj.user_info.remove(*user_info_objs)
        # 添加: 反向
        user_info_obj.usergroup_set.add(group_obj)
        user_info_obj.usergroup_set.add(*group_objs)
        # 删除:反向
        user_info_obj.usergroup_set.remove(group_obj)
        user_info_obj.usergroup_set.remove(*group_objs)
        # 查找:正向
        print(group_obj.user_info.all()) # 查找
        group_python组中所有用户
        print(group_obj.user_info.all().filter(username='zhangsan'))
        # 查找:反向
        print(user_info_obj.usergroup_set.all()) # 查找用户
        zhangsan属于那些组
        print(user_info_obj.usergroup_set.all().filter(group_name='group_python'))
        # 双下划线 正向、反向查找
        # 正向:从用户组表中查找zhangsan属于哪个用户组:[<UserGroup: group_python>]
        print( models.UserGroup.objects.filter(user_info__username='zhangsan'))
        # 反向:从用户表中查询group_python组中有哪些用户:related_query_name='m2m'
        print( models.UserInfo.objects.filter(m2m__group_name='group_python'))
        # 自动创建UserInfo表和UserGroup表中的数据
    '''
    user_list = [{'username':'zhangsan'},
    {'username':'lisi'},
    {'username':'wangwu'},]
    group_list = [{'group_name':'group_python'},
    {'group_name':'group_linux'},
    {'group_name':'group_mysql'},]
    for c in user_list:
    models.UserInfo.objects.create(**c)
    for l in group_list:
    models.UserGroup.objects.create(**l)
    '''return HttpResponse('orm')

    3.2 第二种: 自己创建第三张表

    • 自己创建第三张关系表,无 m2m 字段,自己链表查询

    from django.db import models
    ​
    #表1:主机表
    class Host(models.Model):
        nid = models.AutoField(primary_key=True)
        hostname = models.CharField(max_length=32,db_index=True)
    #表2:应用表
    class Application(models.Model):
        name = models.CharField(max_length=32)
    #表3:自定义第三张关联表
    class HostToApp(models.Model):
        hobj = models.ForeignKey(to="Host",to_field="nid")
        aobj = models.ForeignKey(to='Application',to_field='id')
    # 向第三张表插入数据,建立多对多外键关联
    HostToApp.objects.create(hobj_id=1,aobj_id=2)

    3.3 多对多双下划线查找

    from django.shortcuts import HttpResponse
    from app01 import models
    ​
    def orm(request):
        # 第一种:values-----获取的内部是字典,拿固定列数
        # 1.1 正向查找: 使用ManyToManyField字段名user_info结合双下划线查询
        models.UserGroup.objects.filter(group_name='group_python').values('group_name',
        'user_info__username')
        # 1.2 反向查找: 使用ManyToManyField的related_query_name='m2m',的字段
        models.UserInfo.objects.filter(username='zhangsan').values('username',
        'm2m__group_name')
        
        # 第二种:values_list-----获取的是元组 拿固定列数
        # 2.1 正向查找: 使用ManyToManyField字段名user_info结合双下划线查询
        models.UserGroup.objects.filter(group_name='group_python').values_list('group_na
        me', 'user_info__username')
        # 2.2 反向查找: 使用ManyToManyField的related_query_name='m2m',的字段
        lesson =
        models.UserInfo.objects.filter(username='zhangsan').values_list('username',
        'm2m__group_name')
                                                                               
            # 自动创建UserInfo表和UserGroup表中的数据
            '''
            # user_info_obj = models.UserInfo.objects.get(username='lisi')
            # user_info_objs = models.UserInfo.objects.all()
            #
            # group_obj = models.UserGroup.objects.get(group_name='group_python')
            # group_objs = models.UserGroup.objects.all()
            # group_obj.user_info.add(*user_info_objs)
            # user_info_obj.usergroup_set.add(*group_objs)
            user_list = [{'username':'zhangsan'},
            {'username':'lisi'},
            {'username':'wangwu'},]
            group_list = [{'group_name':'group_python'},
            {'group_name':'group_linux'},
            {'group_name':'group_mysql'},]
            for c in user_list:
            models.UserInfo.objects.create(**c)
            for l in group_list:
            models.UserGroup.objects.create(**l)
            '''
        return HttpResponse('orm')

    3.4 创建m2m多对多时ManyToManyField可以添加的参数

    1、to,                       # 要进行关联的表名
    2、related_name=None,        # 反向操作时,使用的字段名,用于代替 【表名_set】如: obj.
    表名_set.all()
    3、related_query_name=None,  # 反向操作时,使用的连接前缀,用于替换【表名】

    4 model相关操作

    4.1 基础查询语句

    from django.shortcuts import HttpResponse
    from app01 import models
    ​
    def orm(request):
        # 1 创建
        # 创建数据方法一
        models.UserInfo.objects.create(username='root', password='123')
        # 创建数据方法二
        obj = models.UserInfo(username='alex', password='123')
        obj.save()
        # 创建数据库方法三(传入字典必须在字典前加两个星号)
        dic = {'username': 'eric', 'password': '666'}
        models.UserInfo.objects.create(**dic)
        
        # 2 查
        result = models.UserInfo.objects.all() # 查找所有条目
        result = models.UserInfo.objects.filter(username='alex', password='123')
        for row in result:
        print(row.id, row.username, row.password)
        
        # 3 删除
        models.UserInfo.objects.all().delete() # 删除所有
        models.UserInfo.objects.filter(username='alex').delete() # 删除指定
        
        # 4 更新
        models.UserInfo.objects.all().update(password='12345')
        models.UserInfo.objects.filter(id=4).update(password='15')
        
        # 5 获取个数
        models.UserInfo.objects.filter(name='seven').count()
        
        # 6 执行原生SQL
        # 6.1 执行原生SQL
        models.UserInfo.objects.raw('select * from userinfo')
        # 6.2 如果SQL是其他表时,必须将名字设置为当前UserInfo对象的主键列名
        models.UserInfo.objects.raw('select id as nid from 其他表')
        # 6.3 指定数据库
        
        models.UserInfo.objects.raw('select * from userinfo', using="default")
        
        return HttpResponse('orm')

    4.2 进阶操作:双下划线

    1、大于,小于
            # models.Tb1.objects.filter(id__gt=1) # 获取id大于1的值
            # models.Tb1.objects.filter(id__gte=1) # 获取id大于等于1的值
            # models.Tb1.objects.filter(id__lt=10) # 获取id小于10的值
            # models.Tb1.objects.filter(id__lte=10) # 获取id小于等于10的值
            # models.Tb1.objects.filter(id__lt=10, id__gt=1) # 获取id大于1 且 小于10的值
    2、in
            # models.Tb1.objects.filter(id__in=[11, 22, 33]) # 获取id等于11、22、33的数据
            # models.Tb1.objects.exclude(id__in=[11, 22, 33]) # not in
        
    3、isnull
            # Entry.objects.filter(pub_date__isnull=True) #双下划线isnull,查找
            pub_date是null的数据
            
    4、contains #就是原生sql的like操作:模糊匹配
            # models.Tb1.objects.filter(name__contains="ven")
            # models.Tb1.objects.filter(name__icontains="ven") # icontains大小写不敏感
            # models.Tb1.objects.exclude(name__icontains="ven")
            
    5、range
            # models.Tb1.objects.filter(id__range=[1, 2]) # 范围bettwen and
    6、order by
            # models.Tb1.objects.filter(name='seven').order_by('id') # asc没有减号升续排列
            # models.Tb1.objects.filter(name='seven').order_by('-id') # desc有减号升续排列
    7、group by
            # from django.db.models import Count, Min, Max, Sum
            # models.Tb1.objects.filter(c1=1).values('id').annotate(c=Count('num'))
            #根据id列进行分组
            # SELECT "app01_tb1"."id", COUNT("app01_tb1"."num") AS "c" FROM "app01_tb1"
            # WHERE "app01_tb1"."c1" = 1 GROUP BY "app01_tb1"."id"
    8、limit 、offset #分页
            # models.Tb1.objects.all()[10:20]
    9、regex正则匹配,iregex 不区分大小写
            # Entry.objects.get(title__regex=r'^(An?|The) +')
            # Entry.objects.get(title__iregex=r'^(an?|the) +')
    10、date
            # Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1))
            #__data表示日期查找,2005-01-01
            # Entry.objects.filter(pub_date__date__gt=datetime.date(2005, 1, 1))
            # 2005-01-01以后创建的数据
    11、year
            # Entry.objects.filter(pub_date__year=2005)
            #__year根据年查找
            # Entry.objects.filter(pub_date__year__gte=2005)
    12、month
            # Entry.objects.filter(pub_date__month=12)
            # Entry.objects.filter(pub_date__month__gte=6)
    13、day
            # Entry.objects.filter(pub_date__day=3)
            # Entry.objects.filter(pub_date__day__gte=3)
    14、week_day
            # Entry.objects.filter(pub_date__week_day=2)
            # Entry.objects.filter(pub_date__week_day__gte=2)
    15、hour
            # Event.objects.filter(timestamp__hour=23)
            # Event.objects.filter(time__hour=5)
            # Event.objects.filter(timestamp__hour__gte=12)
    16、minute
            # Event.objects.filter(timestamp__minute=29)
            # Event.objects.filter(time__minute=46)
            # Event.objects.filter(timestamp__minute__gte=29)
    17、second
            # Event.objects.filter(timestamp__second=31)
            # Event.objects.filter(time__second=2)
            # Event.objects.filter(timestamp__second__gte=31)

    4.3 时间查询

    from django.utils import timezone
    from report.models import *
    ​
    now = timezone.now()
    # start_time = now - timezone.timedelta(days=7)
    start_time = now - timezone.timedelta(hours=240) # 查询10天前的数据
    end_time = now
    ​
    qs = AllClarm.objects.filter(start_tm__range=(start_time, end_time))

    4.4 F查询和Q查询

    4.4.1 F查询
    • 作用:F()允许Django在未实际链接数据的情况下具有对数据库字段的值的引用

    from django.shortcuts import HttpResponse
    from app01 import models
    from django.db.models import F,Q
    ​
    def orm(request):
        # 每访问一次数据库中zhangsan的年纪就会自动增加1
        models.Student.objects.filter(name='zhangsan').update(age=F("age") + 1)
        # 自动生成Student表中数据
        '''
        stu_list = [{'name':'zhangsan','age':11},
        {'name': 'lisi', 'age': 22},
        {'name': 'wangwu', 'age': 33},]
        for u in stu_list:
        models.Student.objects.create(**u)
        '''
        return HttpResponse('orm')
    4.4.2 Q查询
    • Q对象( django.db.models.Q )可以对关键字参数进行封装,从而更好地应用多个查询

    • 可以组合使用 &(and),|(or),~(not)操作符,当一个操作符用于两个Q的对象,它产生一 个新的Q对象

    • 如: Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')

    from django.shortcuts import HttpResponse
    from app01 import models
    from django.db.models import F,Q
    ​
    def orm(request):
            # 查找学生表中年级大于1小于30姓zhang的所有学生
            stus = models.Student.objects.filter(
                Q(age__gt=1) & Q(age__lt=30),
                Q(name__startswith='zhang')
            )
            print('stu',stus) #运行结果:[<Student: zhangsan>]
            # 自动生成Student表中数据
            '''
            stu_list = [{'name':'zhangsan','age':11},
            {'name': 'lisi', 'age': 22},
            {'name': 'wangwu', 'age': 33},]
            for u in stu_list:
            models.Student.objects.create(**u)
            '''
            return HttpResponse('orm')

    5 aggregate&annotate聚合函数

    5.1 aggregate聚合函数

    • 作用:从数据库中取出一个汇总的集合

    from django.db.models import Count,Avg,Max,Sum
    def orm(request):
        stus = models.Student.objects.aggregate(
        stu_num=Count('age'), #计算学生表中有多少条age条目
        stu_avg=Avg('age'), #计算学生的平均年纪
        stu_max=Max('age'), #找到年纪最大的学生
        stu_sum=Sum('age')) #将表中的所有年纪相加
        print('stu',stus)
        return HttpResponse('ok')
        #运行结果:{'stu_sum': 69, 'stu_max': 24, 'stu_avg': 23.0, 'stu_num': 3}

    5.2 annotate实现聚合group by查询

    • 作用:对查询结果进行分组,比如分组求出各年龄段的人数

    • 注: annotate后面加filter过滤相当于原生sql语句中的having

    from django.db.models import Count, Avg, Max, Min, Sum
    def orm(request):
            #1 按年纪分组查找学生表中各个年龄段学生人数:(22岁两人,24岁一人)
            # 查询结果:[{'stu_num': 2, 'age': 22}, {'stu_num': 1, 'age': 24}]
            stus1 = models.Student.objects.values('age').annotate(stu_num=Count('age'))
            
            #2 按年纪分组查找学生表中各个年龄段学生人数,并过滤出年纪大于22的:
            # 查询结果:[{'stu_num': 1, 'age': 24}] (年级大于22岁的仅一人,年级为24岁)
            stus2 =models.Student.objects.values('age').annotate(stu_num=Count('age')).filter(age__gt=22)
            
            #3 先按年纪分组,然后查询出各个年龄段学生的平均成绩
            # 查询结果:[{'stu_Avg': 86.5, 'age': 22}, {'stu_Avg': 99.0, 'age': 24}]
            # 22岁平均成绩:86.5 24岁平均成绩:99
            stus3 = models.Student.objects.values('age').annotate(stu_Avg=Avg('grade'))
            
            return HttpResponse('ok')
  • 相关阅读:
    基于Python的人脸动漫转换
    let 与 var的区别
    【LeetCode】汇总
    【HDU】4632 Palindrome subsequence(回文子串的个数)
    【算法】均匀的生成圆内的随机点
    【LeetCode】725. Split Linked List in Parts
    【LeetCode】445. Add Two Numbers II
    【LeetCode】437. Path Sum III
    【LeetCode】222. Count Complete Tree Nodes
    【LeetCode】124. Binary Tree Maximum Path Sum
  • 原文地址:https://www.cnblogs.com/mapel1594184/p/13893331.html
Copyright © 2020-2023  润新知