Models#1

  • model是Django中的数据模型
    • 每个model都是继承自django.db.models.Model的子类
    • 每个model都映射一个数据表
    • model中的每个类属性对应着数据表中的一列
    • django支持ORM
  • 创建model并进行migrate后
    • Django会自动生成表名(可以自定义
    • Django会自动增加主键一列(可以自定义)
    • Django会根据不同数据库创建不同的SQL语句
  • Field中的常见选项
    • null:允许该列数据为空(默认为False)
    • blank:主要用于是否允许表单为空(默认为False)
    • choices:为一个Field提供可选项(并且默认生成的表单为一个选项)
      from django.db import models
      
      class Person(models.Model):
          # choices的对象是一个可迭代对象,其元素为‘含有两个元素的元组’
          SHIRT_SIZES = (
              ('S', 'Small'),
              ('M', 'Medium'),
              ('L', 'Large'),
          )
          name = models.CharField(max_length=60)
          shirt_size = models.CharField(max_length=1, choices=SHIRT_SIZES)
        
      # choice API
      >>> p = Person(name="Fred Flintstone", shirt_size="L")
      >>> p.save()
      >>> p.shirt_size
      'L'
      >>> p.get_shirt_size_display()   # get_FOO_display()方法可以显示具体内容
      'Large'
      
    • default:既可以是一个数值对象,也可以是一个可调用对象
    • help_text:在生成的表单中展示‘帮助’信息
    • primary_key:将某一列设置为主键(该列变为只读);默认为False,即Django会自动创建一个整型主键
    • unique:该列中的每个数据必须独一无二(默认为False)
  • 自动生成主键
    默认情况下,如果不显式指定主键,Django会在model中自动添加以下属性
    id = models.AutoField(primary_key=True)
    
  • 显式指定列名
    对于非关系型列(即非ForeignKeyField,ManyToManyField,OneToOneField),第一个位置参数为空时,将默认属性名为列名;否则使用位置参数作为列名
    对于关系型列,需要指定位置参数以表明关联的数据表
    # 列名为"person's first name"
    first_name = models.CharField("person's first name", max_length=30)
    
    # 列名为"first_name"
    first_name = models.CharField(max_length=30)
    
    # 关联表为"Poll"
    poll = models.ForeignKey(
        Poll,
        on_delete=models.CASCADE,
        verbose_name="the related poll",
    )
    
  • 关联
    • Many-to-one 关联
      使用django.db.models.ForeignKey,第一个位置参数需要指定关联表名
    • Many-to-many 关联
      使用django.db.models.ManyToManyField(相关的两个表中,只需要在一个表中指定即可)
      可以显式的创建many-to-many的关联数据表
      from django.db import models
      
      class Person(models.Model):
          name = models.CharField(max_length=128)
      
          def __str__(self):              # __unicode__ on Python 2
              return self.name
      
      class Group(models.Model):
          name = models.CharField(max_length=128)
          # 通过through指定关联表
          members = models.ManyToManyField(Person, through='Membership')
      
          def __str__(self):              # __unicode__ on Python 2
              return self.name
      
      class Membership(models.Model):
          person = models.ForeignKey(Person, on_delete=models.CASCADE)
          group = models.ForeignKey(Group, on_delete=models.CASCADE)
          date_joined = models.DateField()
          invite_reason = models.CharField(max_length=64)
      
    • One-to-one 关联
      使用django.db.models.OneToOneField,可以用于扩展某一model
  • Meta 选项
    Model的Meta中保存着所有非列的属性(比如ordering(默认排序)、db_table(数据表名称)等等)
    from django.db import models
    
    class Ox(models.Model):
        horn_length = models.IntegerField()
        
        # class Meta 是可选项
        class Meta:
            ordering = ["horn_length"]
            verbose_name_plural = "oxen"
    
  • Model 的方法
    我们可以在Model中自定义方法,也可以使用或者重载Model中已有的方法
    有两个方法在大多数情况下需要我们自己定义
    • __ str__()
    • get_absolute_url()
      该方法告诉Django如何得到一个对象的URL(一般使用django的reverse()函数)
      def get_absolute_url(self):
          from django.urls import reverse
          return reverse('people.views.details', args=[str(self.id)])
      
    重载Model中已定义的方法
    from django.db import models
    
    class Blog(models.Model):
        name = models.CharField(max_length=100)
        tagline = models.TextField()
    
        def save(self, *args, **kwargs):
            do_something()
            # 关键在于对Model.save()方法的继承上,另外通过使用(*args, **kwargs)参数可以自动获取相关参数
            super(Blog, self).save(*args, **kwargs) # Call the "real" save() method.
            do_something_else()
    

  • Model的继承
    django中存在三种继承
    • Abstract base classes
    • Multitable inheritance
    • Proxy models
  • Abstract base classes
    在class Meta中设置abstract = True,就可以将该model变为抽象类——该类中定义的列属性可以被子类所继承而无需重新定义,且class Meta中的属性亦会被继承(除了abstract = True)
    Abstract base classes并不会产生数据表,也不能直接用于创建实例
    from django.db import models
    
    class CommonInfo(models.Model):
        name = models.CharField(max_length=100)
        age = models.PositiveIntegerField()
        
        # 将CommonInfo声明为一个abc类
        class Meta:
            abstract = True
            ordering = ['name']
    
    class Student(CommonInfo):
        # Student 类自动继承name和age列
        home_group = models.CharField(max_length=5)
    
        class Meta: 
            # Student 类会继承CommonInfo中的Meta的信息
            # 不过在此之前会自动设置abstract=False(当然也可以自己显式地设置abstract=True从而成为abc类)
            db_table = 'student_info'
    
    为了指定子类关联表列的relate_name,可以在abc类的关联表列中进行设置
    # common/models.py
    from django.db import models
    
    class Base(models.Model):
        m2m = models.ManyToManyField(
            OtherModel,
            # 若不设置related_name,则默认为"子类名 + '_set'"
            # %(app_label)s 指代当前应用名称
            # %(class)s 指代当前类的类名
            related_name="%(app_label)s_%(class)s_related",
            related_query_name="%(app_label)s_%(class)ss",
        )
    
        class Meta:
            abstract = True
    
    # OtherModel 使用 ChildA 类时的属性名将是'common_childa_related'
    class ChildA(Base):
        pass
    
    class ChildB(Base):
        pass
    
  • Multi-table inheritance
    父类和子类都可以生成数据表,且子类会继承父类的类属性(列属性),但父类和子类是两个不同的表
    此外,不同于abc类,子类不会继承父类class Meta中的属性
  • Proxy models
    Proxy model用于当你只想为一个表增加一些方法或者Meta属性,而不想改变原model的代码时
    from django.db import models
    
    class Person(models.Model):
        first_name = models.CharField(max_length=30)
        last_name = models.CharField(max_length=30)
    
    class MyPerson(Person):
        class Meta:
            # 指定该类为Person的代理数据模型
            proxy = True
            # 在该proxy model中可以增加一个额外的Meta属性
            odering = ['last_name']
    
        # 在该proxy model中可以增加一些额外的方法
        def do_something(self):
            # ...
            pass
    
    # 需要注意的一点是Person和MyPerson类都可以调用Person数据表中的数据
    # 不同之处在于通过Person类创建/查找到的实例中没有ordering属性,也不能调用do_something方法
    
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,390评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,821评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,632评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,170评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,033评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,098评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,511评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,204评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,479评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,572评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,341评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,893评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,171评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,486评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,676评论 2 335

推荐阅读更多精彩内容