s14 django高级

Django进阶篇


- 参考博客
    Django高级:
        https://www.cnblogs.com/wupeiqi/articles/5246483.html
    Form:
        http://www.cnblogs.com/wupeiqi/articles/6144178.html
    Model:
        http://www.cnblogs.com/wupeiqi/articles/6216618.html
        
- Model

    # django为使用一种新的方式,
    # 即:关系对象映射(Object Relational Mapping,简称ORM)。

    # django中遵循 Code Frist 的原则,
    # 即:根据代码中定义的类来自动生成数据库表。
    # db first & code first
    
    # 根据类自动创建数据库表
    # 根据类对数据库表中的数据进行各种操作

    
- 基本操作
            
    a. 先写类
    
        # app下的models.py
        from django.db import models

        # app01_userinfo
        class UserInfo(models.Model):
            # 隐含id列,自增,主键
            # 用户名列,字符串类型,指定长度
            username = models.CharField(max_length=32)
            password = models.CharField(max_length=64)
        
    b. 注册APP

        INSTALLED_APPS = [
            'django.contrib.admin',
            'django.contrib.auth',
            'django.contrib.contenttypes',
            'django.contrib.sessions',
            'django.contrib.messages',
            'django.contrib.staticfiles',
            'app01',
        ]
        
    c. 执行命令
        
        # 先注册app
        根据类自动创建数据库表
        python manage.py  makemigrations
        python manage.py  migrate

        
    d. 其他
    
        - Django默认使用MySQLdb模块链接MySQL
        - 修改为pymysql,在project同名文件夹下__init__文件添加代码:
            
            import pymysql
            pymysql.install_as_MySQLdb()
            
        - 根据数据库,配置参数:
        
            mysql配置如下:
            
            DATABASES = {
                'default': {
                'ENGINE': 'django.db.backends.mysql',
                'NAME':'dbname',    # 手动创建数据库
                'USER': 'root',
                'PASSWORD': 'xxx',
                'HOST': '',
                'PORT': '',
                }
            }
    
        - pycharm数据库驱动
            C:\Users\jacka\.PyCharm2019.2\config\jdbc-drivers
            
        - 使用navicat链接sqlite
            - 右击复制copy path
            - nivacat:新建连接- 数据库文件

        - views.py
            from app01 import models
            
        - admin.py
        
            from django.contrib import admin
            from app01 import models
            # Register your models here.
            admin.site.register(models.UserInfo)
            
            创建 Django 用户:python manage.py createsuperuser            
            
------------------------------------------------
    
- 字段:
    - 字符串类型
    - 数字
    - 时间
    - 二进制
    - 自增(primary_key=True)

    AutoField(Field)
        - int自增列,必须填入参数 primary_key=True

    BigAutoField(AutoField)
        - bigint自增列,必须填入参数 primary_key=True

        注:当model中如果没有自增列,则自动会创建一个列名为id的列
        from django.db import models

        class UserInfo(models.Model):
            # 自动创建一个列名为id的且为自增的整数列
            username = models.CharField(max_length=32)

        class Group(models.Model):
            # 自定义自增列
            nid = models.AutoField(primary_key=True)
            name = models.CharField(max_length=32)

    SmallIntegerField(IntegerField):
        - 小整数 -32768 ~ 32767

    PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
        - 正小整数 0 ~ 32767
    IntegerField(Field)
        - 整数列(有符号的) -2147483648 ~ 2147483647

    PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
        - 正整数 0 ~ 2147483647

    BigIntegerField(IntegerField):
        - 长整型(有符号的) -9223372036854775808 ~ 9223372036854775807

    自定义无符号整数字段

        class UnsignedIntegerField(models.IntegerField):
            def db_type(self, connection):
                return 'integer UNSIGNED'

        PS: 返回值为字段在数据库中的属性,Django字段默认的值为:
            'AutoField': 'integer AUTO_INCREMENT',
            'BigAutoField': 'bigint AUTO_INCREMENT',
            'BinaryField': 'longblob',
            'BooleanField': 'bool',
            'CharField': 'varchar(%(max_length)s)',
            'CommaSeparatedIntegerField': 'varchar(%(max_length)s)',
            'DateField': 'date',
            'DateTimeField': 'datetime',
            'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
            'DurationField': 'bigint',
            'FileField': 'varchar(%(max_length)s)',
            'FilePathField': 'varchar(%(max_length)s)',
            'FloatField': 'double precision',
            'IntegerField': 'integer',
            'BigIntegerField': 'bigint',
            'IPAddressField': 'char(15)',
            'GenericIPAddressField': 'char(39)',
            'NullBooleanField': 'bool',
            'OneToOneField': 'integer',
            'PositiveIntegerField': 'integer UNSIGNED',
            'PositiveSmallIntegerField': 'smallint UNSIGNED',
            'SlugField': 'varchar(%(max_length)s)',
            'SmallIntegerField': 'smallint',
            'TextField': 'longtext',
            'TimeField': 'time',
            'UUIDField': 'char(32)',

    BooleanField(Field)
        - 布尔值类型

    NullBooleanField(Field):
        - 可以为空的布尔值

    CharField(Field)
        - 字符类型
        - 必须提供max_length参数, max_length表示字符长度

    TextField(Field)
        - 文本类型

    EmailField(CharField):
        - 字符串类型,Django Admin以及ModelForm中提供验证机制

    IPAddressField(Field)
        - 字符串类型,Django Admin以及ModelForm中提供验证 IPV4 机制

    GenericIPAddressField(Field)
        - 字符串类型,Django Admin以及ModelForm中提供验证 Ipv4和Ipv6
        - 参数:
            protocol,用于指定Ipv4或Ipv6, 'both',"ipv4","ipv6"
            unpack_ipv4, 如果指定为True,则输入::ffff:192.0.2.1时候,可解析为192.0.2.1,开启刺功能,需要protocol="both"

    URLField(CharField)
        - 字符串类型,Django Admin以及ModelForm中提供验证 URL

    SlugField(CharField)
        - 字符串类型,Django Admin以及ModelForm中提供验证支持 字母、数字、下划线、连接符(减号)

    CommaSeparatedIntegerField(CharField)
        - 字符串类型,格式必须为逗号分割的数字

    UUIDField(Field)
        - 字符串类型,Django Admin以及ModelForm中提供对UUID格式的验证

    FilePathField(Field)
        - 字符串,Django Admin以及ModelForm中提供读取文件夹下文件的功能
        - 参数:
                path,                      文件夹路径
                match=None,                正则匹配
                recursive=False,           递归下面的文件夹
                allow_files=True,          允许文件
                allow_folders=False,       允许文件夹

    FileField(Field)
        - 字符串,路径保存在数据库,文件上传到指定目录
        - 参数:
            upload_to = ""      上传文件的保存路径
            storage = None      存储组件,默认django.core.files.storage.FileSystemStorage

    ImageField(FileField)
        - 字符串,路径保存在数据库,文件上传到指定目录
        - 参数:
            upload_to = ""      上传文件的保存路径
            storage = None      存储组件,默认django.core.files.storage.FileSystemStorage
            width_field=None,   上传图片的高度保存的数据库字段名(字符串)
            height_field=None   上传图片的宽度保存的数据库字段名(字符串)

    DateTimeField(DateField)
        - 日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]

    DateField(DateTimeCheckMixin, Field)
        - 日期格式      YYYY-MM-DD

    TimeField(DateTimeCheckMixin, Field)
        - 时间格式      HH:MM[:ss[.uuuuuu]]

    DurationField(Field)
        - 长整数,时间间隔,数据库中按照bigint存储,ORM中获取的值为datetime.timedelta类型

    FloatField(Field)
        - 浮点型

    DecimalField(Field)
        - 10进制小数
        - 参数:
            max_digits,小数总长度
            decimal_places,小数位长度

    BinaryField(Field)
        - 二进制类型        
        
        
- 字段的参数:

    null               -> db是否可以为空
    default            -> 默认值
    primary_key        -> 主键
    db_column          -> 列名                 # 设定表列名
    db_index           -> 索引
    unique               -> 唯一索引
    unique_for_date    -> 只对date索引
    unique_for_month
    unique_for_year
    auto_now           -> 创建时,自动生成时间
    auto_now_add       -> 更新时,自动更新为当前时间
    
        # obj = UserGruop.objects.filter(id=1).update(caption='CEO')    # 不支持
        # 仅限于:
        # obj = UserGruop.objects.filter(id=1).first()
        # obj.caption ='CEO'
        # obj.save()
        
    choices              -> django admin中显示下拉框,避免连表查询
    blank             -> django admin是否可以为空
    verbose_name      -> django admin显示字段中文
    editable          -> django admin是否可以被编辑
    error_messages    -> 错误信息欠
    help_text         -> django admin提示
    validators          -> django form ,自定义错误信息(欠)
    
    - 字段类型验证:

        Django Admin:有验证功能
            
        model操作:无验证功能
        
            User.objects.create(username='root',email='asdfasdfasdfasdf')
            User.objects.filter(id=1).update(email='666')    

        
- 元信息

    class UserInfo(models.Model):
        nid = models.AutoField(primary_key=True)
        username = models.CharField(max_length=32)
        class Meta:
            # 数据库中生成的表名称 默认 app名称 + 下划线 + 类名
            db_table = "table_name"

            # 联合索引
            index_together = [
                ("pub_date", "deadline"),
            ]
                # 最左前缀的模式:
                # select * from where name='xx'
                # select * from where name='xx' and email = 'xx'
                # select * from where email = 'xx' # 无法命中索引                

            # 联合唯一索引
            unique_together = (("driver", "restaurant"),)

            # admin中显示的表名称
            verbose_name

            # verbose_name加s
            verbose_name_plural
        
        更多:https://docs.djangoproject.com/en/1.10/ref/models/options/    


- 多表关系以及参数:

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

                                                        def func():
                                                            return 10

                                                        class MyModel(models.Model):
                                                            user = models.ForeignKey(
                                                                to="User",
                                                                to_field="id"
                                                                on_delete=models.SET(func),)
        related_name=None,          # 反向操作时,使用的字段名,用于代替 【表名_set】 如: obj.表名_set.all()
        # 自关联时会使用。
        related_query_name=None,    # 反向操作时,使用的连接前缀,用于替换【表名】     如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名')
        
        limit_choices_to=None,      # 在Admin或ModelForm中显示关联数据时,提供的条件:
                                    # 如:
                                            - 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')
        db_constraint=True          # 是否在数据库中创建外键约束
        parent_link=False           # 在Admin中是否显示关联数据


    OneToOneField(ForeignKey)
        to,                         # 要进行关联的表名
        to_field=None               # 要关联的表中的字段名称
        on_delete=None,             # 当删除关联表中的数据时,当前表与其关联的行的行为

                                    ###### 对于一对一 ######
                                    # 1. 一对一其实就是 一对多 + 唯一索引
                                    # 2.当两个类之间有继承关系时,默认会创建一个一对一字段
                                    # 如下会在A表中额外增加一个c_ptr_id列且唯一:
                                            class C(models.Model):
                                                nid = models.AutoField(primary_key=True)
                                                part = models.CharField(max_length=12)

                                            class A(C):
                                                id = models.AutoField(primary_key=True)
                                                code = models.CharField(max_length=1)

    ManyToManyField(RelatedField)
        to,                         # 要进行关联的表名
        related_name=None,          # 反向操作时,使用的字段名,用于代替 【表名_set】 如: obj.表名_set.all()
        related_query_name=None,    # 反向操作时,使用的连接前缀,用于替换【表名】     如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名')
        limit_choices_to=None,      # 在Admin或ModelForm中显示关联数据时,提供的条件:
                                    # 如:
                                            - 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')
        symmetrical=None,           # 仅用于多对多自关联时,symmetrical用于指定内部是否创建反向操作的字段
                                    # 做如下操作时,不同的symmetrical会有不同的可选字段
                                        models.BB.objects.filter(...)

                                        # 可选字段有:code, id, m1
                                            class BB(models.Model):

                                            code = models.CharField(max_length=12)
                                            m1 = models.ManyToManyField('self',symmetrical=True)

                                        # 可选字段有: bb, code, id, m1
                                            class BB(models.Model):

                                            code = models.CharField(max_length=12)
                                            m1 = models.ManyToManyField('self',symmetrical=False)

        through=None,               # 自定义第三张表时,使用字段用于指定关系表
        through_fields=None,        # 自定义第三张表时,使用字段用于指定关系表中那些字段做多对多关系表
                                        from django.db import models

                                        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,              # 默认创建第三张表时,数据库中表的名称
            
- ORM操作

    - 基本操作
    
        # 增
        #
        # 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.exclude(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()                                                 # 修改单条数据        
    
    - 进阶操作
    
        # 获取个数
        #
        # 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)        
    
    - 高级操作
    
        # 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,))
        #    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()        
    
    - 其他操作
        
        ##################################################################
        # 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
            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,])

            # 将获取的到列名转换为指定列名
            name_map = {'first': 'first_name', 'last': 'last_name', 'bd': 'birth_date', 'pk': 'id'}
            Person.objects.raw('SELECT * FROM some_other_table', translations=name_map)

            # 指定数据库
            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'))

            """
            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'))
           ===> {'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)

        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):
           # 是否有结果        

-------------------------------------------------------
                  
           
           
# 一对多/一对一/多对多
    
    一对一:
            外键唯一约束。
    
    一对多:
            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)
                ForiegnKey(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()
            # 新版本关联数据默认都删除
        
        
            
            # 正向查找
            # v = User.objects.all()
            # for item in v:
            #     item.user
            #     item.pwd
            #     item.ut.name

            # User.objects.all().values('user','ut__name')


            # 反向查找
            # v= UserType.objects.all()
            # for item in v:
            #     item.name
            #     item.id
            #     item.user_set.all()
            # related_name='b' ==> item.b.all()
            # related_query_name='a' ==>  item.a_set.all()

            # UserType.objects.all().values('name','user__pwd')
            
    - 多对多:
        a. django创建第三张表
            m2m.remove
            m2m.add
            m2m.set
            m2m.clear
            m2m.filter()
        b. 自定义第三张表(无m2m字段)
            
            自己链表查询
            
        c. 自定义第三张表(有m2m字段)
            # 通过m2m字段查操作
            # 通过m2m字段 clear        
        

- QuerySet中的方法:

    - 返回QuerySet类型(select_related,prefetch_related)
        
        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)
                print(row.tu.name) # 再发起一次SQL请求
        
        prefetch_related
            
            users = models.User.objects.filter(id__gt=30).prefetch_related('ut','tu')
            # select * from users where id > 30
            # 获取上一步骤中所有的ut_id=[1,2]
            # select * from user_type where id in [1,2]
            # select * from user_type where id in [1,2]
            
            for row in users:
                print(row.user,row.pwd,row.ut_id)
                print(row.ut.name)
                
- 数据验证(弱)
    
    full_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')               
        
- 操作表    
    

    - 增
        models.User.objects.create(name='qianxiaohu',age=18)
        dic = {'name': 'xx', 'age': 19}
        models.User.objects.create(**dic)
        
        obj = models.User(name='qianxiaohu',age=18)    # 也可以传字典
        obj.save()
        
    - 删
        models.User.objects.filter(id=1).delete()
        
    - 改
        models.User.objects.filter(id__gt=1).update(name='alex',age=84)
        dic = {'name': 'xx', 'age': 19}
        models.User.objects.filter(id__gt=1).update(**dic)
        
    - 查
    
        models.User.objects.all()
        models.User.objects.filter(id=1,name='root')
        models.User.objects.filter(id__gt=1,name='root')
        models.User.objects.filter(id__lt=1)
        models.User.objects.filter(id__gte=1)
        models.User.objects.filter(id__lte=1)
        
        models.User.objects.filter(id=1,name='root')
        dic = {'name': 'xx', 'age__gt': 19}
        models.User.objects.filter(**dic)

        
    - 查2
    
        v1 = models.Business.objects.all()
        # QuerySet ,内部元素都是对象
                
        v2 = models.Business.objects.all().values('id','caption')
        # QuerySet ,内部元素都是字典
        
        v3 = models.Business.objects.all().values_list('id','caption')
        # QuerySet ,内部元素都是元组
        
        
        models.Business.objects.get(id=1)
        # 获取到的一个对象,如果不存在就报错
        
        models.Business.objects.filter(id=1).first()
        # 对象或者None
        
    外键:
    
        v = models.Host.objects.filter(nid__gt=0)
        v[0].b.caption  ---->  通过.进行跨表
        
        v1 = models.Host.objects.filter(nid__gt=0)
        # for row in v1:
        #     print(row.nid,row.hostname,row.ip,row.port,row.b_id,row.b.caption,row.b.code,row.b.id,sep='\t')

        v2 = models.Host.objects.filter(nid__gt=0).values('nid','hostname','b_id','b__caption')
        # models.Host.objects.后面跨表用双下划线: "__" ,为普通字符串,取值时为对象
        # print(v2)
        # QuerySet[{内部为字典},{字典}]
        # for row in v2:
        #     print(row['nid'],row['hostname'],row['b_id'],row['b__caption'])

        v3 = models.Host.objects.filter(nid__gt=0).values_list('nid','hostname','b_id','b__caption')

    
        class UserType(models.Model):
            caption = models.CharField(max_length=32)    
        # id  caption
            
        class User(models.Model):
            age = models.IntergerFiled()
            name = models.CharField(max_length=10)#字符长度
            # user_type_id = models.IntergerFiled() # 约束
            user_type = models.ForeignKey("UserType",to_field='id') # 约束
        # name  age  user_type_id    
        

        # models.tb.object.create(name='root', user_group_id=1)    
        # userlist = models.tb.object.all()
            for row in userlist:
                row.id
                row.user_group_id
                row.user_group.caption
                
        # user = User.objects.get(id=1)    # 得到单个对象
                

    - 序号相关
    
        {% for row in v1 %}
            <td>{{ forloop.counter}}</td>        # 序号从1开始
            <td>{{ forloop.counter0}}</td>        # 序号从0开始
            <td>{{ forloop.revcounter}}</td>    # 倒序从1开始
            <td>{{ forloop.revcounter0}}</td>    # 倒序从0开始
            <td>{{ forloop.last}}</td>            # 是否最后一个
            <td>{{ forloop.firs}}</td>            # 是否第一个
            <td>{{ forloop.parentloop}}</td>    # 如嵌套,显示父循环次数
        {%endfor%}



    - 多对多:
    
        - 自定义关系表
        
            class Host(models.Model):
                nid = models.AutoField(primary_key=True)
                hostname = models.CharField(max_length=32,db_index=True)
                ip = models.GenericIPAddressField(protocol="ipv4",db_index=True)
                port = models.IntegerField()
                b = models.ForeignKey(to="Business", to_field='id')

            class Application(models.Model):
                name = models.CharField(max_length=32)
            
            class HostToApp(models.Model):
                hobj = models.ForeignKey(to='Host',to_field='nid')
                aobj = models.ForeignKey(to='Application',to_field='id')
                
            # app01_hosttoapp 表 id,aobj_id,hobj_id    
            # HostToApp.objects.create(hobj_id=1,aobj_id=2)
                
            
                
        - 自动创建关系表
        
            class Host(models.Model):
                nid = models.AutoField(primary_key=True)
                hostname = models.CharField(max_length=32,db_index=True)
                ip = models.GenericIPAddressField(protocol="ipv4",db_index=True)
                port = models.IntegerField()
                b = models.ForeignKey(to="Business", to_field='id')
            
            class Application(models.Model):
                name = models.CharField(max_length=32)
                r = models.ManyToManyField("Host")
            
            # app01.application_r 表 id,application_id,host_id    
            # 无法直接对第三张表进行操作
            
            
            obj = Application.objects.get(id=1)
            obj.name
            
        - 第三张表操作
        
            obj.r.add(1)
            obj.r.add(2)
            obj.r.add(2,3,4)
            obj.r.add(*[1,2,3,4])
            
            obj.r.remove(1)
            obj.r.remove(2,4)
            obj.r.remove(*[1,2,3])
            
            obj.r.clear()
            
            obj.r.set([3,5,7])
            
            # objects后的都可以使用
            obj.r.all()
            
            # 所有相关的主机对象“列表” QuerySet
            obj.r.all()            
    






    
- FORM            


---------------------------------------

- Django的Form主要具有一下几大功能:

    生成HTML标签
    验证用户数据(显示错误信息)
    HTML Form提交保留上次提交数据
    初始化页面显示内容
    
    
- 小试牛刀

1、创建Form类

    from django.forms import Form
    from django.forms import widgets
    from django.forms import fields
    
    class MyForm(Form):
        user = fields.CharField(
            widget=widgets.TextInput(attrs={'id': 'i1', 'class': 'c1'})
        )
    
        gender = fields.ChoiceField(
            choices=((1, '男'), (2, '女'),),
            initial=2,
            widget=widgets.RadioSelect
        )
    
        city = fields.CharField(
            initial=2,
            widget=widgets.Select(choices=((1,'上海'),(2,'北京'),))
        )
    
        pwd = fields.CharField(
            widget=widgets.PasswordInput(attrs={'class': 'c1'}, render_value=True)
        )

2、View函数处理

    from django.shortcuts import render, redirect
    from .forms import MyForm
    
    
    def index(request):
        if request.method == "GET":
            obj = MyForm()
            return render(request, 'index.html', {'form': obj})
        elif request.method == "POST":
            obj = MyForm(request.POST, request.FILES)
            if obj.is_valid():
                values = obj.clean()
                print(values)
            else:
                errors = obj.errors
                print(errors)
            return render(request, 'index.html', {'form': obj})
        else:
            return redirect('http://www.google.com')

3、生成HTML

    <form action="/" method="POST" enctype="multipart/form-data">
        <p>{{ form.user }} {{ form.user.errors }}</p>
        <p>{{ form.gender }} {{ form.gender.errors }}</p>
        <p>{{ form.city }} {{ form.city.errors }}</p>
        <p>{{ form.pwd }} {{ form.pwd.errors }}</p>
        <input type="submit"/>
    </form>
    
    

1、Django内置字段如下:

    Field
        required=True,               是否允许为空
        widget=None,                 HTML插件
        label=None,                  用于生成Label标签或显示内容
        initial=None,                初始值
        help_text='',                帮助信息(在标签旁边显示)
        error_messages=None,         错误信息 {'required': '不能为空', 'invalid': '格式错误'}
        show_hidden_initial=False,   是否在当前插件后面再加一个隐藏的且具有默认值的插件(可用于检验两次输入是否一直)
        validators=[],               自定义验证规则
        localize=False,              是否支持本地化
        disabled=False,              是否可以编辑
        label_suffix=None            Label内容后缀
    
    
    CharField(Field)
        max_length=None,             最大长度
        min_length=None,             最小长度
        strip=True                   是否移除用户输入空白
    
    IntegerField(Field)
        max_value=None,              最大值
        min_value=None,              最小值
    
    FloatField(IntegerField)
        ...
    
    DecimalField(IntegerField)
        max_value=None,              最大值
        min_value=None,              最小值
        max_digits=None,             总长度
        decimal_places=None,         小数位长度
    
    BaseTemporalField(Field)
        input_formats=None          时间格式化   
    
    DateField(BaseTemporalField)    格式:2015-09-01
    TimeField(BaseTemporalField)    格式:11:12
    DateTimeField(BaseTemporalField)格式:2015-09-01 11:12
    
    DurationField(Field)            时间间隔:%d %H:%M:%S.%f
        ...
    
    RegexField(CharField)
        regex,                      自定制正则表达式
        max_length=None,            最大长度
        min_length=None,            最小长度
        error_message=None,         忽略,错误信息使用 error_messages={'invalid': '...'}
    
    EmailField(CharField)      
        ...
    
    FileField(Field)
        allow_empty_file=False     是否允许空文件
    
    ImageField(FileField)      
        ...
        注:需要PIL模块,pip3 install Pillow
        以上两个字典使用时,需要注意两点:
            - form表单中 enctype="multipart/form-data"
            - view函数中 obj = MyForm(request.POST, request.FILES)
    
    URLField(Field)
        ...
    
    
    BooleanField(Field)  
        ...
    
    NullBooleanField(BooleanField)
        ...
    
    ChoiceField(Field)
        ...
        choices=(),                选项,如:choices = ((0,'上海'),(1,'北京'),)
        required=True,             是否必填
        widget=None,               插件,默认select插件
        label=None,                Label内容
        initial=None,              初始值
        help_text='',              帮助提示
    
    
    ModelChoiceField(ChoiceField)
        ...                        django.forms.models.ModelChoiceField
        queryset,                  # 查询数据库中的数据
        empty_label="---------",   # 默认空显示内容
        to_field_name=None,        # HTML中value的值对应的字段
        limit_choices_to=None      # ModelForm中对queryset二次筛选
        
    ModelMultipleChoiceField(ModelChoiceField)
        ...                        django.forms.models.ModelMultipleChoiceField
    
    
        
    TypedChoiceField(ChoiceField)
        coerce = lambda val: val   对选中的值进行一次转换
        empty_value= ''            空值的默认值
    
    MultipleChoiceField(ChoiceField)
        ...
    
    TypedMultipleChoiceField(MultipleChoiceField)
        coerce = lambda val: val   对选中的每一个值进行一次转换
        empty_value= ''            空值的默认值
    
    ComboField(Field)
        fields=()                  使用多个验证,如下:即验证最大长度20,又验证邮箱格式
                                   fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(),])
    
    MultiValueField(Field)
        PS: 抽象类,子类中可以实现聚合多个字典去匹配一个值,要配合MultiWidget使用
    
    SplitDateTimeField(MultiValueField)
        input_date_formats=None,   格式列表:['%Y--%m--%d', '%m%d/%Y', '%m/%d/%y']
        input_time_formats=None    格式列表:['%H:%M:%S', '%H:%M:%S.%f', '%H:%M']
    
    FilePathField(ChoiceField)     文件选项,目录下文件显示在页面中
        path,                      文件夹路径
        match=None,                正则匹配
        recursive=False,           递归下面的文件夹
        allow_files=True,          允许文件
        allow_folders=False,       允许文件夹
        required=True,
        widget=None,
        label=None,
        initial=None,
        help_text=''
    
    GenericIPAddressField
        protocol='both',           both,ipv4,ipv6支持的IP格式
        unpack_ipv4=False          解析ipv4地址,如果是::ffff:192.0.2.1时候,可解析为192.0.2.1, PS:protocol必须为both才能启用
    
    SlugField(CharField)           数字,字母,下划线,减号(连字符)
        ...
    
    UUIDField(CharField)           uuid类型
        ...

2、Django内置插件:
    
    TextInput(Input)
    NumberInput(TextInput)
    EmailInput(TextInput)
    URLInput(TextInput)
    PasswordInput(TextInput)
    HiddenInput(TextInput)
    Textarea(Widget)
    DateInput(DateTimeBaseInput)
    DateTimeInput(DateTimeBaseInput)
    TimeInput(DateTimeBaseInput)
    CheckboxInput
    Select
    NullBooleanSelect
    SelectMultiple
    RadioSelect
    CheckboxSelectMultiple
    FileInput
    ClearableFileInput
    MultipleHiddenInput
    SplitDateTimeWidget
    SplitHiddenDateTimeWidget
    SelectDateWidget
    
    常用选择插件
    

        
    # 单radio,值为字符串
    # user = fields.CharField(
    #     initial=2,
    #     widget=widgets.RadioSelect(choices=((1,'上海'),(2,'北京'),))
    # )
    
    # 单radio,值为字符串
    # user = fields.ChoiceField(
    #     choices=((1, '上海'), (2, '北京'),),
    #     initial=2,
    #     widget=widgets.RadioSelect
    # )
    
    # 单select,值为字符串
    # user = fields.CharField(
    #     initial=2,
    #     widget=widgets.Select(choices=((1,'上海'),(2,'北京'),))
    # )
    
    # 单select,值为字符串
    # user = fields.ChoiceField(
    #     choices=((1, '上海'), (2, '北京'),),
    #     initial=2,
    #     widget=widgets.Select
    # )
    
    # 多选select,值为列表
    # user = fields.MultipleChoiceField(
    #     choices=((1,'上海'),(2,'北京'),),
    #     initial=[1,],
    #     widget=widgets.SelectMultiple
    # )
    
    
    # 单checkbox
    # user = fields.CharField(
    #     widget=widgets.CheckboxInput()
    # )
    
    
    # 多选checkbox,值为列表
    # user = fields.MultipleChoiceField(
    #     initial=[2, ],
    #     choices=((1, '上海'), (2, '北京'),),
    #     widget=widgets.CheckboxSelectMultiple
    # )

    在使用选择标签时,需要注意choices的选项可以从数据库中获取,
    但是由于是静态字段 ***获取的值无法实时更新***,那么需要自定义构造方法从而达到此目的。

    方式一:

        from django.forms import Form
        from django.forms import widgets
        from django.forms import fields
        from django.core.validators import RegexValidator
        
        class MyForm(Form):
        
            user = fields.ChoiceField(
                # choices=((1, '上海'), (2, '北京'),),
                initial=2,
                widget=widgets.Select
            )
        
            def __init__(self, *args, **kwargs):
                super(MyForm,self).__init__(*args, **kwargs)
                # self.fields['user'].widget.choices = ((1, '上海'), (2, '北京'),)
                # 或
                self.fields['user'].widget.choices = models.Classes.objects.all().value_list('id','caption')

    方式二:

        使用django提供的ModelChoiceField和ModelMultipleChoiceField字段来实现
            
        from django import forms
        from django.forms import fields
        from django.forms import widgets
        from django.forms import models as form_model
        from django.core.exceptions import ValidationError
        from django.core.validators import RegexValidator
        
        class FInfo(forms.Form):
            authors = form_model.ModelMultipleChoiceField(queryset=models.NNewType.objects.all())
            # authors = form_model.ModelChoiceField(queryset=models.NNewType.objects.all())

- 自定义验证规则

    方式一:
        
        from django.forms import Form
        from django.forms import widgets
        from django.forms import fields
        from django.core.validators import RegexValidator
        
        class MyForm(Form):
            user = fields.CharField(
                validators=[RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头')],
            )

    方式二:


        import re
        from django.forms import Form
        from django.forms import widgets
        from django.forms import fields
        from django.core.exceptions import ValidationError


        # 自定义验证规则
        def mobile_validate(value):
            mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$')
            if not mobile_re.match(value):
                raise ValidationError('手机号码格式错误')
        
        
        class PublishForm(Form):
        
        
            title = fields.CharField(max_length=20,
                                    min_length=5,
                                    error_messages={'required': '标题不能为空',
                                                    'min_length': '标题最少为5个字符',
                                                    'max_length': '标题最多为20个字符'},
                                    widget=widgets.TextInput(attrs={'class': "form-control",
                                                                  'placeholder': '标题5-20个字符'}))
        
        
            # 使用自定义验证规则
            phone = fields.CharField(validators=[mobile_validate, ],
                                    error_messages={'required': '手机不能为空'},
                                    widget=widgets.TextInput(attrs={'class': "form-control",
                                                                  'placeholder': u'手机号码'}))
        
            email = fields.EmailField(required=False,
                                    error_messages={'required': u'邮箱不能为空','invalid': u'邮箱格式错误'},
                                    widget=widgets.TextInput(attrs={'class': "form-control", 'placeholder': u'邮箱'}))

    方法三:自定义方法

        from django import forms
            from django.forms import fields
            from django.forms import widgets
            from django.core.exceptions import ValidationError
            from django.core.validators import RegexValidator
        
            class FInfo(forms.Form):
                username = fields.CharField(max_length=5,
                                            validators=[RegexValidator(r'^[0-9]+$', 'Enter a valid extension.', 'invalid')], )
                email = fields.EmailField()
        
                def clean_username(self):
                    """
                    Form中字段中定义的格式匹配完之后,执行此方法进行验证
                    :return:
                    """
                    value = self.cleaned_data['username']
                    if "666" in value:
                        raise ValidationError('666已经被玩烂了...', 'invalid')
                    return value

    方式四:同时生成多个标签进行验证

        from django.forms import Form
        from django.forms import widgets
        from django.forms import fields
        
        from django.core.validators import RegexValidator
        
        
        ############## 自定义字段 ##############
        class PhoneField(fields.MultiValueField):
            def __init__(self, *args, **kwargs):
                # Define one message for all fields.
                error_messages = {
                    'incomplete': 'Enter a country calling code and a phone number.',
                }
                # Or define a different message for each field.
                f = (
                    fields.CharField(
                        error_messages={'incomplete': 'Enter a country calling code.'},
                        validators=[
                            RegexValidator(r'^[0-9]+$', 'Enter a valid country calling code.'),
                        ],
                    ),
                    fields.CharField(
                        error_messages={'incomplete': 'Enter a phone number.'},
                        validators=[RegexValidator(r'^[0-9]+$', 'Enter a valid phone number.')],
                    ),
                    fields.CharField(
                        validators=[RegexValidator(r'^[0-9]+$', 'Enter a valid extension.')],
                        required=False,
                    ),
                )
                super(PhoneField, self).__init__(error_messages=error_messages, fields=f, require_all_fields=False, *args,
                                                 **kwargs)
        
            def compress(self, data_list):
                """
                当用户验证都通过后,该值返回给用户
                :param data_list:
                :return:
                """
                return data_list
        
        ############## 自定义插件 ##############
        class SplitPhoneWidget(widgets.MultiWidget):
            def __init__(self):
                ws = (
                    widgets.TextInput(),
                    widgets.TextInput(),
                    widgets.TextInput(),
                )
                super(SplitPhoneWidget, self).__init__(ws)
        
            def decompress(self, value):
                """
                处理初始值,当初始值initial不是列表时,调用该方法
                :param value:
                :return:
                """
                if value:
                    return value.split(',')
                return [None, None, None]

-----------------------------

- 动态select数据


    user_type = fields.ChoiceField(
        # choices=[(1,'普通用户'),(2,'超级用户')],
        # choices=models.UserType.objects.values_list('id','name'),
        # 增加后无法更新,静态字段
        choices=[],
        widget = widgets.Select
    )
    user_type2 = fields.CharField(widget=widgets.Select(choices=[]))


    # 解决方法二
    user_type3 = ModelChoiceField(
        empty_label='请选择用户类型',
        queryset=models.UserType.objects.all(),
        to_field_name='id'
        # 依赖 models.py中的 def __str__(self): return self.name
        # 否则选项的是对象
    )
    # 解决方法一(推荐)
    def __init__(self,*args,**kwargs):
        # 自定义方法,重新获取
        super(UserInfoForm,self).__init__(*args,**kwargs)
        self.fields['user_type'].choices = models.UserType.objects.values_list('id','name')
        self.fields['user_type2'].widget.choices = models.UserType.objects.values_list('id','name')
    
    
- 数据验证(强大)

    验证顺序:
    
        字段:
            正则  ==>  clean_fields  
        整体:
            clean  ==>  _post_clean
        
    源码查找:
    
        is_valid()    errors    full_clean    _clean_fields    clean_fields
                                              _clean_form      clean
                                              _post_clean
    
    整体错误信息:
    
        ‘__all__’  'NON_FIELD_ERRORS'    
        
        
    代码示例:
    
        class LoginForm(forms.Form):
            user =fields.CharField()
            pwd =fields.CharField()
            # 需整体显示错误信息
            def clean_user(self):
                c = models.UserInfo.objects.filter(name=self.cleaned_data['user']).count()
                if not c:
                    return self.cleaned_data['user']
                else:
                    raise ValidationError('用户名已经存在',code='xxx')

            def clean_pwd(self):
                return self.cleaned_data['pwd']

            def clean(self):
                c = models.UserInfo.objects.filter(name=self.cleaned_data['user'],pwd=self.cleaned_data['pwd']).count()
                if c:
                    return self.clean_data
                else:
                    raise ValidationError('用户名或密码错误')

            def _post_clean(self):
                pass

- 序列化

    关于Django中的序列化主要应用在将数据库中检索的数据返回给客户端用户,
    特别的Ajax请求一般返回的为Json格式。

    1、serializers

        from django.core import serializers
        
        ret = models.BookType.objects.all()
        
        data = serializers.serialize("json", ret)
    2、json.dumps

        import json
        
        #ret = models.BookType.objects.all().values('caption')
        ret = models.BookType.objects.all().values_list('caption')
        
        ret=list(ret)
        
        result = json.dumps(ret)
    3、由于json.dumps时无法处理datetime日期,所以可以通过自定义处理器来做扩展,如:

        import json
        from datetime import date
        from datetime import datetime
           
        class JsonCustomEncoder(json.JSONEncoder):
            
            def default(self, field):
            
                if isinstance(field, datetime):
                    return o.strftime('%Y-%m-%d %H:%M:%S')
                elif isinstance(field, date):
                    return o.strftime('%Y-%m-%d')
                else:
                    return json.JSONEncoder.default(self, field)
           
           
        # ds = json.dumps(d, cls=JsonCustomEncoder)
    
    示例:

        # djang 默认序列化
        # from django.core import serializers
        # ret = models.UserType.objects.all()
        # data = serializers.serialize("json", ret)
        # return HttpResponse(data)

        # 自定制
        import json
        v = models.UserType.objects.values_list('id','name')
        v=list(v)
        return HttpResponse(json.dumps(v))                

    - ErrorDict
    
        - 自定义encoder
        
    - QuerySet
    
        第一种:
            from django.core import serializers
            
            v = models.tb.objects.all()
            data = serializers.serialize("json", v)
            
        第二种:
            
            如果有时间进行排除处理。
            
            import json
            from datetime import date
            from datetime import datetime
               
            class JsonCustomEncoder(json.JSONEncoder):
                
                def default(self, field):
                
                    if isinstance(field, datetime):
                        return field.strftime('%Y-%m-%d %H:%M:%S')
                    elif isinstance(field, date):
                        return field.strftime('%Y-%m-%d')
                    else:
                        return json.JSONEncoder.default(self, field)

            v = models.tb.objects.values('id','name','ctime')
            v = list(v)
            v = json.dumps(v,cls=JsonCustomEncoder)



        
- FORM 代码
    
    # views.py
    
        from django import forms
        from django.forms import widgets
        from django.forms import fields
        class FM(forms.Form):
            # 字段本身只做验证
            user = fields.CharField(
                error_messages={'required':'用户名不能为空'},
                widget= widgets.Textarea(attrs={'class':'c1'}),
                label='用户名',
                initial='root',
                )
            pwd =fields.CharField(
                max_length=12,
                min_length=6,
                error_messages={'required':'密码不能为空',
                                'min_length':'密码长度不能小于6位',
                                'max_length':'密码长度不能超过12位'},
                widget=widgets.PasswordInput
            )
            email = fields.EmailField(error_messages={'required':'用户名不能为空','invalid':'邮箱格式错误'})

        from app01 import models
        def fm(request):
            if request.method=='GET':
                obj = FM()
                return render(request,'fm.html',{'obj':obj})
            elif request.method =='POST':
                # 获取数据,验证
                # 成功后获取正确数据,失败显示错误信息
                obj =FM(request.POST)
                if obj.is_valid():
                    print(obj.cleaned_data)
                    # models.Userinfo.bojects.create(**cleaned_data)
                else:
                    # print(obj.errors)
                    # print(obj.errors.as_json())
                    # print(obj.errors['user'][0])
                    return render(request,'fm.html',{'obj':obj})
    # html

        <!DOCTYPE html>
        <html lang="en">
        <head>
            <meta charset="UTF-8">
            <title></title>
        </head>
        <body>
            <form action="/fm/"method="POST">
                {% csrf_token %}
                <p>{{ obj.user.label }}{{ obj.user }}{{ obj.errors.user.0 }}</p>
                <p>{{ obj.pwd }}{{ obj.errors.pwd.0 }}</p>
                <p>{{ obj.email }}{{ obj.errors.email.0 }}</p>
        {#        {{ obj.as_p }}#}
        {#        {{ obj.as_ul }}#}
        {#        <table>{{ obj.as_table }}</table>#}
                <p><input type="submit"></p>
            </form>
        </body>
        </html>
        
    
- 示例(数据库操作补充之QuerySet方法、 Model数据验证以及钩子、动态Select数据、Form内置钩子、Django序列化)

    # urls.py
        urlpatterns = [
            url(r'^admin/', admin.site.urls),
            url(r'^index/', test.index),
            url(r'^login.html$', account.login),

            url(r'^register/', test.register),
        ]
    # views/test.py
    
        from django.shortcuts import render,HttpResponse

        # Create your views here.
        from app01 import models
        def index(request):
            # models.UserType.objects.all().values('name','user__pwd')
            # models.UserInfo.objects.create(name='root',email='root')
            # 没有进行验证
            # obj = models.UserInfo(name='alex',email='alex')
            # obj.full_clean()  # 验证
            # obj.save()
            # 此方法会验证

            from app01.forms import UserInfoForm
            if request.method == 'GET':
                obj = UserInfoForm()
                # obj = UserInfoForm({'user':'alex'})
                # obj.fields['user_type'].choices = models.UserType.objects.values_list('id','name')
                return render(request, 'index.html',{'obj':obj})
            elif request.method=='POST':
                obj = UserInfoForm(request.POST,request.FILES)
                obj.is_valid()

        def register(request):
            from app01.forms import RegisterForm
            from django.core.exceptions import NON_FIELD_ERRORS
            # obj =RegisterForm(request.POST)
            # if obj.is_valid():
            #     obj.cleaned_data
            # else:
            #     obj.errors
            #     {
            #         '__all__':[],
            #         # 'NON_FIELD_ERRORS':[],
            #         # 整体错误信息在__all__里面
            #         'user':[{'code':'required','message':'xxx'}],
            #         'pwd':[{'code':'required','message':'xxx'}],
            #     }

            # djang 默认序列化
            # from django.core import serializers
            # ret = models.UserType.objects.all()
            # data = serializers.serialize("json", ret)
            # return HttpResponse(data)

            # 自定制
            import json
            v = models.UserType.objects.values_list('id','name')
            v=list(v)
            return HttpResponse(json.dumps(v))
            
    # views/account.py

        from django.shortcuts import render,HttpResponse
        from django import forms
        from django.forms import fields
        from django.forms import widgets
        import json
        class LoginForm(forms.Form):
            # 登陆
            username = fields.CharField()
            password = fields.CharField(
                max_length=64,
                min_length=12,
            )
        from django.core.exceptions import ValidationError
        class JsonCustomEncoder(json.JSONEncoder):
            def default(self, field):
                if isinstance(field,ValidationError):
                    return {'code':field.code,'message':field.messages}
                else:
                    return json.JSONEncoder.default(self,field)

        def login(request):
            ret = {'status':True,'error':None,'data':None}
            if request.method=='GET':
                return render(request,'login.html')
            elif request.method=='POST':
                obj = LoginForm(request.POST)
                if obj.is_valid():
                    print(obj.clean_data)
                else:
                    # print(obj.errors,type(obj.errors))
                    # ret['error'] = obj.errors.as_json()
                    # 前端需要对 arg parse两回才能得到error
                    from django.forms.utils import ErrorDict

                    print(type(obj.errors.as_data()))
                    for k,v in obj.errors.as_data().items():
                        print(k,v)
                    from django.core.exceptions import ValidationError
                    ret['error'] =obj.errors.as_data()
                result =json.dumps(ret,cls=JsonCustomEncoder)
                return HttpResponse(result)

    # models.py

        from django.db import models

        # Create your models here.
        class UserType(models.Model):
            name=models.CharField(max_length=32)

            def __str__(self):
                return self.name

        class User(models.Model):
            user =models.CharField(max_length=32)
            pwd =models.CharField(max_length=64)
            ut = models.ForeignKey(to='UserType',
                                   to_field='id',
                                   related_name='b',
                                   related_query_name='a',
                                   limit_choices_to={'id__gt':5},    # admin 中外键筛选
                                   # parent_link=False      #欠着
                                   )
        # 正向查找
        # v = User.objects.all()
        # for item in v:
        #     item.user
        #     item.pwd
        #     item.ut.name

        # User.objects.all().values('user','ut__name')


        # 反向查找
        # v= UserType.objects.all()
        # for item in v:
        #     item.name
        #     item.id
        #     item.user_set.all()
        # related_name='b' ==> item.b.all()
        # related_query_name='a' ==>  item.a_set.all()

        # UserType.objects.all().values('name','user__pwd')


        class Blog(models.Model):
            site = models.CharField(max_length=32)
            m =models.ManyToManyField('Tag',through='B2T',through_fields=['b','t1'])

        class Tag(models.Model):
            name = models.CharField(max_length=32)

        class B2T(models.Model):
            b = models.ForeignKey('Blog')
            t1 = models.ForeignKey('Tag')
            # t2 = models.ForeignKey('Tag')

        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')    

    # login.html
    
        <form id="fm">
            {% csrf_token %}
            <p><input type="text"name="username"></p>
            <p><input type="password"name="password"></p>
            <p><a id = 'submit'>提交</a></p>
        </form>

        <script src="/static/jquery-1.12.4.js"></script>
        <script>
            $(function () {
                $('#submit').click(function () {
                    $.ajax({
                        url:'/login.html',
                        type:'POST',
                        data:$('#fm').serialize(),
                        //自行打包了csrf_token
                        success: function (arg) {
                            console.log(arg);
                            arg = JSON.parse(arg);
                            console.log(arg);
                        },
                        error: function () {

                        }
                    })
                })
            });
        </script>
        
        
        
    # forms.py

        from django import forms
        from django.forms import fields
        from django.forms import widgets
        from django.forms.models import ModelChoiceField,ModelMultipleChoiceField
        from app01 import models

        class UserInfoForm(forms.Form):
            user = fields.CharField(
                required= False,
                widget=widgets.Textarea(attrs={'class':'c1'})
            )
            pwd =fields.CharField(
                max_length= 12,
                widget= widgets.PasswordInput(attrs={'class':'c1'})
            )
            user_type = fields.ChoiceField(
                # choices=[(1,'普通用户'),(2,'超级用户')],
                # choices=models.UserType.objects.values_list('id','name'),
                # 增加后无法更新,静态字段
                choices=[],
                widget = widgets.Select
            )
            user_type2 = fields.CharField(widget=widgets.Select(choices=[]))


            # 解决方法二
            user_type3 = ModelChoiceField(
                empty_label='请选择用户类型',
                queryset=models.UserType.objects.all(),
                to_field_name='id'
                # 依赖 models.py中的 def __str__(self): return self.name
                # 否则选项的是对象
            )
            # 解决方法一(推荐)
            def __init__(self,*args,**kwargs):
                # 自定义方法,重新获取
                super(UserInfoForm,self).__init__(*args,**kwargs)
                self.fields['user_type'].choices = models.UserType.objects.values_list('id','name')
                self.fields['user_type2'].widget.choices = models.UserType.objects.values_list('id','name')


            # 验证:
            # 生成html(保留上一次提交的数据)

            # 新URL方式操作(Form方式)
            # Ajax请求通常不使用Form生成html,只使用验证。

        from django.core.exceptions import ValidationError
        class RegisterForm(forms.Form):
            user =fields.CharField()
            email =fields.EmailField()
            # 单独字段
            def clean_user(self):
                c = models.UserInfo.objects.filter(name=self.cleaned_data['user']).count()
                if not c:
                    return self.cleaned_data['user']
                else:
                    raise ValidationError('用户名已经存在',code='xxx')

            def clean_email(self):
                return self.cleaned_data['email']


        class LoginForm(forms.Form):
            user =fields.CharField()
            pwd =fields.CharField()
            # 需整体显示错误信息(用户名是否存在)
            def clean_user(self):
                c = models.UserInfo.objects.filter(name=self.cleaned_data['user']).count()
                if not c:
                    return self.cleaned_data['user']
                else:
                    raise ValidationError('用户名已经存在',code='xxx')

            def clean_pwd(self):
                return self.cleaned_data['pwd']

            def clean(self):
                c = models.UserInfo.objects.filter(name=self.cleaned_data['user'],pwd=self.cleaned_data['pwd']).count()
                if c:
                    return self.clean_data
                else:
                    raise ValidationError('用户名或密码错误')
                    
            # 密码两次输入一致,可在此判断

            def _post_clean(self):
                pass
                
    #index.html            
                
        <!DOCTYPE html>
        <html lang="en">
        <head>
            <meta charset="UTF-8">
            <title></title>
        </head>
        <body>
            <p>{{ obj.user }}</p>
            <p>{{ obj.pwd }}</p>
            <p>{{ obj.user_type }}</p>
            <p>{{ obj.user_type2 }}</p>
            <p>{{ obj.user_type3 }}</p>
        </body>
        </html>    


        
                    
- 示例(基本增删改查和用户登陆、删除、查看详细、字段、参数、外键操作、外键增加):

    # app01/urls.py

        urlpatterns = [
            url(r'^login/', views.login),
            url(r'^orm/', views.orm),
            url(r'^index/', views.index),
            url(r'^user_info/', views.user_info),
            url(r'^userdetail-(?P<nid>\d+)/', views.user_detail),
            url(r'^userdel-(?P<nid>\d+)/', views.user_del),
            url(r'^useredit-(?P<nid>\d+)/', views.user_edit),
        ]    
            
    # app01/views.py

        def login(request):
            # models.UserInfo.objects.create(caption='DBA')
            if request.method =='GET':
                # GET 必须大写,否则无法进入
                return render(request,'login.html')
            elif request.method=='POST':
                # 数据库中获取数据
                u = request.POST.get('user')
                p = request.POST.get('pwd')
                # obj=models.UserInfo.objects.filter(username=u,password=p)
                # obj=models.UserInfo.objects.filter(username=u,password=p).first() # 一个obj ****
                # print(obj)
                # obj=models.UserInfo.objects.filter(username=u,password=p).count()   # 获取个数
                obj=models.UserInfo.objects.filter(username=u,password=p).first()
                if obj:
                    return redirect('/cmdb/index/')
                else:
                    return render(request,'login.html')
            else:
                # put,delete,head,option..
                return redirect('/index/')

        def index(request):
            return render(request,'index.html')

        def user_info(request):
            if request.method=='GET':
                user_list = models.UserInfo.objects.all()
                # QuerySet[obj(id,username..),obj,]
                # QuerySet[obj(id,username,email,user_group_id,user_group_id(uid,caption)),obj,]
                # for row in user_list:
                #     print(row.id)
                #     print(row.user_group)
                #     print(row.user_group.uid)
                #     print(row.user_group.caption)
                # print(user_list.query)
                # 查看SQL语句
                group_list = models.UserGruop.objects.all()
                return render(request,'user_info.html',{'user_list':user_list,'group_list':group_list})
            elif request.method == 'POST':
                u = request.POST.get('user')
                p = request.POST.get('pwd')
                models.UserInfo.objects.create(username=u,password=p)
                return redirect('/cmdb/user_info/')
                # user_list = models.UserInfo.objects.all()
                # return render(request,'user_info.html',{'user_list':user_list})

        def user_detail(request,nid):
            obj=models.UserInfo.objects.filter(id=nid).first()
            # models.UserInfo.objects.get(id=nid)   # 不存在报错
            return render(request,'user_detail.html',{'obj':obj})

        def user_del(request,nid):
            models.UserInfo.objects.filter(id=nid).delete()
            return redirect('/cmdb/user_info/')

        def user_edit(request,nid):
            if request.method=="GET":
                obj=models.UserInfo.objects.filter(id=nid).first()
                return render(request,'user_edit.html',{'obj':obj})
            elif request.method=="POST":
                nid =request.POST.get('id')
                u =request.POST.get('username')
                p =request.POST.get('password')
                print(nid,u,p)
                models.UserInfo.objects.filter(id=nid).update(username=u,password=p)
                return redirect('/cmdb/user_info/')


        from app01 import models
        def orm(request):
            # 创建
            # models.UserInfo.objects.create(username= 'root',password = '123')

            # dic={'username':'eric','password':'666'}
            # models.UserInfo.objects.create(**dic)

            # obj = models.UserInfo(username= 'alex',password = '123')
            # obj.save()

            # 查
            # result = models.UserInfo.objects.all()
            # result:QuerySet django提供的[]
            # [obj(id,usernmae,password),obj.obj] obj是 UserInfo对象

            # result = models.UserInfo.objects.filter(username='root')
            # result = models.UserInfo.objects.filter(username='root',password='123')
            # for row in result:
            #     print(row.id,row.username,row.password)
            # print(result)

            # 删除
            # models.UserInfo.objects.all().delete()
            # models.UserInfo.objects.filter(id=4).delete()
            # models.UserInfo.objects.filter(username='alex').delete()

            # 更新
            # models.UserInfo.objects.all().update(password='6666')
            # models.UserInfo.objects.filter(id=3).update(password='999')


            # 一对多
            # user_list =models.UserInfo.objects.all()

            # models.UserInfo.objects.create(
            #     username='root1',
            #     password='123',
            #     email='root1@eee.com',
            #     test='dfdfdfd',
            #     user_group= models.UserInfo.objects.filter(id=1).first()
            # )
            models.UserInfo.objects.create(
                username='root1',
                password='123',
                email='root1@eee.com',
                test='dfdfdfd',
                user_group_id = 1,
            )
            return HttpResponse('orm')
            
    # models.py
    
        from django.db import models

        # Create your models here.

        # app01_userinfo
        class UserGruop(models.Model):
            uid = models.AutoField(primary_key=True)
            # 创建自增列
            caption =models.CharField(max_length=32)
            ctime=models.DateField(auto_now_add=True,null=True)
            utime=models.DateField(auto_now=True,null=True)

        # user_list = UserInfo.objects.all()
        # for row in user_list:
        #     print(row.user_group_id)
        #     print(row.user_group)
        #     print(row.user_group.uid)
        #     print(row.user_group.cption)

        class UserInfo(models.Model):
            # 自动创建ID列,自增,主键
            # 基本类型:字符串、数字、时间、二进制
            username = models.CharField(max_length=32,blank=True,verbose_name='用户名')
            password = models.CharField(max_length=64,help_text='pwd')
            # 长度改小,则数据丢失
            email = models.CharField(max_length=60,default='xxxx@164.com')
            test = models.EmailField(max_length=19,null=True)
            user_group = models.ForeignKey('UserGruop',to_field='uid',default=1)
            # 不添加to_field默认使用主键
            # 数据库中:user_group_id 数字
            # (uid,caption,ctime,utime)
            user_type_choices =(
                (1,'超级用户'),
                (2,'普通用户'),
                (3,'普普通用户'),
            )
            user_type_id = models.IntegerField(choices=user_type_choices,default=1)
            # test = models.URLField(max_length=19,null=True)
            # test = models.GenericIPAddressField()
            # gender = models.CharField(max_length=60,null=True)

    # login.html
    
        <form action="/cmdb/login/"method="POST" enctype="multipart/form-data">
            <p><input type="text"name="user"placeholder="用户名"></p>
            <p><input type="password"name="pwd"placeholder="密码"></p>
            <p><input type="submit"value="提交"></p>
        </form>        

    # index.html(含菜单)

        <style>body{margin: 0;}
        .menu{display: block;padding: 5px;}</style>
        
        <div style="height: 48px;color: white;">welcome</div>
        <div>
            <div style="position: absolute;top:48px;bottom:0;left: 0;width: 200px;
            
                <a class="menu" href="/cmdb/user_info/">用户管理</a>
                <a class="menu" href="/cmdb/user_group/">用户组管理</a>
            </div>
            <div style="position: absolute;top:48px;left: 210px;bottom:0;right: 0;overflow: auto"></div>
        </div>            
    
    # user_info.html
    
        <div style="height: 48px;color: white;">welcome</div>
        <div>
            <div style="position: absolute;top:48px;bottom:0;left: 0;width: 200px;
            
                <a class="menu" href="/cmdb/user_info/">用户管理</a>
                <a class="menu" href="/cmdb/user_group/">用户组管理</a>
            </div>
            <div style="position: absolute;top:48px;left: 210px;bottom:0;right: 0;overflow: auto">
                <h3>添加用户</h3>

                <form action="/cmdb/user_info/"method="POST">
                    <input type="text"name="user">
                    <input type="text"name="pwd">
                    <select name="group_id" id="">
                        {% for item in group_list %}
                            <option value="{{ item.uid }}">{{ item.caption }}</option>
                        {% endfor %}
                    </select>
                    <input type="submit">
                </form>

                <h3>用户列表</h3>
                <ul>
                    {% for row in user_list %}
                        <li><a href="/cmdb/userdetail-{{ row.id }}">{{ row.username }}</a> |
                            <span>{{ row.user_group.caption }}</span>
                            <a href="/cmdb/userdel-{{ row.id }}/">删除</a>|
                            <a href="/cmdb/useredit-{{ row.id }}/">编辑</a></li>
                    {% endfor %}
                </ul>
            </div>
        </div>
    
    # user_detail.html(详细信息)


        <div style="height: 48px;color: white;">welcome</div>
        <div>
            <div style="position: absolute;top:48px;bottom:0;left: 0;width: 200px;
            
                <a class="menu" href="/cmdb/user_info/">用户管理</a>
                <a class="menu" href="/cmdb/user_group/">用户组管理</a>
            </div>
            <div style="position: absolute;top:48px;left: 210px;bottom:0;right: 0;overflow: auto">
                <h1>用户详细信息</h1>
                <h5>{{ obj.id }}</h5>
                <h5>{{ obj.username }}</h5>
                <h5>{{ obj.password }}</h5>
            </div>
        </div>
    
    # user_edit.html
    
        <div style="height: 48px;color: white;">welcome</div>
        <div>
            <div style="position: absolute;top:48px;bottom:0;left: 0;width: 200px;
            
                <a class="menu" href="/cmdb/user_info/">用户管理</a>
                <a class="menu" href="/cmdb/user_group/">用户组管理</a>
            </div>
            <div style="position: absolute;top:48px;left: 210px;bottom:0;right: 0;overflow: auto">
                <h1>编辑用户</h1>

                <form action="/cmdb/useredit-{{ obj.id }}/"method="POST">
                    <input style="display: none" type="text"name="id" value="{{ obj.id }}">
                    <input type="text"name="username" value="{{ obj.username }}">
                    <input type="text" name="password" value="{{ obj.password }}">
                    <input type="submit">
                </form>
            </div>
        </div>
    
    # admin.py
    
        from django.contrib import admin
        from app01 import models
        # Register your models here.
        admin.site.register(models.UserInfo)


        
        
- 示例(主机、业务线、应用 获取表单3方式、一对多、多对多操作,ajax)

    # urls.py
    
        from app01 import views
        urlpatterns = [
            url(r'^admin/', admin.site.urls),
            url(r'^business$', views.business),
            url(r'^host$', views.host),
            url(r'^test_ajax', views.test_ajax),
            url(r'^app$', views.app),
            url(r'^ajax_add_app$', views.ajax_add_app),
        ]

    # models.py
    
        from django.db import models

        # Create your models here.
        # class Foo(models.Model):
        #     name = models.CharField(max_length=1)
        #     row.b.fk.name

        class Business(models.Model):
            # id
            caption=models.CharField(max_length=32)
            code = models.CharField(max_length=32,null=True,default='SA')
            # fk = models.ForeignKey('Foo')

        class Host(models.Model):
            nid = models.AutoField(primary_key=True)
            hostname= models.CharField(max_length=32,db_index=True)
            ip = models.GenericIPAddressField(protocol='ipv4',db_index=True)
            port = models.IntegerField()
            b = models.ForeignKey(to = 'Business',to_field='id')


        # 多对多
        class Application(models.Model):
            name=models.CharField(max_length=32)
            r =models.ManyToManyField('Host')
        # app01.application_r 表 id,application_id,host_id

        # 手动创建
        # class HostToApp(models.Model):
        #     hobj = models.ForeignKey(to='Host',to_field='nid')
        #     aobj = models.ForeignKey(to='Application',to_field='id')
        # app01_hosttoapp 表 id,aobj_id,hobj_id

    # views.py

        from django.shortcuts import render,HttpResponse,redirect
        from app01 import models
        # Create your views here.
        def business(request):
            v1 = models.Business.objects.all()
            # QuerySet[obj(id,caption,code),obj]    内部为对象
            v2 = models.Business.objects.all().values('id','caption')
            # QuerySet[{'id':1,'caption':'xxx'},{},{}]  内部为列表
            v3 = models.Business.objects.values_list('id','caption')
            # QuerySet[(1,xxx),(2,yyy)] 内部为元组
            return  render(request,'business.html',{'v1':v1,'v2':v2,'v3':v3})

        """
        def host(request):
            v1 = models.Host.objects.filter(nid__gt=0)
            # for row in v1:
            #     print(row.nid,row.hostname,row.ip,row.port,row.b_id,row.b.caption,row.b.code,row.b.id,sep='\t')

            v2 = models.Host.objects.filter(nid__gt=0).values('nid','hostname','b_id','b__caption')
            # models.Host.objects.后面跨表用双下划线: "__" ,为普通字符串,取值时为对象
            # print(v2)
            # QuerySet[{内部为字典},{字典}]
            # for row in v2:
            #     print(row['nid'],row['hostname'],row['b_id'],row['b__caption'])

            v3 = models.Host.objects.filter(nid__gt=0).values_list('nid','hostname','b_id','b__caption')
            return  render(request,'host.html',{'v1':v1,'v2':v2,'v3':v3})
        """

        def host(request):
            if request.method =='GET':
                v1 = models.Host.objects.filter(nid__gt=0)
                v2 = models.Host.objects.filter(nid__gt=0).values('nid','hostname','b_id','b__caption')
                v3 = models.Host.objects.filter(nid__gt=0).values_list('nid','hostname','b_id','b__caption')
                b_list = models.Business.objects.all()
                return  render(request,'host.html',{'v1':v1,'v2':v2,'v3':v3,'b_list':b_list})
            elif request.method=='POST':
                h = request.POST.get('hostname')
                i = request.POST.get('ip')
                p = request.POST.get('port')
                b = request.POST.get('b_id')
                models.Host.objects.create(hostname =h,
                                           ip=i,
                                           port=p,
                                           b_id=b)
                # return render(request,'host.html')
                return redirect('/host')

        def test_ajax(request):
            import json
            ret={'status':True,'error':None,'data':None}
            try:
                h = request.POST.get('hostname')
                i = request.POST.get('ip')
                p = request.POST.get('port')
                b = request.POST.get('b_id')
                if h and len(h) > 5:
                    models.Host.objects.create(hostname =h,
                                               ip=i,
                                               port=p,
                                               b_id=b)
                else:
                    ret['status'] = False
                    ret['error'] = 'too lower'
            except Exception as e:
                ret['status']= False
                ret['error'] = '请求错误'
            return HttpResponse(json.dumps(ret))

        def app(request):
            if request.method=='GET':
                app_list=models.Application.objects.all()
                # for row in app_list:
                #     print(row.name,row.r.all())
                host_list = models.Host.objects.all()
                return render(request,'app.html',{'app_list':app_list,'host_list':host_list})
            elif request.method == 'POST':
                app_name =request.POST.get('app_name')
                host_list =request.POST.getlist('host_list')
                print(app_name,host_list)
                obj= models.Application.objects.create(name=app_name)
                # obj 为刚才操作过的
                obj.r.add(*host_list)
                return redirect('/app')

        import json
        def ajax_add_app(request):
            # 创建ret,待写
            ret={'status':True,'error':None,'data':None}
            app_name= request.POST.get('app_name')
            host_list= request.POST.getlist('host_list')
            obj= models.Application.objects.create(name=app_name)
            obj.r.add(*host_list)
            return HttpResponse(json.dumps(ret))
            
    # business.html

        <!DOCTYPE html>
        <html lang="en">
        <head>
            <meta charset="UTF-8">
            <title></title>
        </head>
        <body>
            <h1>业务线列表(对象)</h1>
            <ul>
                {%  for row in v1 %}
                    <li>{{ row.id }} - {{ row.caption }} - {{ row.code }}</li>
                {% endfor %}
            </ul>
            <h1>业务线列表(字典)</h1>
            <ul>
                {%  for row in v2 %}
                    <li>{{ row.id }} - {{ row.caption }}</li>
                {% endfor %}
            </ul>
            <h1>业务线列表(元组)</h1>
            <ul>
                {%  for row in v3 %}
                    <li>{{ row.0 }} - {{ row.1 }}</li>
                {% endfor %}
            </ul>
        </body>
        </html>

    # host.html

        <!DOCTYPE html>
        <html lang="en">
        <head>
            <meta charset="UTF-8">
            <title></title>
            <style>
                .hide{display: none}
                .shade{position: fixed;top:0;right: 0;left: 0;bottom: 0;
                    background: black;opacity: 0.6;z-index:100; }
                .add-modal,.edit-modal{position: fixed;height: 300px;width:400px;top:100px;left: 50% ;
                    border:1px solid green;z-index: 101;background: white;margin-left: -200px;}
            </style>
        </head>
        <body>
            <h1>主机列表(对象)</h1>
            <div>
                <input id='add_host' type="button"value="添加">
            </div>
            <table border="1">
                <thead>
                    <tr>
        {#                <th>主机ID</th>#}
                        <th>序号</th>
                        <th>主机名</th>
                        <th>IP</th>
                        <th>端口</th>
        {#                <th>业务线ID</th>#}
                        <th>业务线名称</th>
                        <th>操作</th>
        {#                <th>业务线编码</th>#}
                    </tr>
                </thead>
                <tbody>
        {#        {% for i in v1 %}#}
                    {% for row in v1 %}
                        <tr hid="{{ row.nid }}" bid="{{ row.b_id }}">
                        // 将两个id 放置于此处,待用。
        {#                    <td>{{ row.nid }}</td>#}
                            <td>{{ forloop.counter}}</td>
                            <td>{{ row.hostname }}</td>
                            <td>{{ row.ip }}</td>
                            <td>{{ row.port }}</td>
        {#                    <td>{{ row.b_id }}</td>#}
                            <td>{{ row.b.caption }}</td>
                            <td><a class="edit">编辑</a>|<a class="delete">删除</a></td>
                            // 实现删除时,可通过Form表单或Ajax操作,Ajax操作时可找到页面当前行,进行删除。
        {#                    <td>{{ row.b.code }}</td>#}
                        </tr>
                    {% endfor %}
        {#        {% endfor %}#}
                </tbody>
            </table>


            <h1>主机列表(字典)</h1>
            <table border="1">
                <thead>
                    <tr>
                        <th>主机名</th>
                        <th>业务线名称</th>
                    </tr>
                </thead>
                <tbody>
                    {% for row in v2 %}
                        <tr hid="{{ row.id }}" bid="{{ row.b_id }}">
                            <td>{{ row.hostname }}</td>
                            <td>{{ row.b__caption }}</td>
                        </tr>
                    {% endfor %}
                </tbody>
            </table>

            <h1>主机列表(元组)</h1>
            <table border="1">
                <thead>
                    <tr>
                        <th>主机名</th>
                        <th>业务线名称</th>
                    </tr>
                </thead>
                <tbody>
                    {% for row in v3 %}
                        <tr hid="{{ row.0 }}" bid="{{ row.2 }}">
                            <td>{{ row.1 }}</td>
                            <td>{{ row.3 }}</td>
                        </tr>
                    {% endfor %}
                </tbody>
            </table>

            <div class="shade hide"></div>

            <div class="add-modal hide">
                <form id='add_form'action="/host"method="POST">
                    // 未含验证功能,待Ajax
                    <div class="group"><input id="host" type="text"placeholder="主机名"name="hostname"></div>
                    <div class="group"><input id="ip" type="text"placeholder="ip"name="ip"></div>
                    <div class="group"><input id="port" type="text"placeholder="端口"name="port"></div>
                    <div class="group"><select name="b_id" id="sel">
                        {% for op in b_list %}
                            <option value="{{ op.id }}">{{ op.caption }}</option>
                        {% endfor %}
                    </select></div>
                    <input type="submit"value="提交">
                    <a id="ajax_submit" style="display: inline-block;padding: 5px;
                    color: white">Ajax提交</a>
                    <input id="cancel" type="button"value="取消">
                    <span id="erro_msg" style="color: red;"></span>
                </form>
            </div>

            <div class="edit-modal hide">
                <form id='edit_form'action="/host"method="POST">
                    <input type="text"name="nid" style="display: none;">
                    // 额外添加,修改后提交时获取host的id使用
                    <input type="text"placeholder="主机名"name="hostname">
                    <input type="text"placeholder="ip"name="ip">
                    <input type="text"placeholder="端口"name="port">
                    <select name="b_id" id="sel">
                        {% for op in b_list %}
                            <option value="{{ op.id }}">{{ op.caption }}</option>
                        {% endfor %}
                    </select>

                    <a id="ajax_sumit_edit">确认编辑</a>
                </form>
            </div>


            <script src="/static/jquery-1.12.4.js"></script>
            <script>
                $(function () {
                    // 模态对话框
                    $('#add_host').click(function () {
                        $('.shade,.add-modal').removeClass('hide');
                    });
                    $('#cancel').click(function () {
                        $('.shade,.add-modal').addClass('hide');
                    })
                });

                // Ajax 提交
                $('#ajax_submit').click(function () {
                    $.ajax({
                        url:'/test_ajax',
                        type:"POST",
        {#                data:{'hostname':$('#host').val(),#}
        {#                    'ip':$('#ip').val(),#}
        {#                    'port':$('#port').val(),#}
        {#                    'b_id':$('#sel').val()#}
        {#                    },#}
                        data:$('#add_form').serialize(),
                        success: function (data) {
                            var obj =JSON.parse(data);
                            if (obj.status){
                                location.reload();
                            }else{
                                 $("#erro_msg").text(obj.error);
                            }
                        }
                    })
                });

                // Ajax 编辑
                $('.edit').click(function () {
                    $('.shade,.edit-modal').removeClass('hide');

                    // 只实现了多选,其他待添加

                    var bid= $(this).parent().parent().attr('bid');
                    // ** 获取编辑行修改前的 business 的 id
                    var nid= $(this).parent().parent().attr('hid');
                    // @@ 获取当前编辑行host的 id

                    console.log(bid,nid);
                    $('#edit_form').find('select').val(bid);
                    // ** 将 bid 赋值给模态对话框 select标签:选中状态

                    $('#edit_form').find('input[name="nid"]').val(nid);
                    // @@ 将当前编辑的host id 赋值给 模态框 额外添加的input框

                    $.ajax({
                        url:'',
                        data:$('#edit_form').serialize()
                    });
                    // models.Host.object.filter(nid=nid).update()
                });
            </script>
        </body>
        </html>

    # app.py
    
        <!DOCTYPE html>
        <html lang="en">
        <head>
            <meta charset="UTF-8">
            <title></title>
            <style>
                .host-tag{display: inline-block;padding: 3px;border: 1px solid red;}
            </style>
            <style>
                .hide{display: none}
                .shade{position: fixed;top:0;right: 0;left: 0;bottom: 0;
                    background: black;opacity: 0.6;z-index:100; }
                .add-modal,.edit-modal{position: fixed;height: 300px;width:400px;top:100px;left: 50% ;
                    border:1px solid green;z-index: 101;background: white;margin-left: -200px;}
            </style>
        </head>
        <body>
            <h1>****** 多对多*******</h1>
            <h1>应用列表</h1>
            <div>
                <input id='add_app' type="button"value="add">
            </div>
            <table border="1">
                <thead>
                    <tr>
                        <td>应用名称</td>
                        <td>应用主机列表</td>
                    </tr>
                </thead>
                <tbody>
                    {% for app in app_list %}
                        <tr aid = '{{ app.id }}'>
                        // 定制aid 为编辑使用
                            <td>{{ app.name }}</td>
                            <td>
                                {% for host in app.r.all %}
                                    <span class='host-tag' hid="{{ host.nid }}">{{ host.hostname }}</span>
                                    // hid="{{ host.nid }} 额外添加,为编辑使用准备
                                    // 后面添加 删除 图标,进行删除,待写。
                                {% endfor %}
                            </td>
                            <td><a class="edit">编辑</a></td>
                        </tr>
                    {% endfor %}
                </tbody>
            </table>

            <div class="shade hide"></div>
            <div class="add-modal hide">
                <form id='add_form' action="/app" method="POST">
                    <div class="group"><input id="app_name" type="text"placeholder="应用名称"name="app_name"></div>

                    <div class="group"><select name="host_list" id="host_list" multiple>
                        {% for op in host_list %}
                            <option value="{{ op.nid }}">{{ op.hostname }}</option>
                        {% endfor %}
                    </select></div>
                    <input type="submit"value="提交">
                    <input id="add_submit_ajax" type="button"value="ajax提交">

                </form>
            </div>

            <div class="edit-modal hide">
                <form id='edit_form' action="/host" method="POST">
                    <input type="text"name="nid" style="display: none;">
                    <input type="text"placeholder="应用名称"name="app">
                    <select name="host_list"  multiple>
                        {% for op in host_list %}
                            <option value="{{ op.nid }}">{{ op.hostname }}</option>
                        {% endfor %}
                    </select>

                    <a id="ajax_sumit_edit">编辑</a>
                </form>
            </div>

            <script src="/static/jquery-1.12.4.js"></script>
            <script>
                $(function () {
                    $('#add_app').click(function () {
                        $('.shade,.add-modal').removeClass('hide');
                    });
                    $('#cancel').click(function () {
                        $('.shade,.add-modal').addClass('hide');
                    });
                    $("#add_submit_ajax").click(function () {
                        $.ajax({
                            url:'/ajax_add_app',
        {#                    data:{'user':123,'host_list':[1,2,3,4]},#}
                            data:$('#add_form').serialize(),
                            type:'POST',
                            dataType:JSON,
                            traditional:true,
                            // 添加后才能处理: []
                            success: function (obj) {
                                console.log(obj);
                                // 拿到ret进行判断、跳转,待写。
                            },
                            error: function () {
                            }
                        });
                    });

                    // 编辑功能
                    $('.edit').click(function () {
                        $('.edit-modal,.shade').removeClass('hide');

                        // 仅做了 主机 多选项,其他待写。
                        var hid_list=[];
                        $(this).parent().prev().children().each(function () {
                            // 对span标签循环,获取hid
        {#                    var text= $(this).text();#}  // 获取主机名
                            var hid = $(this).attr('hid');  // 获取value
                            hid_list.push(hid)
                        });
                        //select 设置多选后,value 是个列表
                        $('#edit_form').find('select').val(hid_list);
                        //发送到后台 obj=model.Application.objects.get(id=aid)
                        // obj.name= New name
                        // obj.save()
                        // obj.r.set([1,2,3,])
                    });
                });

            </script>
        </body>
        </html>

   

posted @ 2020-01-16 20:45  badweather  阅读(115)  评论(0编辑  收藏  举报