zoukankan      html  css  js  c++  java
  • Django:学习笔记(6)——模型

    Django:学习笔记(6)——模型

    快速上手

       模型到底是什么呢?我们可以想,如果一张数据表的各个字段可以自动映射到一个类的各个属性,则每条记录对应这个类的一个对象。那我们通过类方法来操作对象(即表记录)就会很容易了。这也大大简化了我们对SQL语句的依赖。

      在Django中,这种类统称为模型,我们只管创建模型,Django会自动为我们创建响应的数据表。

      比如,我们创建一个Peron模型:

    from django.db import models
    
    class Person(models.Model):
        first_name = models.CharField(max_length=30)
        last_name = models.CharField(max_length=30)

      first_name 和 last_name 是模型的字段。每个字段都被指定为一个类属性,并且每个属性映射为一个数据库列。

      上面的 Person 模型会创建一个如下的数据库表:

    CREATE TABLE myapp_person (
        "id" serial NOT NULL PRIMARY KEY,
        "first_name" varchar(30) NOT NULL,
        "last_name" varchar(30) NOT NULL
    ); 

      在创建完模型后,切莫执行数据迁移命令,来将模型变动同步到数据库。

      

    关于字段

      在创建模型是,我们需要声明各个属性映射的字段。

      常见的字段类型如下:

      常见的字段选项如下:

    • null:设置为true,表示该字段默认为NULL。
    • blank:设置为true,表示该字段允许为空。
    • choices:该参数接受一个可迭代的列表或元组。如果指定了该参数,在实例化该模型时,该字段只能取选项列表中的值。
      • 一个选项列表:
        YEAR_IN_SCHOOL_CHOICES = (
            ('FR', 'Freshman'),
            ('SO', 'Sophomore'),
            ('JR', 'Junior'),
            ('SR', 'Senior'),
            ('GR', 'Graduate'),
        )
      • 每个二元组的第一个值会储存在数据库中,而第二个值将只会用于显示作用。 

    • unique:为true,表示该字段值整个表唯一。
    • primary_key:为true,表示改字段为该模型的主键。
    • default:该字段的默认值。

    关于主键 

      我们创建模型时,没有定义di属性,但是在创表的SQL语句中出现了ID,这是因为默认情况下,Django会给每一个模型添加下面字段。

    id = models.AutoField(primary_key=True)
    

      这是一个自增的主键。任何一个模型都必须有一个主键。在你想要设置为主键的字段上设置 primary_key=True 选项。如果 Django 看到你显式的设置了 Field.primary_key ,将不会自动在表(模型)中添加 id 列。

      主键字段是只可读得,如果你修改了一个模型实例的主键值并保存,就等同于创建了一个新的模型实例。

    from django.db import models
    
    class Fruit(models.Model):
        name = models.CharField(max_length=100, primary_key=True)
    
    >>> fruit = Fruit.objects.create(name='Apple')
    >>> fruit.name = 'Pear'
    >>> fruit.save()
    >>> Fruit.objects.values_list('name', flat=True)
    <QuerySet ['Apple', 'Pear']>

    关联关系

      关系型数据库的强大之处在于个表之间的关联关系,无非是多对一、多对多、一对一。在Django中,表之间的关联关系,在这里当然体现为模型之间的关联关系。

    多对一关系

      

      比如A汽车制造厂,制造了多辆汽车,他们之间是多对一关系,即多量汽车都是同一个汽车制造厂制造。那么A汽车、B汽车等汽车一定要有一个外键指向A汽车制造厂的ID。

    from django.db import models
    
    # Create your models here.
    
    class Manufacturer(models.Model):
        #....
        pass
    
    class Car(models.Model):
        #....
        manufacturer = models.ForeignKey(Manufacturer,on_delete=models.CASCADE)
        
    

      建议设置ForeignKey字段名为要关联的模型名,正如代码所示,但是你也可以设置为你自己想要的名称。

      我们来分析一下,在数据库层面是如何处理多对一关系的。

      

      不出所料,每一个汽车有一个外键,指向了其 制造厂。

    多对多关系

      

      A、B汽车制造厂都参与制造了ABC...等汽车,一辆车由多个汽车制造厂联合制造,一个汽车制造厂参与制造了多亮汽车。此时汽车制造厂与汽车之间形成了多对多关系。  

    from django.db import models
    
    # Create your models here.
    
    class Manufacturer(models.Model):
        #....
        pass
    
    class Car(models.Model):
        #....
        manufacturers = models.ManyToManyField(Manufacturer)
    

      建议设置ManyToManyField字段名为一个复数名词,表示要关联的模型对象的集合。对于多对多关联关系的两个模型,可以在任何一个模型中添加ManyToManyField字段,但只能选择一个模型设置该字段,即不能在两个模型中添加该字段

      我们来分析一下,数据库层面是如何处理这样多对多关系的。

      

      首先,建立了三张表,最主要是的中间这张表,他记录了汽车与制造商的关联关系。也就是说只要在第二种表中传入汽车的id就能获取所关联制造厂的所有id,同样传入汽车制造厂的id就能获取其制造的所有汽车的id。 

    一对一关系

      一对一关系是指关系数据库中两个表之间的一种关系,该关系中第一个表中的单个行只可以与第二个表中的一个行相关,且第二个表中的一个行也只可以与第一个表中的一个行相关。我们现在以饭店和它的地皮为例:

    from django.db import models
    
    class Place(models.Model):
        name = models.CharField(max_length=50)
        address = models.CharField(max_length=80)
    
        def __str__(self):
            return "%s the place" % self.name
    
    class Restaurant(models.Model):
        place = models.OneToOneField(
            Place,
            on_delete=models.CASCADE,
            primary_key=True,
        )
        serves_hot_dogs = models.BooleanField(default=False)
        serves_pizza = models.BooleanField(default=False)
    
        def __str__(self):
            return "%s the restaurant" % self.place.name
    

      一个饭店对应一个地点,它们构成一对一关系。

    # 现在我们创建几个地方
    >>> p1 = Place(name='Demon Dogs', address='944 W. Fullerton')
    >>> p1.save()
    >>> p2 = Place(name='Ace Hardware', address='1013 N. Ashland')
    >>> p2.save()
    # 创建一个餐馆,并传入一个地方
    >>> r = Restaurant(place=p1, serves_hot_dogs=True, serves_pizza=False)
    >>> r.save()
    # 餐厅可进入其地点
    >>> r.place
    <Place: Demon Dogs the place>
    # 一个地方可显示其餐厅
    >>> p1.restaurant
    <Restaurant: Demon Dogs the restaurant>
    

      我们来分析一下,数据库层面是如何处理这样一对一关系的。

      

      一对一关系,数据库建立了两张表,place表有自增主键,restaurant表的主键参照place的主键。这样可以方便的从地皮找到其对应的餐厅(餐厅的id参照地皮的id),也可以方便的从餐厅找到其对应的地皮(同样地皮的id就是餐厅的id)。

    Meta选项

      模型的元数据Meta,指的是“除了字段外的所有内容”,例如排序方式、数据库表名、人类可读的单数或者复数名等等。所有的这些都是非必须的,甚至元数据本身对模型也是非必须的。但是,我要说但是,有些元数据选项能给予你极大的帮助,在实际使用中具有重要的作用,是实际应用的‘必须’。

    创建一个元数据

      想在模型中增加元数据,方法很简单,在模型类中添加一个子类,名字是固定的Meta,然后在这个Meta类下面增加各种元数据选项或者说设置项。

    from django.db import models
    
    class Ox(models.Model):
        horn_length = models.IntegerField()
    
        class Meta:         # 注意,是模型的子类,要缩进!
            ordering = ["horn_length"]  
    

      上面的例子中,我们为模型Ox增加了两个元数据‘ordering’,分别表示排序依据,下面我们会详细介绍有哪些可用的元数据选项。

    强调:每个模型都可以有自己的元数据类,每个元数据类也只对自己所在模型起作用。

    更多元数据的配置项

      请查看官方文档:https://docs.djangoproject.com/zh-hans/2.1/ref/models/options/

    模型方法

      模型,提供了一些内置的功能,同样也支持我们自定义一些新的功能。

      我们建立模型、保存数据为的就是在需要的时候可以查询得到数据。Django自动为所有的模型提供了一套完善、方便、高效的API,一些重要的,我们要背下来,一些不常用的,要有印象,使用的时候可以快速查找参考手册。

    保存及创建对象

    >>> from blog.models import Blog
    >>> b = Blog(name='Beatles Blog', tagline='All the latest Beatles news.')
    >>> b.save()
    
    #或者一条语句
    b = Blog.objects.create(name='Beatles Blog', tagline='All the latest Beatles news.')  

      注意,在保存字段中有外键的实例时,需要想将其外键对象查找出来,再进行保存:

    entry = Entry.objects.get(pk=1)
    cheese_blog = Blog.objects.get(name="Cheddar Talk")
    entry.blog = cheese_blog
    entry.save()
    

      

    检索对象

      想要从数据库内检索对象,你需要基于模型类,通过管理器(Manager)构造一个查询结果集(QuerySet)。

      每个QuerySet代表一些数据库对象的集合。它可以包含零个、一个或多个过滤器(filters)。Filters缩小查询结果的范围。在SQL语法中,一个QuerySet相当于一个SELECT语句,而filter则相当于WHERE或者LIMIT一类的子句。

      通过模型的Manager获得QuerySet,每个模型至少具有一个Manager,默认情况下,它被称作objects,可以通过模型类直接调用它,但不能通过模型类的实例调用它,以此实现“表级别”操作和“记录级别”操作的强制分离。如下所示:

    from blog.models import Entry
    # 检索所有对象
    all_entries = Entry.objects.all()
    
    # 检索单一数据
    one_entry = Entry.objects.get(pk=1)
    
    # 数据切片
    Entry.objects.all()[:5]      # 返回前5个对象
    Entry.objects.all()[5:10]    # 返回第6个到第10个对象
    
    # 过滤对象(只要2006年的数据)
    Entry.objects.filter(pub_date__year=2006)
    
    # 过滤对象(除了2006年的数据都要)
    Entry.objects.exclude(pub_date__year=2006)

    删除对象

    Entry.objects.filter(pub_date__year=2005).delete()
    #或者
    b = Entry.objects.get(pk=1)
    # 下面的动作将删除该条Entry和所有的它关联的对象
    b.delete()

    自定义功能

      当然,除了使用Django提供的模型方法,我们也可以自定义自己的方法,或者重写原有的方法。

    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()
            super().save(*args, **kwargs)  # Call the "real" save() method.
            do_something_else()

     

    结语

      这篇博客的篇幅太长了,一定讲不好模型。我们会在下篇文章中重点阐述模型的更多内容。

  • 相关阅读:
    Java知多少(28)super关键字
    Java知多少(27)继承的概念与实现
    Java知多少(26)源文件的声明规则
    Java知多少(25)再谈Java包
    Java知多少(24)包装类、拆箱和装箱详解
    Java知多少(23)类的基本运行顺序
    Java知多少(22)方法重载
    Java知多少(21)this关键字详解
    Java知多少(20)变量的作用域
    Java知多少(19)访问修饰符(访问控制符)
  • 原文地址:https://www.cnblogs.com/MrSaver/p/10428272.html
Copyright © 2011-2022 走看看