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)
    
  • 相关阅读:
    分享一下用终端的命令来恢复丢失的硬盘分区表 (转)
    Smart Link
    underrun || overrun
    mtr命令详解诊断网络路由
    tracert traceroute
    OE1、OE2、ON1、ON2路由有什么区别?
    GRE tunnel 2
    【SAP HANA】新建账户和数据库(2)
    【SAP HANA】SAP HANA开篇(1)
    入职一周
  • 原文地址:https://www.cnblogs.com/midworld/p/11380515.html
Copyright © 2011-2022 走看看