zoukankan      html  css  js  c++  java
  • Django Model

    1. ORM 简介

    MTV 设计模式中,模型(M)就是对数据库的操作,在 Web 开发中,使用最频繁的也是对数据库的操作,那么该怎么样去实现呢?

    我们不可能自己手动去写大量的 SQL 语句,因为我们也不是专业 DBA 人员,那么我们就只能奢求有一种能够使用 Python 程序对数据库操作的方法了。这就是 ORM(Object Relation Mapping)对象关系映射,以面向对象的方式去操作数据库。

    其实现模式大致是这样的:

    Django 本身给我们提供了强大的 ORM 系统,不需要再额外的
    安装,当然还有一些其他的 ORM ,如:SQLAlch 等。

    2. 字段

    Model 中的字段 fileds 即数据表中的列,用来存储数据(记录),字段类型对应列的数据类型。

    2.1 常用字段类型

    Django 内置了很多字段类型,都位于 django.db.models 中,以下为常用字段类型:

    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
    
    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
        - auto_now_add=True		当在首次创建对象时自动将字段设置为现在。用于创建时间戳
        - auto_add=True			每次保存对象时,自动将字段设置为现在。用于“最后修改”的时间戳
    
    TimeField(DateTimeCheckMixin, Field)
        - 时间格式      HH:MM[:ss[.uuuuuu]]
    
    DurationField(Field)
        - 长整数,时间间隔,数据库中按照bigint存储,ORM中获取的值为datetime.timedelta类型
    
    FloatField(Field)	
        - 浮点型,精确的数不能用 FloatField
    
    DecimalField(Field)
        - 10进制小数,对于比较精确的数可以用 DecimalField
        - 参数:
            max_digits,小数总长度
            decimal_places,小数位长度
    
    BinaryField(Field)
        - 二进制类型
    

    2.2 字段参数

    null                数据库中字段是否可以为空
    db_column           数据库中字段的列名
    default             数据库中字段的默认值
    primary_key         数据库中字段是否为主键
    db_index            数据库中字段是否可以建立索引
    unique              数据库中字段是否可以建立唯一索引
    unique_for_date     数据库中字段【日期】部分是否可以建立唯一索引
    unique_for_month    数据库中字段【月】部分是否可以建立唯一索引
    unique_for_year     数据库中字段【年】部分是否可以建立唯一索引
    
    verbose_name        Admin中显示的字段名称
    blank               Admin中是否允许用户输入为空
    editable            Admin中是否可以编辑
    help_text           Admin中该字段的提示信息
    choices             Admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作
                        如:gf = models.IntegerField(choices=[(0, '何穗'),(1, '大表姐'),],default=1)
    
    error_messages      自定义错误信息(字典类型),从而定制想要显示的错误信息;
                        字典健:null, blank, invalid, invalid_choice, unique, and unique_for_date
                        如:{'null': "不能为空.", 'invalid': '格式错误'}
    
    validators          自定义错误验证(列表类型),从而定制想要的验证规则
                        from django.core.validators import RegexValidator
                        from django.core.validators import EmailValidator,URLValidator,DecimalValidator,
                        MaxLengthValidator,MinLengthValidator,MaxValueValidator,MinValueValidator
                        如:
                            test = models.CharField(
                                max_length=32,
                                error_messages={
                                    'c1': '优先错信息1',
                                    'c2': '优先错信息2',
                                    'c3': '优先错信息3',
                                },
                                validators=[
                                    RegexValidator(regex='root_d+', message='错误了', code='c1'),
                                    RegexValidator(regex='root_112233d+', message='又错误了', code='c2'),
                                    EmailValidator(message='又错误了', code='c3'), ]
                            )
    
    1. null
    用来保存空值,默认值 false。对于保存字符串的字段,尽量避免将其设置为 true,否则可能会导致出现是 null 或空字符串
    
    2. blank
    表示字段可以为空,默认 false。常用语表单输入验证是否为空,与数据库无关。
    
    3. choices
    页面上选择框标签,二维元组格式。两个参数,第一个为存储在数据库中,第二个显示在页面上内容。
    数据库存储的是0 、1 、2,而页面上显示的是篮球、足球、羽毛球
    hobby_choices = [(0, '篮球'), (1, '足球'), (2, '羽毛球'),]
    
    hobby = models.IntegerField(
        choices=hobby_choices
    )
    
    4. primary_key 
    主键,如果没有指定主键,那么 Django会自动创建一个 AutoField的自增字段,名为 id,并将其设置为主键。
    
    primary_key 相当于 null=False和unique=True,即唯一且不能为空,你也可以自己将其他字段设置为空,若有必要。 
    
    

    示例

    from django.db import models
    
    class UserInfo(models.Model):
        username = models.CharField(
            null=True,
            db_column='user',
            max_length=32,
            db_index=True,
            verbose_name='用户名',
            help_text='帮助信息',
            default='',
        )
    
        hobby_choices = [(0, '篮球'), (1, '足球'), (2, '羽毛球'),]
    
        hobby = models.IntegerField(
            choices=hobby_choices
        )
    
        def __str__(self):
            return self.username
    

    2.3 元类 Meta

    模型中的元类是指除了字段外的其他非必须内容,如修改数据表的名字,设置代理等。

    使用方式

    class User(models.Model):
        ...
    
        class Meta:
            verbose_name = '用户'
    
    1. abstract
    为 true 时,模型会被认为是一个抽象类,长用来作为其他模型的父类被继承。
    
    2. app_label
    如果没有在 settings 中注册 app,那么必须在元类中声名是属于哪个 app
    app_label = 'polls'
    
    3. base_manager_name
    自定义模型的 _base_manager 管理器的名字,模型管理器是 Django 为模型提供的 API
    
    4. db_table
    指定模型生成数据表时,数据表的表名
    db_table = 'user'
    
    5. db_tablespace
    自定义数据库表空间的名字。默认值是工程的DEFAULT_TABLESPACE设置
    
    6. default_manager_name
    自定义模型的_default_manager管理器的名字
    
    7. default_related_name
    反向查询时,默认我们使用的 `<model_name>_set` 也就是源模型名字+下划线+set 方法查询,当我们定义了 default_related_name时,就可以使用它来反向查询。
    
    8. ordering
    指定该模型生成的所有对象的排序方式,接收一个字段名组成的元组或列表。默认按升序排列,如果在字段名前加上字符“-”则表示按降序排列,如果使用字符问号“?”表示随机排列。
    
    ordering = ['pub_date']             # 表示按'pub_date'字段进行升序排列
    ordering = ['-pub_date']            # 表示按'pub_date'字段进行降序排列
    ordering = ['-pub_date', 'author']  # 表示先按'pub_date'字段进行降序排列,再按`author`字段进行升序排列。
    
    9. permissions
    该元数据用于当创建对象时增加额外的权限。它接收一个所有元素都是二元元组的列表或元组,每个元素都是(权限代码, 直观的权限名称)的格式。比如下面的例子:
    
    permissions = (("can_deliver_pizzas", "可以送披萨"),)
    
    10. default_permissions
    Django默认给所有的模型设置('add', 'change', 'delete')的权限,也就是增删改。你可以自定义这个选项,比如设置为一个空列表,表示你不需要默认的权限,但是这一操作必须在执行migrate命令之前
    
    11. proxy
    
    若为 true,表示使用代理模式的模型继承方式。
    
    12. required_db_vendor
    
    声明模型支持的数据库。Django默认支持sqlite, postgresql, mysql, oracle
    
    13. indexes
    
    接收一个应用在当前模型上的索引列表
    
    from django.db import models
    
    class Customer(models.Model):
        first_name = models.CharField(max_length=100)
        last_name = models.CharField(max_length=100)
    
        class Meta:
            indexes = [
                models.Index(fields=['last_name', 'first_name']),
                models.Index(fields=['first_name'], name='first_name_idx'),
            ]
    
    14. unique_together
    
    等同于数据库的联合约束,无法应用多对多字段。
    比如一张用户表,保存用户姓名、出生日期、地址等,现在有两个叫张伟的人,那么就可以使用联合唯一。
    
    # 表示 name、birth_day、address 联合唯一,即不能在同一地方、同一时刻出生且都叫张伟
    unique_together = (('name', 'birth_day', 'address'),)
    
    14. verbose_name
    给 Admin 提供人性化的名称,支持中文,如:
    verbose_name = '用户'   # 那么 Admin 中显示的就是 用户
    
    15. label
    只读元数据,不可修改,相当于 polls.Question
    

    3. 多表关系及参数

    • 一对一:Foreignkey 基础上加一个唯一索引 unique
    • 一对多:ForeignKey
    • 多对多:ManyToMany(两个一对多,两个 ForeignKey 相连)

    3.1 一对多模型

    一对多模型,如:员工部门表,一个部门可以有多个员工。那么 Django 怎么建立这种关系呢?

    其实就是通过外键 ForeignKey 进行关联,在多的一方,字段指定外键即可

    ForeignKey 字段参数

    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",		# 关联 User 表
                                    to_field="id"	# 关联 User 表 的  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中是否显示关联数据
    

    示例:

    class Department(models.Model):
        """部门表"""
        name = models.CharField(max_length=32)
        create_data = models.DateField(auto_now_add=True)	# 创建时间
        id_delete = models.BooleanField(default=False)		# 是否可删除
        
        class Meta:
            db_table = 'department'
        
        
    class Employee(models.Model):
        """员工表"""
        name = models.CharField(max_length=32)
        age = models.IntegerField()
        gender = models.IntegerField(default=0)
        salary = models.DecimalField(max_digits=8, decimal_places=2)	# max_digits 表示八个数字,包括两位小数,decimal_places 表示保留两位小数
        
        # null=True 表示可以为空, blank=True 表示 Django admin 后台可以输入空
        comment = models.CharField(max_length=300, null=True, blank=True)	
        hire_data = models.DateField(auto_now_add=True)
        department = models.ForeignKey('Department')		# 外键字段
        
        class Meta:
            db_table = 'employee'		# 数据表名字
    

    Tips

    在设置外键时,需要给子表(有外键的表)指定当主表(被连接的表)删除数据时,从表该如何处理。Django 通过设置 on_delete 属性来控制,它有三种值:

    • 删除时报错:DO_NOTHING/PROTECT
    • 级联删除:主表删除数据,从表与之关联的数据也将被删除:CASCADE
    • 设置默认值:SET_NULL/SET_DEFAULTset_null 仅在字段可以是 null 时才能使用

    3.2 一对一模型

    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)
        
    # 使用 OneToOneField 字段创建一对一模型
    class Person(models.Model):
        name = models.CharField(max_length=32)
        o2o = models.OneToOneField(to='Person_detail', to_field='id', on_delete=models.CASCADE)
        
    class Person_detal(models.Model):
        age = models.IntegerField()
        gender_choices = [(0, '男'), (1, '女')]
        gender = models.IntegerField(
            choices=gender_choices,
            default=0,
        )
        height = models.PositiveIntegerField()      # 正整数
        email = models.EmailField(max_length=64)
    
    

    3.3 多对多模型

    多对多其实就是两个一对多,通过两个外键将三张表相连,其中第三张表存储了前面两张表的对应关系。例如:名字和爱好表,一个人可以有多个爱好,一个爱好也可以是多个人有。

    如何创建三张表:

    • 自动创建:ManyToMangField 字段自动创建,不能新增列
    • 手动创建:元 Meta,可以新增列
    • 手动加自动:元 Meta + ManyToMangField

    多对多 ManyToManyField 字段参数:

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

    自动创建

    class UserInfo(models.Model):
        username = models.CharField(max_length=32, verbose_name='用户名')
        m = models.ManyToManyField(
        	to = 'Tag',
            related_name = 'bb',
        )
        
    class Tag(models.Model):
        title = models.CharField(max_length=32)
    
    

    手动创建

    class UserInfo(models.Model):
        username = models.CharField(max_length=32, verbose_name='用户名')
        
    class Tag(models.Model):
        title = models.CharField(max_length=32)
        
    # 手动创建第三张表
    class UserToTag(models.Model):
        tid = models.AutoField(primary_key=True)
        u = models.ForeignKey('UserInfo', on_delete=models.CASCADE)		# 通过外键相连
        t = models.ForeignKey('Tag', on_delete=models.CASCADE)
    
        #  联合唯一索引
        class Meta:
            unique_together = [
                ('u', 't'),
            ]
    
    

    手动加自动

    class UserInfo(models.Model):
        username = models.CharField(max_length=32, verbose_name='用户名')
        m = models.ManyToManyField(
        	through = 'UserToTag',		# 指定第三张表,不自动创建
            through_fields = ['u', 't']		# 指定第三张表的字段
        )
        
    class Tag(models.Model):
        title = models.CharField(max_length=32)
        
    # 手动创建第三张表
    class UserToTag(models.Model):
        tid = models.AutoField(primary_key=True)
        u = models.ForeignKey('UserInfo', on_delete=models.CASCADE)		# 通过外键相连
        t = models.ForeignKey('Tag', on_delete=models.CASCADE)
    
        #  联合唯一索引
        class Meta:
            unique_together = [
                ('u', 't'),
            ]
    
    

    3.4 自关联模型

    自关联模型,即表中的某列关联表中另一列。最典型的自关联模型就是地区表(省市县三级联动)省的 pid 为 null,市的 pid 为省的 id,县的 pid 为市的 id。具体如下:

    自关联表现形式

    • 省的 parent_id 为 null
    • 市的 parent_id 为对应省的 id
    • 区的 parent_id 为对应市的 id
    1. 数据库设计 models.py
    class Area(models.Model):
        name = models.CharField(max_length=32, verbose_name='名称')
        parent = models.ForeignKey('self',          # 自关联字段的外键指向自身,也可以是 Area
                                   verbose_name='上级行政区划',
                                   on_delete=models.SET_NULL,
                                   related_name='subs',
                                   null=True,
                                   blank=True
                                   )
    
        class Meta:
            db_table = 'tb_areas'       # 自定义表名
            verbose_name = '行政区划'   # admin 中显示的名称
            verbose_name_plural = '行政区划'
    
        def __str__(self):
            return self.name
    
    

    自关联模型,最核心的地方就是自己关联自己 self/Area,用一张表做两张表才能做的事。

    1. 路由系统 app/urls.py
    from django.urls import path
    from app import views
    
    urlpatterns = [
        path('area/', views.area, name='area'),
        path('getPro/', views.getPro, name='getArea'),
        path('getCity/', views.getCity, name='getCity'),
        path('getDis/', views.getDis, name='getDis'),
    ]
    
    
    1. 视图函数 views.py
    from django.shortcuts import render, HttpResponse
    from app import models
    from django.http import JsonResponse
    
    # 访问 http://127.0.0.1:8000/app/area/,返回 area.html
    def area(request):
        return render(request, 'area.html')
    
    
    def getPro(request):
        """获取省份信息"""
        pro_list = models.Area.objects.filter(parent_id=None)		# 省份的 parent_id 为 None
        res = []
        for i in pro_list:
            res.append([i.id, i.name])
        print(res)      # [[1, '广东省'], [7, '湖南省']]
        return JsonResponse({'pro_list': res})		# JsonResponse 打包成 json 格式字符串
    
    
    def getCity(request):
        """获取市信息"""
        city_id = request.GET.get('city_id')
        city_list = models.Area.objects.filter(parent_id=int(city_id))
        res = []
        for i in city_list:
            res.append([i.id, i.name])
    
        print('city', res)      #  [[2, '深圳市'], [3, '广州市'], [6, '湛江市']]
        return JsonResponse({'city_list': res})
    
    
    def getDis(request):
        """获取区信息"""
        dis_id = request.GET.get('dis_id')
        dis_list = models.Area.objects.filter(parent_id=int(dis_id))
        res = []
        for i in dis_list:
            res.append([i.id, i.name])
        return JsonResponse({'dis_list': res})
    
    
    1. 模板 area.html
    {% load static %}
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <select id="pro">
            <option value="">请选择省份</option>
        </select>
    
        <select id="city">
            <option value="">请选择城市</option>
        </select>
    
        <select id="dis">
            <option value="">请选择区</option>
        </select>
    
    <script src="{% static 'jquery-3.1.1.js' %}"></script>
    <script>
        $(function () {
            var pro = $('#pro');
            var city = $('#city');
            var dis = $('#dis');
    
            // 查询省信息,$.get() 为 $.ajax 的简化版
            // 向 /app/getPro/ 发送 ajax 请求,arg 为请求成功返回的信息
            $.get('/app/getPro/', function (arg) {			
                console.log(arg);   // {'pro_list': [[1, '广东省'],[7, '湖南省']]}
    
                $.each(arg.pro_list, function (index, item) {
                    console.log(item);      // [1, '广东省'] 、[7, '湖南省']
                    console.log(index);     // 0、1
                    
                    // 将从数据库中取出的数据添加到 option 标签中,其中 value 为 id,文本值为 name
                    var $new = $("<option value="+ item[0] +">" + item[1] + "</option>");
                    pro.append($new);
                });
                
    {# 或者使用 JavaScript for 循环#}
    {#            console.log(arg.pro_list);#}
    {#            for (var i = 0, len=arg.pro_list.length; i<len; i++){#}
    {#                var $new = $('<option value='+ arg.pro_list[i][0] +'>' + arg.pro_list[i][1] + '</option>')#}
    {#                pro.append($new);#}
    {#            }#}
    
            });
    
            // 根据省的变化查询市,改变省时,清空市和区
            pro.change(function () {
                city.empty().append('<option value="">请选择市</option>');
                dis.empty().append('<option value="">请选择市</option>');
                $.ajax({
                    url: '/app/getCity/',
                    type: 'get',
                    data: {'city_id': $(this).val()},
                    success: function (arg) {
                        $.each(arg.city_list, function (index, item) {
                            var $new = $('<option value='+ item[0]+'>' + item[1] + '</value>');
                            city.append($new);
                        })
                    }
                })
            });
    
            // 根据市变化查询区,改变市,清空区
            city.change(function () {
                dis.empty().append('<option value="">请选择市</option>');
                $.ajax({
                    url: '/app/getDis/',
                    type: 'get',
                    data: {'dis_id': $(this).val()},
                    success: function (arg) {
                        console.log('区', arg.dis_list);     // [[4, '宝安区'], ]
                            $.each(arg.dis_list, function (index, item) {
                                console.log(item[1]);
                                var $new = $('<option value='+ item[0] +'>' + item[1] + '</value>');
                                dis.append($new);
                        })
                    }
                })
            })
    
        })
    </script>
    </body>
    </html>
    
    

    当访问 http://127.0.0.1:8000/app/area/ 时,会向 /app/getPro/ 发送 ajax 请求,请求成功获得包含省份 id、name 的信息 {'pro_list': [[1, '广东省'],[7, '湖南省']]}。取出数据遍历循环,添加到 option 标签中,从而获得省份信息。

    当我们改变省份时,将上一次省份的市、区信息清空,避免添加重复。获取当前省份的 id,并向 /app/getDis/ 发送 ajax 请求,从而获得相应市的信息,同理区也是一样。

    1. 添加数据 views.py

    添加数据,可以用 pycharm 自带的数据库添加,也可以手动添加:

    def add(request):
        models.Area.objects.create(id=7, name='湖南省', parent_id=None)
        models.Area.objects.create(id=8, name='长沙市', parent_id=7)
        models.Area.objects.create(id=9, name='雨花区', parent_id=8)
    
        return HttpResponse('添加成功')
    
    

    参考博客:

    3.5 知识点补充

    Ajax 的 get() 方法,它可以向后台发送 ajax 请求,请求成功可调用回调函数。如果需要在出错时执行函数,请使用 $.ajax,它是 $.ajax 简化版本。

    语法

    $(selector).get(url, data, success(response, status, xhr), dataType);	// 除了 url 必需,其他都可选,status 为请求状态,xhr - 包含 XMLHttpRequest 对象
    
    
    $('button').click(function(){
        get('/app/getdata/', function(arg){});
    });
    
    

    3.6 Model 常用设计模型示例及方法

    3.6.1 Model 设计

    总共四张表,分别是班级、学生、学生个人信息以及老师表,之间的关系如下:

    class Class(models.Model):
        """班级表"""
        class_name = models.CharField(max_length=32)
        create_data = models.DateField()
    
        def __str__(self):
            return self.class_name
    
        class Meta:
            verbose_name = '班级'
    
    
    class Student(models.Model):
        """
        学生表
        一每个学生都有对应的个人信息(一对一),一个班级可以有多个学生(一对多)
        """
        student_name = models.CharField(max_length=32)
    
        # 一对多,与班级关联
        sc = models.ForeignKey(to='Class', to_field='id', related_name='stu', on_delete=models.CASCADE)
    
        # 一对一,与学生个人信息关联
        detail = models.OneToOneField('StudentDetail', to_field='id', on_delete=models.CASCADE)
    
        class Meta:
            verbose_name = '学生'
    
        def __str__(self):
            return self.student_name
    
    
    class StudentDetail(models.Model):
        """学生个人信息表"""
        age = models.IntegerField()
        gender_choices = [(0, '男'), (1, '女')]
        gender = models.IntegerField(
            choices=gender_choices,
            default=0,
        )
        height = models.PositiveIntegerField()      # 正整数
        email = models.EmailField(max_length=64)
    
    
    class Teacher(models.Model):
        """
        老师表
        一个老师可以教多个班,一个班也可以有多个老师
        """
        teacher_name = models.CharField(max_length=32)
        tc = models.ManyToManyField(to='Class', related_name='b')
    
        class Meta:
            verbose_name = '老师'
    
        def __str__(self):
            return self.teacher_name
    
    
    1. 老师表 app_teacher

    1. 学生个人信息表 app_student_detail

    1. 学生表 app_student

    1. 班级表 app_class

    1. 老师、班级关系表(第三张表)app_teacher_tc

    3.6.2 查询操作

    def query(request):
        ########### 一对一 #####################
        # 正向查询(根据外键字段)
        # 根据学生名字查询其个人信息
        # obj = models.Student.objects.filter(student_name='rose')[0]
        # print(obj)
        # print(obj.detail.age, obj.detail.gender, obj.detail.height, obj.detail.email)
        # # 17 1 170 456@qq.com
    
    
        # 反向查询(根据要查询的数据表名)
        # 根据邮箱查询学生名字
        # obj2 = models.StudentDetail.objects.filter(email='456@qq.com')[0]
        # print(obj2)         # <QuerySet [<StudentDetail: StudentDetail object (2)>]>
        #
        # print(obj2.student.student_name)        # rose
    
    
        ############## 一对多(班级表和学生表) ##################
        # 正向查询
         # 根据学生名查询所属班级
        # obj3 = models.Student.objects.get(student_name='rose')
        # print(obj3.sc_id)   # 1
        # print(type(obj3.sc))      # <class 'app.models.Class'>
        # print(obj3.sc.class_name)   # 一班
    
    
        # 反向查询
        # 二班有哪些学生
        # obj4 = models.Class.objects.filter(class_name='二班')[0]
        # print(obj4)
        # # res = obj4.student_set.all()     # 如果外键字段没有设置 related_name 就用 表名_set
        # res = obj4.stu.all()
        # print(res)       # <QuerySet [<Student: john>, <Student: lila>]>
        # for i in res:
        #     print(i.student_name)   # john、lila
    
        # 方法二
        # ret = models.Student.objects.filter(sc=obj4).values('student_name')   # 字典形式
        # print(ret)      # <QuerySet [{'student_name': 'john'}, {'student_name': 'lila'}]>
        # for i in ret:
        #     print(i['student_name'])    # john、lila
    
        # # 双下划线
        # 正向
        obj4 = models.Class.objects.filter(class_name='二班').values('stu__student_name')
    
        # 反向
        obj5 = models.Student.objects.filter(sc__class_name='二班').values('student_name')
    
    
    
    ############################### 多对多(老师表与班级表) ############################################
        # 查看 孙老师教哪几个班
        # 正向查询(通过多对多字段)
    
        # obj5 = models.Teacher.objects.filter(teacher_name='孙老师')[0]
        # ret = obj5.tc.all()
        # print(ret)      # <QuerySet [<Class: 一班>, <Class: 二班>]>
        # for i in ret:
        #     print(i.class_name)
    
        # 查看一班有哪几个老师
        # 反向查询
        # obj5 = models.Class.objects.filter(class_name='一班')[0]
        # ret = obj5.b.all()
        # print(ret)          # < QuerySet[ < Teacher: 孙老师 >, < Teacher: 刘老师 >] >
        # for i in ret:
        #     print(i.teacher_name)       # 孙老师、刘老师
    
        # # 双下划线
        # # 如果没有设置 related_name = b,那么就是 values('teacher__name`) 即要查的表的表名__要查询的字段
        # obj6 = models.Class.objects.filter(class_name='一班').values('b__teacher_name')
        # print(obj6)     # <QuerySet [{'b__teacher_name': '孙老师'}, {'b__teacher_name': '刘老师'}]>
    
        # # 正向  tc = models.ManyToManyField(to='Class', related_name='b')
        # obj6 = models.Teacher.objects.filter(tc__class_name='一班').values('teacher_name')
    
        return HttpResponse('查询成功!')
    
    

    3.6.3 总结

    一对一、一对多、多对多,最好都设置好 related_name 参数,没有设置时,反向查找用 要查询的命名.查询字段 或 _set.all()

    查询分为:

    • 基于对象查询(相当于 SQL 中子查询)
      • 先获取相关对象:models.Models.objects.filter(过滤字段)
      • 再通过对象(正向、反向)查询相关字段
    • 基于 QuerySet 和双下划线查询(相当于 SQL 中连表查询)
      • 前面是过滤条件,后面跟要显示(查询)的字段
      • models.Model.objects.filter(过滤字段).values(要显示的字段)

    一对一

    • 正向查询:根据 OneToOneField 字段查询
    • 反向查询:根据 要查询的命名.查询字段查询
    # detail = models.OneToOneField('StudentDetail', to_field='id', on_delete=models.CASCADE)
    # 正向
    obj = models.Student.objects.filter(student_name='rose')[0]
    print(obj.detail.age)
    
    # 反向
    obj2 = models.StudentDetail.objects.filter(email='456@qq.com')[0]
    print(obj2.student.student_name)	# 这里没设置 related_name 因此用表名
    
    

    一对多

    • 正向查询:根据外键字段查询
    • 反向查询
      • 设置了related_name,就用这个名字查询
      • 没有设置,用表名_set 方式查询
    • 双下划线查询
      • 正向:filter(条件).values(要查询的表名__要查询字段)
      • 反向:filter(外键字段__条件).values(要查询字段)
    # sc = models.ForeignKey(to='Class', to_field='id', related_name='stu', on_delete=models.CASCADE)
    # 正向
    obj3 = models.Student.objects.get(student_name='rose')
    print(obj3.sc.class_name)	# 根据外键字段 sc 查询
    
    # 反向
    obj4 = models.Class.objects.filter(class_name='二班')[0]
    # res = obj4.student_set.all()	# 没设置 related_name,用表名_set
    res = obj4.stu.all()		# 用 related_name 名字
    
    # 双下划线
    # 正向
    obj5 = models.Class.objects.filter(class_name='二班').values('stu__student_name')
    
    # 反向
    obj6 = models.Student.objects.filter(sc__class_name='二班').values('student_name')
    
    

    多对多

    • 正向查询:ManyToManyField 字段查询
    • 反向查询:表名_set、related_name名字查询
    • 双下划线与一对多一样
    # tc = models.ManyToManyField(to='Class', related_name='b')
    # 正向
    obj5 = models.Teacher.objects.filter(teacher_name='孙老师')[0]
    print(obj5.tc.all())
    
    # 反向
    obj5 = models.Class.objects.filter(class_name='一班')[0]
    print(obj5.b.all())
    
    

    参考博客:django 一对一、一对多、多对多操作、常用方法

    4. 模型继承

    Django中所有的模型都必须继承 django.db.models.Model 模型,同样地我们也可以自己创建一个父模型用来保存公共部分,子模型继承父模型。这样的好处就是有时会省去很多重复代码。

    同样地 Django 也支持继承多个父类。

    Django 中三种继承方式:

    • 抽象基类:被用来继承的模型被称为 Abstract base classes,将子类共同的数据抽离,供子类复用,它不会创建实际的数据表
    • 多表继承: Multi-table inheritance,每一个模型都有自己的数据库表
    • 代理模型:如果你只想修改模型的Python层面的行为,并不想改动模型的字段,可以使用代理模型

    4.1 抽象基类

    只需在模型中元类添加 abstract=True,即可将模型转换为抽象基类。但是它不会创建实际数据库表,只能用来被继承。

    from django.db import models
    
    class CommonInfo(models.Model):
        username = models.CharField(max_length=32)
        password = models.CharField(max_length=64)
    
        class Meta:
            abstract = True
    
    
    class User(CommonInfo):
        email = models.EmailField(max_length=60)
    
    

    模型 User 将会有 username、password、email 三个字段。

    抽象基类元类

    如果子类没有元类,那么它将继承基类的元类,同样地子类也可以对基类的元类进行拓展:

    class CommonInfo(models.Model):
        username = models.CharField(max_length=32)
        password = models.CharField(max_length=64)
    
        class Meta:
            abstract = True
            ordering = ['username']
    
    
    class User(CommonInfo):
        email = models.EmailField(max_length=60)
    
        # 继承基类的元类,并进行拓展
        class Meta(CommonInfo.Meta):
            db_table = 'username'
    
    
    • 基类有元类,子类也没有的话,直接继承
    • 基类有元类,子类也有,直接覆盖
    • 子类可以添加额外元数据
    • 基类的 abstract=true 不会被继承
    • 基类的 db_table 元数据无效,因为抽象基类不会创建数据表

    related_name 和 related_query_name

    若抽象基类中存在 ForeignkManyToManyField 字段,且设置了 related_namerelated_query_name 参数,其子类也将继承这两个参数。但是在查询时就会出现错误。

    例如,对于 app01/models.py 中:

    class Base(models.Model):
        m2m = models.ManyToManyField(User, related_name="%(app_label)s_%(class)s_related", related_query_name="%(app_label)s_%(class)ss")
        class Meta:
            abstract = True
            
    class ChildA(Base):
        pass
    
    class ChildB(Base):
        pass
    
    
    • app01.ChildA.m2m 字段:反向关系名(reverse name)为 app01_childa_related;反向查询名(reverse query name)为 app01_childas
    • app01.ChildB.m2m 字段:分别为: app01_childb_relatedapp01_childbs
    • 如果没有设置 related_name 或 related_query_name 就没有上述情况

    4.2 多表继承

    父类和子类都是可正常使用的模型,且都有自己的数据表,其本质为 一对一 关系。

    class UserInfo(models.Model):
        name = models.CharField(max_length=32)
        age = models.IntegerField()
        
        
    class PersonalDetail(UserInfo):
        email = models.EmailField()
        description = models.CharField(max_length=4000)
    
    

    PersonalDetail 继承 UserInfo,它会继承父类所有的字段,两个模型内部是一对一关系,如下所示:

    >>> from polls.models import UserInfo, PersonalDetail
    >>> q = PersonalDetail.objects.all()
    
    >>> for i in q:
    ...     i.name
    ...
    'rose'
    'lina'
    
    

    多表继承之元类

    多表继承中子类不会继承父类的元类,但是有两个元类数据除外: ordering、get_latest_by,因此若希望不继承父类的元类的所有元数据,就需要指定或重写这两个元数据:

    class PersonalDetail(UserInfo):
        email = models.EmailField()
        description = models.CharField(max_length=4000)
    
        class Meta:
        # 重写 ordering,移除父类元类的影响
            ordering = []
    
    

    4.3 多重继承

    与 Python 一样,模型也可以继承多个父类模型,当有多个父类都含有 Meta 类时,那么只有第一个父类的会被继承,其余将被忽略掉。

    Tips

    • 尽量避免不用多重继承
    • 当父类有相同 id 主键字段时,将会报错,因此需要给父类显示地添加 AutoField 字段。
    class Base1(models.Model):
        base1_id = models.AutoField(primary_key=True)
        pass
    
    class Base2(models.Model):
        base2_id = models.AutoField(primary_key=True)
        pass
    
    class Child(Base1, Base2):
        pass
    
    

    4.4 代理模型

    代理模型就是对源模型的一种代理,可以创建、删除、更新代理模型的实例,与源模型用的是同一张数据表,但是 它对源模型数据没有影响

    要想将一个模型设置为代理模型,只需在 Meta 类中设置 proxy=True

    class A(models.Model):
        name = models.CharField(max_length=32)
        age = models.IntegerField()
    
    
    class B(A):
        # 代理模型
        class Meta:
            proxy = True
            ordering = ['age']
    
        def do_something(self):
            pass
    
    

    只会创建一张数据表,同时代理模型也可以操作数据表:

    from .models import A, B
    
    
    >>> A.objects.create(name='rose', age=18)
    
    >>> q = B.objects.get(name='rose')
    >>> q.age
    18
    
    # 对代理模型排序,按照年龄从小到大排列,被代理的模型,查询不会排序
    
    obj_list = B.objects.all()
    for obj in obj_list:
        print(obj.age)      # 17、18 、20
        print(obj.name)     # lila、rose、tom
    
    

    Tips

    • 代理模型必须继承自一个非抽象的基类,并且不能同时继承多个非抽象基类;
    • 代理模型可以同时继承任意多个抽象基类,前提是这些抽象基类没有定义任何模型字段。
    • 代理模型可以同时继承多个别的代理模型,前提是这些代理模型继承同一个非抽象基类。

    4.5 总结

    • 抽象基类不会创建数据表,直接设置 abstract=True 即可设置为抽象基类
    • 多表继承实质是一对一关系,不会继承基类 Meta,除 ordering 和 get_latest_by
    • 多表继承最好不要用
    • 代理模型与被代理模型通用一张数据表,可以对代理数据进行创建、删除、修改等操作,但对源模型无影响
    • 若基类是非抽象基类,基类与子类有相同名字的字段,那么将会覆盖子类(抽象基类除外)
    # A 中的 name 将会覆盖 B 中 的 name,除非 A 是抽象基类
    class A(models.Model):
        name = models.CharField(max_length=32)
    
        # class Meta:
        #     abstract = True
    
    class B(A):
        name = models.CharField(max_length=32)
    
    

    组织模型

    当模型有很多时,我们最好将模型分割开来,分类存储,这样有利于组织。我们可以利用包来组织模型。

    在应用中创建一个名为 models 的包(pycharm 可以直接创建包,不需要手动创建 init.py文件),然后将模型分类到各个 .py 文件中,最后将其导入 __init__.py 文件中:

    # app/models/__init__.py
    from polls.models.modelone import User
    
    

    5. 聚合分组

    5.1 聚合 aggregate

    aggregate() 返回一个字典,键为聚合值标识符,值为计算处理的聚合值。

    使用时需要先导入内置函数:

    from django.db.models import Avg, Sum, Max, Min, Count
    
    

    示例:

    from django.db.models import Avg, Sum, Max, Min, Count
    >>> models.UserInfo.objects.all.aggregate(avg_age=Avg('age'))	# 指定键为 avg_age,也可以用默认的
    {'avg_age': 18}
    
    

    多个聚合:

    from django.db.models import Avg, Sum, Max, Min, Count
    >>> models.UserInfo.objects.all.aggregate(avg_age=Avg('age'), max_length=Max('height'))	
    {'avg_age': 18, 'max_length': 182}
    
    

    5.2 分组 annotate

    ORM 中 values()values_list() 选字段,就相当于原生 SQL 中 select 什么字段:

    ret = models.Employee.objects.all()    # 相当于 select * from employee
    """
    SELECT `employee`.`id`, `employee`.`name`, `employee`.`age`, `employee`.`salary`, `employee`.`province`, `employee`.`dept` FROM `employee` LIMIT 21; args=()
    """
    
    ret = models.Employee.objects.all().values("dept", "age")
    """
    SELECT `employee`.`dept`, `employee`.`age` FROM `employee` LIMIT 21; args=()
    """
    
    

    select 选中什么字段,group by 就只能是什么字段:

    mysql> select name, Avg(salary) from app_employee group by name;
    +------+-------------+
    | name | Avg(salary) |
    +------+-------------+
    | rose |      2000.1 |
    | lila |     3000.45 |
    | john |     4000.56 |
    | tom  |     5005.78 |
    +------+-------------+
    
    

    1. 连表分组查询

      按照部门分组,查询每个部门的平均薪水:

    # ORM 操作
    # 前一个 values() 表示按照什么分组,后一个表示要显示的字段
    >>> employee_list = models.Employee.objects.values('dept__name').annotate(avg=Avg('salary')).values('dept__name', 'avg')
    >>> print(employee_list)    
        
    <QuerySet [{'dept__name': '财务部', 'avg': 2000.1}, {'dept__name': '事业部', 'avg': 4003.115}, {'dept__name': '人事部', 'avg': 4000.56}]>
    
    
    # 对应 SQL 语句
    SELECT `app_department`.`name`, AVG(`app_employee`.`salary`) AS `avg` FROM `app_employee` INNER JOIN `app_department` ON (`app_employee`.`dept_id` = `app_department`.`id`) GROUP BY `app_employee`.`name`, `app_department`.`name` ORDER BY NULL  LIMIT 21; args=()
    
    
    1. ORM 分组查询

    按照国家分组,查询每个国家的平均薪水:

    >>> employee_list = models.Employee.objects.values('addr').annotate(avg=Avg('salary')).values('addr', 'avg')
    >>> print(employee_list)    
    
     <QuerySet [{'addr': '美国', 'avg': 3502.9399999999996}, {'addr': '英国', 'avg': 3000.45}, {'addr': '德国', 'avg': 4000.56}]>
    
    
    SELECT `app_employee`.`addr`, AVG(`app_employee`.`salary`) AS `avg` FROM `app_employee` GROUP BY `app_employee`.`addr` ORDER BY NULL  LIMIT 21; args=()
    
    

    Tips

    • ORM 中的连表查询(跨表)相当于 SQL 中的连表(inner john)查询
    • ORM 查询,第一个 values(fields) 为分组字段,第二个 values(fileds1, fields2) 为要显示的字段
    • select选中什么字段,group by 就只能是什么字段

    5. F 查询和 Q 查询

    5.1 F 查询

    上面我们都是在比较字段与某个常亮,要想两个字段进行比较,那就要用到 F 查询

    1. 查询书的价格大于评论数的书籍
    from django.db.models import F
    models.Book.objects.filter(price__gt=F('comment_count'))		
    
    
    1. 将书的价格整体提升 5 元
    models.Book.objects.update(price=F('price')+5)
    
    
    1. F 对象和 F 对象以及常量之间可以进行加减乘除、取模等
    models.Book.objects.update(price=F('price')*5)
    
    

    5.2 Q 查询

    Q 构建搜索条件(在这里解决了或、与的问题)

    1. Q 对象可以对关键字参数进行封装,从而更好地应用多个查询
    obj1 = models.StudentDetail.objects.filter(Q(age=18))		# 构建过滤条件
    
    
    1. 组合使用 &、| 、~ 操作符
    obj2 = models.StudentDetail.objects.filter(Q(age=18) | Q(age=19))	# 解决了 Django API 中没有或的问题
    obj3 = models.StudentDetail.objects.filter(Q(age=18) & Q(age=19))	# 解决了 Django API 中没有与的问题
    obj3 = models.StudentDetail.objects.filter(~ Q(age=19))	# 解决了 Django API 中没有非的问题
    
    

    手动创建逻辑关系

    q1 = Q()		# 创建 Q 对象
    q1.connector = 'OR'		# q1 内部为 or 关系,即 age=18 或 age =19
    q1.children.append(('age', 18))
    q1.children.append(('age', 19))
    
    q2 = Q()		# 创建 Q 对象
    q2.connector = 'AND'	# q2 内部为 and 关系
    q2.children.append(('gender', 0))
    
    q3 = Q()			# 创建 Q 对象
    q3.add(q1, 'AND')		# 将 q1、q2 都添加到 q3 中,创建总的过滤条件
    q3.add(q2, 'AND')
    obj = models.StudentDetail.objects.filter(q3)
    print(obj)  # <QuerySet [<StudentDetail: StudentDetail object (1)>]>
    
    # 原生 SQL
    SELECT "app_studentdetail"."id", "app_studentdetail"."age", "app_studentdetail"."gender", "app_studentdetail"."height", "app_studentdetail"."email" FROM "app_studentdetail" WHERE (("app_studentdetail"."age" = 18 OR "app_studentdetail"."age" = 19) AND "app_studentdetail"."gender" = 0)  LIMIT 21;
            
    
    1. Q 对象 可以和关键字参数一起查询使用,不管一定要在关键字参数前面
    models.StudentDetail.filter(Q(age=18), email__startswith='123')
    
    1. 应用
    import datetime
    obj = models.Class.objects.filter(Q(create_data=datetime.date(2019,2,15)))
    print(obj)
    
  • 相关阅读:
    ZOJ 1002 Fire Net
    Uva 12889 One-Two-Three
    URAL 1881 Long problem statement
    URAL 1880 Psych Up's Eigenvalues
    URAL 1877 Bicycle Codes
    URAL 1876 Centipede's Morning
    URAL 1873. GOV Chronicles
    Uva 839 Not so Mobile
    Uva 679 Dropping Balls
    An ac a day,keep wa away
  • 原文地址:https://www.cnblogs.com/midworld/p/11380515.html
Copyright © 2011-2022 走看看