Django-9:django模型层ORM-5

DjangoORM详解:choices参数与模型关系处理
本文介绍了DjangoORM中的choices参数用于限制字段输入值,以及get_字段_display()方法获取显示值。讨论了MTV和MVC模型的区别,并详细阐述了多对多关系的创建方式,包括全自动、纯手动和半自动。另外,提到了on_delete参数在数据安全中的作用,以及如何断开外键约束。最后,讨论了抽象表的概念和ImageField字段的使用,强调了media配置的重要性。

ORM-5

本章节作为补充

一、choices参数

数据库字段设计时,经常会遇到

应用场景:

  • 只要某个字段的可能性,是可以列举完全的,那么这种情况下,都可以采用choices参数

代码示例:

class Staff(models.Model):
    '''
    员工表
    '''
    name = models.CharField(max_length=20, verbose_name='姓名')
    age = models.IntegerField(verbose_name='年龄')

    sex_choices = ((1, '男'), (2, '女'), (3, '未知'))
    sex = models.IntegerField(choices=sex_choices)

    education_choices = (
    ('A', '初中'), ('B', '中专'), ('C', '高中'), ('D', '大专'), ('E', '本科'), ('F', '研究生'), ('G', '博士生'))
    education = models.CharField(max_length=10, verbose_name='学历', choices=education_choices)
  • 先把将要创建的字段,所有可能的值列举出来,格式为分组套分组的形式。
  • 随后需要使用choices参数的字段,将值列举好的元祖,传给choices参数

利用ORM添加数据,并打印查看信息

  • res = models.Staff.objects.create(name='张三',age=27,sex=1,education='D')
    print(res.sex,res.education)
    
    '''
    输出结果:
    	1 D
    '''
    

    现象:打印的值,并不是choices参数所指定对应的值,而是创建字段时的值。

    解决方法:利用get_字段_display()方法来获取。

get_字段_display()

  • 这里的字段,指的是使用choices参数的字段

    res = models.Staff.objects.create(name='张三',age=27,sex=1,education='D')
    print(res.get_sex_display(), res.get_education_display())
    
    '''
    输出结果:
    	男 大专
    '''
    

结论:

  • 只要某个字段的可能性是可以列举完全的,那么就可以采用choices参数。

  • 实际存入数据库的并不是choices参数所指定的值,所以在取出时,需要使用get_使用choices参数的字段_display()来进行获取。

  • 还有,元祖内的"key"数据类型,要和使用choices参数的字段类型一致,如:

    sex_choices = ((1, '男'), (2, '女'), (3, '未知'))
    sex = models.IntegerField(choices=sex_choices)  # 注意这一应该是int类型的,和上面的(1, '男')中的1,数据类型一致。
    
  • 如果,字段的数据不在上述元祖列举的范围内容内,那么会原封不动的将数据展示,例如:

    res = models.Staff.objects.create(name='李四', age=25, sex=4, education='x')
    print(res.get_sex_display(),res.get_education_display())
    '''
    输出结果:
    	4 x
    '''
    # 缘分不动的返回。
    

实际项目案例:CRM相关内部表

image-20221013032543060

二、MTV与MVC模型

# MTV:Django号称是MTV模型
M:models
T:templates
V:views
# MVC:其实django本质也是MVC
M:models
V:views
C:controller
  
# vue框架:MVVM模型

三、多对多三种创建方式

django ORM在创建表多对多关系时,有三种方法:

  • “全自动”
  • “纯手动”
  • “半自动”

这三种方法的叫法并不是真的叫这个,只是为了很好的区分

“全自动”

  • class Book(models.Model):
        name = models.CharField(max_length=32)
        authors = models.ManyToManyField(to='Author')
        
    class Author(models.Model):
        name = models.CharField(max_length=32)
    

    直接利用ManyToManyField方法,指定需要建立关系的表。

    **优点:**代码不需要自己写,非常的方便,还支持orm提供操作第三张关系表的方法,如正反向查询等。

    **缺点:**第三张关系表的扩展性很差,没有办法额外的添加字段。

“纯手动”

  • 了解即可,不建议使用。

    class Book(models.Model):
        name = models.CharField(max_length=32)
        
    class Author(models.Model):
        name = models.CharField(max_length=32)
      
    class Book2Author(models.Model):
        book_id = models.ForeignKey(to='Book')
        author_id = models.ForeignKey(to='Author')
    

    手动创建第三张关系表,虽然单独设置外键字段。

    **优点:**第三张表完全取决于自己,可进行各种额外的扩展

    **缺点:**需要写的代码较多,不能够再使用orm提供的简单的方法(不建议使用)

“半手动”

  • 同样是手动创建第三张关系表,也同样是用的ManyToManyField方法,只不过我们从中指定建立多对多关系是那张表、第三张关系表是谁、两张表是依据第三张表的哪两个字段进行多对多关系的。

    class Book(models.Model):
        name = models.CharField(max_length=32)
        authors = models.ManyToManyField(to='Author',
                                         through='Book2Author',
                                         through_fields=('bind_book','bind_author')
                                         )
    class Author(models.Model):
        name = models.CharField(max_length=32)
    
    class Book2Author(models.Model):
        bind_book = models.ForeignKey(to='Book')
        bind_author = models.ForeignKey(to='Author')
    

    ManyToManyField方法中

    • to参数指定了要进行关联的表。
    • through参数指定了第三张关系表。
    • through_fields参数指定了,用三张表的哪两个字段用于做多对多关联。(因为本身第三张表可能与其他表也有关联)

through_fields字段先后顺序
判断的本质:
通过第三张表查询对应的表 需要用到哪个字段就把哪个字段放前面
你也可以简化判断
当前表是谁 就把对应的关联字段放前面
半自动:可以使用orm的正反向查询 但是没法使用add,set,remove,clear这四个方法

四、on_delete参数

在django2.x及以上的版本中,默认不再级联更新删除,因为该操作比较危险,删除一个出版社,该出版社连带的所有图书全部也删除,这是很恐怖的,所以后续需要指定,是否进行操作。

该参数表示级联关系:

  • models.CASCADE 级联更新删除(作者没了,详情也没)

  • models.DO_NOTHING 原封不动(出版社没了,书还是那个出版社出版)

  • models.SET_NULL 删除设置为空(部门没了,员工部门为空,但是该字段要有null=True)

  • models.SET_DEFAULT 删除设置为默认值(员工进入默认部门)

五、断关联

绑定了外键关系以后,在插入数据的时候会因为外键值当前并不存在而报错。

如果需要先把数据新增,然后再完善外键关系时,就可以使用到断关联,断开实质上的外键关系。

  • 如:book1外键绑定publish1,如果断关联,那么publish1可以不存在。

断开以后就是逻辑上的关联,实质上没有外键联系,增删不会受外键影响,而且还可以提升效率。

db_constraint=False

在没有断开关联的时候,插入一条数据时,如果外键绑定的那条数据并不存在,那么会插入不进去。

  • 如:新增图书,绑定出版社外键为1000的,但是id=1000的出版社并不存在,那么这个时候数据会插入不进去。

    断开关联就可以直接插入进去,删除也是同理,删除作家出版社,如果绑定的有图书是产出不掉的。

需要注意脏数据,由于不去根据外键进行校验,所以图书很可能会绑定上并不存在的出版社或作者,这种数据就叫做脏数据,那么作为程序员就需要避免脏数据的产生。

六、抽象表

在实际开发当中,每张表基本上都要有的字段,我们为了节省代码可以提取出一个基本类,然后由其他类继承这个基本类。

但是这个时候就会遇到一个问题,那就当执行数据库迁移命令的时候,会连同这张表一并创建到数据库,当不需要数据库新建出表的时候,就可以使用到抽象表

代码示例:

class BaseModel(models.Model):
    is_delete=models.BooleanField(default=False)

    # auto_now_add=True 只要记录创建,不需要手动插入时间,自动把当前时间插入
    create_time=models.DateTimeField(auto_now_add=True,null=True)

    # auto_now=True,只要更新,就会把当前时间插入
    last_update_time=models.DateTimeField(auto_now=True,null=True)

    class Meta:
        abstract=True  # 抽象表,不再数据库建立出表


class Book(BaseModel):
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=8,decimal_places=2)

    # db_constraint=False  逻辑上的关联,实质上没有外键练习,增删不会受外键影响,但是orm查询不影响
    bind_publish = models.ForeignKey(to='Publish',on_delete=models.DO_NOTHING,db_constraint=False)
    bind_author = models.ManyToManyField(to='Author',through='Book2Author',through_fields=('bind_book','bind_author'))



class Publish(BaseModel):
    name = models.CharField(max_length=32)
    addr = models.CharField(max_length=64)
  • 现在Book表和Publish表都有着共同的几个字段:是否删除、创建时间、更新时间

    于是我们抽出来一个基类叫BaseModel,该类中定义Meta类,添加属性abstract=True,这样就表示为抽象类,执行数据库迁移命令不会自动创建表。

七、ImageField字段

图片字段,可用于用户表存储头像,但是需要依赖于pillow模块

  • image-20230217222644546

存进去数据库的是文件路径,再拿出来访问的时候,还需要进行media配置,详情见后续章节。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿煜yv

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值