zoukankan      html  css  js  c++  java
  • Django(八)上:Model操作和Form操作

    ↑↑↑点上面的”+”号展开目录

    Model和Form以及ModelForm简介

    • Model操作:
      • 创建数据库表结构
      • 操作数据库表
      • 做一部分的验证
    • Form操作:
      • 数据验证(强大)
    • ModelForm
      • 数据库操作
      • 数据验证

    admin 登录验证,先经过ModelForm,在经过Model。

    error_message字段之所以有的model里中午改了,前端不生效,因为先经过ModelForm验证

    一、Model操作补充

    1. 创建数据库表

    • 单表
    class User(models.Model):
        name = models.CharField(max_length=32)
        pwd = models.CharField(max_length=32)
    
        class Meta: ########## 元信息 ###########
            # 数据库中生成的表名称 默认 app名称 + 下划线 + 类名
            db_table = "tb1"     # 自定义表名 
    
            index_together = [  # 联合索引
                ("name", 'pwd'),
            ]
              # 遵循最左前缀的匹配模式:
              # select * from where name='xx'                # 命中索引
              # select * from where name='xx' and pwd = 'xx' # 命中索引
              # select * from where pwd = 'xx'               # 无法命中索引
    
            # 联合唯一索引
            unique_together = (("driver", "restaurant"),)
    
            # admin中显示的表名称 (verbose_name加s)
            verbose_name = "上课记录"       # ==> 上课记录s
    
            verbose_name_plural="上课记录"  # ==> 上课记录

    更多:https://docs.djangoproject.com/en/1.10/ref/models/options/

    • 一对多/一对一/多对多
    一对多:models.ForeignKey(其他表)
    多对多:models.ManyToManyField(其他表)
    一对一:models.OneToOneField(其他表)
    • 一对一

    一对一场景,比如网站一个用户只允许开通一个博客。就需要对两张表一对一。

    一对一两个约束:外键约束;唯一索引约束。

    OneToOne 继承 ForeignKey,所以ForeignKey的用法在OneToOne里都适用

    • 一对多
    def func():
        return 5
    
    class UserType(models.Model):
        name = models.CharField(max_length=32)
    
    class User(models.Model):
        name = models.CharField(max_length=32)
        pwd = models.CharField(max_length=32)
        fk = models.ForeignKey(to="UserType",to_field='id',on_delete=models.SET(func))
        # delete from user where id=1
        # delete from UserType where id=1 # 报错
    
        # UserType.objects.filter(id=1).delete()
        # Django现在的版本里,不报错,会把跟它相关的数据都删除。

    字段以及参数

    to,               # 要进行关联的表名
    to_field=None,    # 要关联的表中的字段名称
    on_delete=None,   # 当删除关联表中的数据时,当前表与其关联的行的行为
        - models.CASCADE,    #删除关联数据,与之关联也删除
        - models.DO_NOTHING, #删除关联数据,引发错误IntegrityError(数据库抛出异常)
        - models.PROTECT,    #删除关联数据,引发错误ProtectedError(Django抛出异常)
        - models.SET_NULL,   #删除关联数据,与之关联的值设置为null(前提FK字段需要设置为可空)
        - models.SET_DEFAULT,#删除关联数据,与之关联的值设置为默认值(前提FK字段需要设置默认值)
        - models.SET,        #删除关联数据,设置为指定的值
              a. 与之关联的值设置为指定值,设置:models.SET(值)
              b. 与之关联的值设置为可执行对象的返回值,设置:models.SET(可执行对象)

    ForeignKey 正向操作与反向操作

    # 正向操作
        v = User.objects.all()
        for item in v:
            item.user
            item.pwd
            item.fk.name                              # <====
    
        User.objects.all().values('user','fk__name')  # <====
    
    # 反向操作
        v = UserType.objects.all()
        for item in v:
            item.name
            item.id
            item.user_set.all()  # <== xx_set 反向查找# <====
    
        models.UserType.objects.all().values('name','user__pwd') # <====
    
        # 不使用xx_set,自定义如下:
        fk = models.ForiegnKey(to="UserType",to_field='id',related_name="b")

    related_name:可用在表foreignkey自己时,确定谁关联了自己。

     related_name=None,  # 反向操作时,使用的字段名,用于代替 【表名_set】 如: obj.表名_set.all()
     related_query_name=None,# 反向操作时,使用的连接前缀,用于替换【表名】     如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名')

    在Admin或ModelForm中显示关联数据时,提供的条件

    limit_choices_to=None,    # 在Admin或ModelForm中显示关联数据时,提供的条件:
                     # 例如:
    models.ForeignKey(to="UserType",to_field='id',limit_choices_to={'nid__gt': 5})
                        - limit_choices_to={'nid__gt': 5}
                        - limit_choices_to=lambda : {'nid__gt': 5}
    
                        from django.db.models import Q
                        - limit_choices_to=Q(nid__gt=10)
                        - limit_choices_to=Q(nid=8) | Q(nid__gt=10)
                        - limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')

    示例:

    app下,编辑admin.py

    from cmdb import models
    
    admin.site.register(models.UserType)
    admin.site.register(models.User)

    创建超级用户

    python manage.py createsuperuser

    Django admin登录,显示为对象,让显示名称,如下:

    class UserType(models.Model):
        name = models.CharField(max_length=32)
    
        def __str__(self):
            return self.name

    limit_choices_to 就是对admin网页里下拉框的值的筛选

    db_constraint=True  # 是否在数据库中创建外键约束,false时虽是foreignkey,但不约束
    parent_link=False   # 在Admin中是否显示关联数据
    • 多对多
    symmetrical=None,   # 仅用于多对多自关联时,symmetrical用于指定内部是否创建反向操作的字段
                           # 做如下操作时,不同的symmetrical会有不同的可选字段
                                models.BB.objects.filter(...)
    
    # 可选字段有:id, code, m1
    class BB(models.Model):
        code = models.CharField(max_length=12)
        m1 = models.ManyToManyField('self',symmetrical=True)
    
    # 可选字段有: bb, id, code, m1
    class BB(models.Model):
        code = models.CharField(max_length=12)
        m1 = models.ManyToManyField('self',symmetrical=False)
                a. django创建第三张表
                    m2m.remove
                    m2m.add
                    m2m.set
                    m2m.clear
                    m2m.filter()
                b. 自定义第三张表(无m2m字段)
    
                    自己链表查询
    
                c. 自定义第三张表(有m2m字段)
                    # 通过m2m字段 "查" 操作
                    # 通过m2m字段 clear
    through=None,               # 自定义第三张表时,使用字段用于指定关系表
    through_fields=None,        # 自定义第三张表时,使用字段用于指定关系表中那些字段做多对多关系表
    
        class Person(models.Model):
            name = models.CharField(max_length=50)
    
        class Group(models.Model):
            name = models.CharField(max_length=128)
            members = models.ManyToManyField(
                Person,
                through='Membership',
                through_fields=('group', 'person'),
            )
    
        class Membership(models.Model):
            group = models.ForeignKey(Group, on_delete=models.CASCADE)
            person = models.ForeignKey(Person, on_delete=models.CASCADE)
            inviter = models.ForeignKey(
                Person,
                on_delete=models.CASCADE,
                related_name="membership_invites",
            )
            invite_reason = models.CharField(max_length=64)     
        db_constraint=True,         # 是否在数据库中创建外键约束
        db_table=None,              # 默认创建第三张表时,数据库中表的名称

    2、数据库操作补充之基本操作

    1、基本操作

    #
        #
        # models.Tb1.objects.create(c1='xx', c2='oo')  增加一条数据,可以接受字典类型数据 **kwargs
    
        # obj = models.Tb1(c1='xx', c2='oo')
        # obj.save()
    
        #
        #
        # models.Tb1.objects.get(id=123)         # 获取单条数据,不存在则报错(不建议)
        # models.Tb1.objects.all()               # 获取全部
        # models.Tb1.objects.filter(name='seven') # 获取指定条件的数据
    
        #
        #
        # models.Tb1.objects.filter(name='seven').delete() # 删除指定条件的数据
    
        #
        # models.Tb1.objects.filter(name='seven').update(gender='0')  # 将指定条件的数据更新,均支持 **kwargs
        # obj = models.Tb1.objects.get(id=1)
        # obj.c1 = '111'
        # obj.save()                                                 # 修改单条数据

    2、进阶操作(了不起的双下划线)

    利用双下划线将字段和对应的操作连接起来

    # 获取个数
            #
            # models.Tb1.objects.filter(name='seven').count()
    
            # 大于,小于
            #
            # 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的值
    
            # 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
    
            # isnull
            # Entry.objects.filter(pub_date__isnull=True)
    
            # contains
            #
            # models.Tb1.objects.filter(name__contains="ven")
            # models.Tb1.objects.filter(name__icontains="ven") # icontains大小写不敏感
            # models.Tb1.objects.exclude(name__icontains="ven")
    
            # range
            #
            # models.Tb1.objects.filter(id__range=[1, 2])   # 范围bettwen and
    
            # 其他类似
            #
            # startswith,istartswith, endswith, iendswith,
    
            # order by
            #
            # models.Tb1.objects.filter(name='seven').order_by('id')    # asc
            # models.Tb1.objects.filter(name='seven').order_by('-id')   # desc
    
            # group by
            #
            # from django.db.models import Count, Min, Max, Sum
            # models.Tb1.objects.filter(c1=1).values('id').annotate(c=Count('num'))
            # SELECT "app01_tb1"."id", COUNT("app01_tb1"."num") AS "c" FROM "app01_tb1" WHERE "app01_tb1"."c1" = 1 GROUP BY "app01_tb1"."id"
    
            # limit 、offset
            #
            # models.Tb1.objects.all()[10:20]
    
            # regex正则匹配,iregex 不区分大小写
            #
            # Entry.objects.get(title__regex=r'^(An?|The) +')
            # Entry.objects.get(title__iregex=r'^(an?|the) +')
    
            # date
            #
            # Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1))
            # Entry.objects.filter(pub_date__date__gt=datetime.date(2005, 1, 1))
    
            # year
            #
            # Entry.objects.filter(pub_date__year=2005)
            # Entry.objects.filter(pub_date__year__gte=2005)
    
            # month
            #
            # Entry.objects.filter(pub_date__month=12)
            # Entry.objects.filter(pub_date__month__gte=6)
    
            # day
            #
            # Entry.objects.filter(pub_date__day=3)
            # Entry.objects.filter(pub_date__day__gte=3)
    
            # week_day
            #
            # Entry.objects.filter(pub_date__week_day=2)
            # Entry.objects.filter(pub_date__week_day__gte=2)
    
            # hour
            #
            # Event.objects.filter(timestamp__hour=23)
            # Event.objects.filter(time__hour=5)
            # Event.objects.filter(timestamp__hour__gte=12)
    
            # minute
            #
            # Event.objects.filter(timestamp__minute=29)
            # Event.objects.filter(time__minute=46)
            # Event.objects.filter(timestamp__minute__gte=29)
    
            # second
            #
            # Event.objects.filter(timestamp__second=31)
            # Event.objects.filter(time__second=2)
            # Event.objects.filter(timestamp__second__gte=31)

    3、高级操作

    像下面的语句,上面的功能是不能实现的

    select id, name, 1, 
            func(id), 
            select name from tb2 where nid = id 
    from tb1;
    Entry.objects.filter().extra(select={'cid':"1"})    # 功能如同一下sql语句
    select …… , 1 as cid from tb1
    Entry.objects.filter().extra(select={'cid':"%s"},select_params=[1])
    # %s 被替换为 1
        # extra
        #
        # extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None)
        #    Entry.objects.extra(select={'new_id': "select col from sometable where othercol > %s"}, select_params=(1,))
        # ==> select * (select name from tb2 where nid = id) as new_id from tb1;
        #    Entry.objects.extra(select={'new_id':"func()id"})  # 支持mysql的函数
    
    # 支持里面where操作 (多个条件时“,”逗号间隔为and,“or” or)         
        #    Entry.objects.extra(where=['headline=%s'], params=['Lennon'])
        #    Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"])
        #    Entry.objects.extra(select={'new_id': "select id from tb where id > %s"}, select_params=(1,), order_by=['-nid'])
    
        # F
        #
        # from django.db.models import F
        # models.Tb1.objects.update(num=F('num')+1)
    
        # Q
        #
        # 方式一:
        # Q(nid__gt=10)
        # Q(nid=8) | Q(nid__gt=10)
        # Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')
        # 方式二:
        # con = Q()
        # q1 = Q()
        # q1.connector = 'OR'
        # q1.children.append(('id', 1))
        # q1.children.append(('id', 10))
        # q1.children.append(('id', 9))
        # q2 = Q()
        # q2.connector = 'OR'
        # q2.children.append(('c1', 1))
        # q2.children.append(('c1', 10))
        # q2.children.append(('c1', 9))
        # con.add(q1, 'AND')
        # con.add(q2, 'AND')
        #
        # models.Tb1.objects.filter(con)
    
        # 执行原生SQL
        #
        # from django.db import connection, connections
        # cursor = connection.cursor()  # cursor = connections['default'].cursor()
        # cursor.execute("""SELECT * from auth_user where id = %s""", [1])
        # row = cursor.fetchone()

    4、其他操作

    ##################################################################
    # PUBLIC METHODS THAT ALTER ATTRIBUTES AND RETURN A NEW QUERYSET #
    ##################################################################
    
    def all(self)
        # 获取所有的数据对象
    
    def filter(self, *args, **kwargs)
        # 条件查询
        # 条件可以是:参数,字典,Q
    
    def exclude(self, *args, **kwargs)
        # 条件查询
        # 条件可以是:参数,字典,Q
    
    def select_related(self, *fields)
         性能相关:表之间进行join连表操作,一次性获取关联的数据。
         model.tb.objects.all().select_related()
         model.tb.objects.all().select_related('外键字段')
         model.tb.objects.all().select_related('外键字段__外键字段')
    
    def prefetch_related(self, *lookups)
        性能相关:多表连表操作时速度会慢,使用其执行多次SQL查询在Python代码中实现连表操作。
                # 获取所有用户表
                # 获取用户类型表where id in (用户表中的查到的所有用户ID)
                models.UserInfo.objects.prefetch_related('外键字段')
    
    
    
                from django.db.models import Count, Case, When, IntegerField
                Article.objects.annotate(
                    numviews=Count(Case(
                        When(readership__what_time__lt=treshold, then=1),
                        output_field=CharField(),
                    ))
                )
    
                students = Student.objects.all().annotate(num_excused_absences=models.Sum(
                    models.Case(
                        models.When(absence__type='Excused', then=1),
                    default=0,
                    output_field=models.IntegerField()
                )))
    
    def annotate(self, *args, **kwargs)
        # 用于实现聚合group by查询
    
        from django.db.models import Count, Avg, Max, Min, Sum
    
        v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id'))
        # SELECT u_id, COUNT(ui) AS `uid` FROM UserInfo GROUP BY u_id
    
        v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id')).filter(uid__gt=1)
        # SELECT u_id, COUNT(ui_id) AS `uid` FROM UserInfo GROUP BY u_id having count(u_id) > 1
    
        v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id',distinct=True)).filter(uid__gt=1)
        # SELECT u_id, COUNT( DISTINCT ui_id) AS `uid` FROM UserInfo GROUP BY u_id having count(u_id) > 1
    
    def distinct(self, *field_names)
        # 用于distinct去重
        models.UserInfo.objects.values('nid').distinct()
        # select distinct nid from userinfo
    
        注:只有在PostgreSQL中才能使用distinct进行去重
    
    def order_by(self, *field_names)
        # 用于排序
        models.UserInfo.objects.all().order_by('-id','age')
    
    def extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None)
        # 构造额外的查询条件或者映射,如:子查询
    
        Entry.objects.extra(select={'new_id': "select col from sometable where othercol > %s"}, select_params=(1,))
        Entry.objects.extra(where=['headline=%s'], params=['Lennon'])
        Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"])
        Entry.objects.extra(select={'new_id': "select id from tb where id > %s"}, select_params=(1,), order_by=['-nid'])
    
     def reverse(self):
        # 倒序
        models.UserInfo.objects.all().order_by('-nid').reverse()
        # 注:如果存在order_by,reverse则是倒序,如果多个排序则一一倒序
    
    
     def defer(self, *fields):
        models.UserInfo.objects.defer('username','id')
        或
        models.UserInfo.objects.filter(...).defer('username','id')
        #映射中排除某列数据
    
     def only(self, *fields):
        #仅取某个表中的数据
         models.UserInfo.objects.only('username','id')
         或
         models.UserInfo.objects.filter(...).only('username','id')
    
     def using(self, alias):
         指定使用的数据库,参数为别名(setting中的设置)
    
    
    ##################################################
    # PUBLIC METHODS THAT RETURN A QUERYSET SUBCLASS #
    ##################################################
    
    def raw(self, raw_query, params=None, translations=None, using=None):
        # 执行原生SQL,获取queryset对象
        models.UserInfo.objects.raw('select * from userinfo')
    
        # 如果SQL是其他表时,必须将名字设置为当前UserInfo对象的主键列名
        models.UserInfo.objects.raw('select id as nid from 其他表')
    
        # 为原生SQL设置参数
        models.UserInfo.objects.raw('select id as nid from userinfo where nid>%s', params=[12,])
    
        # 将获取的到列名转换为指定列名
        dic = {'first': 'first_name', 'last': 'last_name', 'bd': 'birth_date', 'pk': 'id'}
        tb.objects.raw('select nid,user,email from tb2', dic)
        tb.objects.raw('SELECT * FROM some_other_table', translations=dic)
    
        # 指定数据库
        models.UserInfo.objects.raw('select * from userinfo', using="default")
    
        ################### 原生SQL ###################
        from django.db import connection, connections
        cursor = connection.cursor()  # cursor = connections['default'].cursor()
        cursor.execute("""SELECT * from auth_user where id = %s""", [1])
        row = cursor.fetchone() # fetchall()/fetchmany(..)
    
    
    def values(self, *fields):
        # 获取每行数据为字典格式
    
    def values_list(self, *fields, **kwargs):
        # 获取每行数据为元祖
    
    def dates(self, field_name, kind, order='ASC'):
        # 根据时间进行某一部分进行去重查找并截取指定内容
        # kind只能是:"year"(取 年), "month"(取 年-月), "day"(取 年-月-日)
        # order只能是:"ASC"  "DESC"
        # 并获取转换后的时间
            - year : 年-01-01
            - month: 年-月-01
            - day  : 年-月-日
    
        models.DatePlus.objects.dates('ctime','day','DESC')
    
    def datetimes(self, field_name, kind, order='ASC', tzinfo=None):
        # 时区问题。
        # 根据时间进行某一部分进行去重查找并截取指定内容,将时间转换为指定时区时间
        # kind只能是 "year", "month", "day", "hour", "minute", "second"
        # order只能是:"ASC"  "DESC"
        # tzinfo时区对象
        models.DDD.objects.datetimes('ctime','hour',tzinfo=pytz.UTC)
        models.DDD.objects.datetimes('ctime','hour',tzinfo=pytz.timezone('Asia/Shanghai'))
    
        """ 需要先安装 pytz模块
        pip3 install pytz
        import pytz
        pytz.all_timezones
        pytz.timezone(‘Asia/Shanghai’)
        """
    
    def none(self):
        # 空QuerySet对象
    
    
    ####################################
    # METHODS THAT DO DATABASE QUERIES #
    ####################################
    
    def aggregate(self, *args, **kwargs):
       # 聚合函数,获取字典类型聚合结果
       from django.db.models import Count, Avg, Max, Min, Sum
       result = models.UserInfo.objects.aggregate(k=Count('u_id', distinct=True), n=Count('nid'))
        # distinct=True 代表先去重再聚合
       ===> select count(nid) as n from userinfo;   {'k': 3, 'n': 4}
    
    def count(self):
       # 获取个数
    
    def get(self, *args, **kwargs):
       # 获取单个对象
    
    def create(self, **kwargs):
       # 创建对象
    
    def bulk_create(self, objs, batch_size=None):
        # 批量插入
        # batch_size表示一次插入的个数
        objs = [
            models.DDD(name='r11'),
            models.DDD(name='r22')
        ]
        models.DDD.objects.bulk_create(objs, 10)  # 10 表示一次插入10条
    
    def get_or_create(self, defaults=None, **kwargs):
        # 如果存在,则获取,否则,创建
        # defaults 指定创建时,其他字段的值
        obj, created = models.UserInfo.objects.get_or_create(username='root1', defaults={'email': '1111111','u_id': 2, 't_id': 2})
    
    def update_or_create(self, defaults=None, **kwargs):
        # 如果存在,则更新,否则,创建
        # defaults 指定创建时或更新时的其他字段
        obj, created = models.UserInfo.objects.update_or_create(username='root1', defaults={'email': '1111111','u_id': 2, 't_id': 1})
    
    def first(self):
       # 获取第一个
    
    def last(self):
       # 获取最后一个
    
    def in_bulk(self, id_list=None):
       # 根据主键ID进行查找
       id_list = [11,21,31]
       models.DDD.objects.in_bulk(id_list)
    
    def delete(self):
       # 删除
    
    def update(self, **kwargs):
        # 更新
    
    def exists(self):
       # 是否有结果

    5、连表操作(了不起的双下划线)

    利用双下划线和 _set 将表之间的操作连接起来

    表结构实例

    class UserProfile(models.Model):
        user_info = models.OneToOneField('UserInfo')
        username = models.CharField(max_length=64)
        password = models.CharField(max_length=64)
    
        def __unicode__(self):
            return self.username
    
    class UserInfo(models.Model):
        user_type_choice = (
            (0, u'普通用户'),
            (1, u'高级用户'),
        )
        user_type = models.IntegerField(choices=user_type_choice)
        name = models.CharField(max_length=32)
        email = models.CharField(max_length=32)
        address = models.CharField(max_length=128)
    
        def __unicode__(self):
            return self.name
    
    class UserGroup(models.Model):
    
        caption = models.CharField(max_length=64)
    
        user_info = models.ManyToManyField('UserInfo')
    
        def __unicode__(self):
            return self.caption
    
    class Host(models.Model):
        hostname = models.CharField(max_length=64)
        ip = models.GenericIPAddressField()
        user_group = models.ForeignKey('UserGroup')
    
        def __unicode__(self):
            return self.hostname

    一对一操作

    user_info_obj = models.UserInfo.objects.filter(id=1).first()
    print user_info_obj.user_type
    print user_info_obj.get_user_type_display()
    print user_info_obj.userprofile.password
    
    user_info_obj = models.UserInfo.objects.filter(id=1).values('email', 'userprofile__username').first()
    print user_info_obj.keys()
    print user_info_obj.values()

    一对多

    1、搜索条件使用 __ 连接
    2、获取值时使用 .    连接

    多对多

    user_info_obj = models.UserInfo.objects.get(name='u')
    user_info_objs = models.UserInfo.objects.all()
    
    group_obj = models.UserGroup.objects.get(caption='CEO')
    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()
    #print group_obj.user_info.all().filter(id=1)
    
    # 获取数据
    #print user_info_obj.usergroup_set.all()
    #print user_info_obj.usergroup_set.all().filter(caption='CEO')
    #print user_info_obj.usergroup_set.all().filter(caption='DBA')

    6、性能相关

    在上面其他操作里提到的 select_relatedprefetch_related是和MySQL优化、性能相关的,是需要掌握的。

    # (默认)不优化的情况下,users有多少条数据,会重复发多少次+1次sql请求
        users = models.User.objects.all()
        for row in users:
            print(row.user,row.pwd,row.ut_id)
            print(row.ut.name)   # 再发起一次SQL请求
    
    # 使用下面的方式跨表取数据,不会发起那么多次请求(缺点:取到的是字典,不是对象)
        # .values,.values_list,取到的值不是queryset对象,不支持链式编程了
        users = models.User.objects.all().values('user','pwd','ut__name')
    
    # select_related (加上后,与之关联的表的数据,一次取过来。)
    
        # 可以指定参数,指定外键字段,只取指定外键关联表的数据。
        users = models.User.objects.all().select_related('ut')
        for row in users:
            print(row.user,row.pwd,row.ut_id)
            print(row.ut.name)   # 再发起一次SQL请求
    
    # prefetch_related (会执行(外键表个数+本身一次查询)请求。不跨表操作。)
    
        # select 所有列 from users where id > 30 (django会查询所有列名,而不是select *,查*效率低一些比列名。)
        # 获取上一步骤中所有的ut_id=[1,2]
        # select 所有列 from user_type where id in [1,2]
        # Django会自动在内存里处理这两条数据,不需要我们管。
        users = models.User.objects.filter(id__gt=30).prefetch_related('ut','tu')
        for row in users:
            print(row.user,row.pwd,row.ut_id)
            print(row.ut.name)

    像一对一、一对多、多对多都是标准的数据库范式,但实际生产中往往不采用这种范式,这种范式省硬盘,但是连表查询效率是慢的。生产中往往以空间换时间。

    3、数据验证(full_clean进行验证)

    如下数据执行,可以执行,没有进行验证

    models.UserInfo.objects.create(name='root',email='root')
    obj = models.UserInfo(name='root',email='root')
    obj.save

    如果进行数据验证,obj.full_clean()

    obj.full_clean()    # 格式不对,直接报错,需要加上try。
    obj.save()
    • 先进行每个字段的正则验证
    • 在clean钩子验证。

    clean钩子自定义验证如下

    class UserInfo(models.Model):
        name = models.CharField(max_length=32)
        email = models.EmailField()
    
        def clean(self):
            from django.core.exceptions import ValidationError
            c = UserInfo.objects.filter(name=self.name).count()
            if c:
                raise ValidationError(message="用户名已经存在", code='i1')

    但是有些其他功能,是验证不了的,而且报错直接显示到前端了,这里的验证功能还是比较弱的。


    转载请务必保留此出处:http://www.cnblogs.com/lgeng/articles/7366330.html

    <!-- END  -->

    《版本说明》: 本文转自 -- http://blog.csdn.net/fgf00/article/details/54614706

  • 相关阅读:
    iot 表索引dump《2》
    heap表和iot表排序规则不同
    Cannot complete the install because one or more required items could not be found.
    iot表输出按主键列排序,heap表不是
    iot 表主键存放所有数据,且按数据插入顺序排序
    iot表和heap表排序规则不同
    org.eclipse.graphiti.ui.editor.DiagramEditorInput.
    Oracle 排序规则
    perl 异步超时 打印错误
    14.6.3 Grouping DML Operations with Transactions 组DML操作
  • 原文地址:https://www.cnblogs.com/lgeng/p/7366330.html
Copyright © 2011-2022 走看看