• 运维开发笔记整理-Django模型语法


                运维开发笔记整理-Django模型语法

                                      作者:尹正杰

    版权声明:原创作品,谢绝转载!否则将追究法律责任。

    一.模型基本概念

    1>.什么是模型

      模型是你的数据唯一的,权威的信息源。它包含你所存储数据的必要字段和行为。每个模型对应数据库中唯一的一张表。它包含你所存储数据的必要字段和行为。每个模型对应数据库中唯一的一张表。

    2>.如何编写模型

      模型:每个模型都用一个类表示,该类继承自“django.db.models.Model”。每个模型有多个类的属性变量,而每一个类的属性变量又都代表类数据库表中的一个字段。

      字段:每个字段通过Field类的一个实例表示,例如字符字段CharField和日期字段DataTimeField。这种方法告诉Django每个字段保存着什么类型的数据。(偷偷告诉你,Django支持的模型字段比数据库本身的字段要支持的多,比如MySQL的varchar类型,就被Django封装成了不同的模型字段,比如EmailField)。

      字段名:每个Field实例的名字(例如username)就是字段的名字,并且是机器刻度的格式。你将在Python代码中使用它的值,并且你的数据库把它为表的列名。

    3>.模型字段类型

      模型字段类型又很多,比如CharField,BooleanFielld,IntegerField,DateField/DateTimeField,EmailField,TextField,TimeField等等,更多字段类型(Field-types)可参考Django组建的官方地址:https://docs.djangoproject.com/en/1.11/ref/models/fields/#field-types

    4>.自增主键字段

      默认情况下Django会给每个模型添加下面这个字段。

    id = models.AutoField(primary_key=True)

      如果Django看到你显示设置了Field.primary_key,就不会自动添加id列。

      每个模型只能有一个字段指定primary_key=True(无论是显示声明还是自动添加)。

    5>.字段的自述名

      每个字段类型都接受一个可选的位置参数,字段的自述名,如果没有给定自述名,Django将根据字段的属性名称自动创建自述名,将属性名称的下划线替换成空格。

      ForeignKey,ManyToManyField和OneToOneField这三个可以使用verbose_name指定自述名。

    #例如:自述名为:"person's first name"
    first_name = models.CharField("person's first name", max_length=30)
    
    
    #例如:自述名为:"first name"
    first_name = models.CharField(max_length=30)

    6>.字段选项

      每个字段有一个也有的参数,例如,CharField(和它的派生类)需要max_length参数来指定VARCHAR数据库字段的大小。

      null:

        如果为True,Django将用NULL来在数据库中存储空值,默认值是False。

      blank:

        如果为True,该字段允许不填,默认值是False。null是纯数据库范畴,而blank是数据验证范畴的,blank=True,表单验证允许为空,blank=False,该字段就是必须的。

      choices:

        由二元组组成的一个可迭代对象(如列表或元组),用来给字段提供选择项,如果设置了choices,默认的表单将是一个选择框,选择框的选择就是choices中的选项。

    YEAR_IN_SCHOOL_CHOICES = (
        ('FR', 'Freshman'),
        ('SO', 'Sophomore'),
        ('JR', 'Junior'),
        ('SR', 'Senior'),
    )

      defaulat:

        字段的默认值,可以是一个值或者调用对象。

      primary_key:

        如果为True,那么这个字段就是模型的主键。

      unique:

        如果改值设置为True,这个字段的值在整张表中必须是唯一的。

      更多关于Field字段选项可参考官方链接:https://docs.djangoproject.com/en/1.11/ref/models/fields/#field-options

    7>.模型meta选项

      使用内部的class Meta定义模型的元数据,例如:

    from django.db import models
    class User(models.Model):
        username = models.IntegerField()
        class Meta:
            ordering = ["username"]

      模型元数据是“任何不是字段的数据”,比如排序选项(ordering),数据库表名(tb_table)。在模型中添加class Meta是完全可选的,所有选项都不是必须的。更多文档可参考官方链接:https://docs.djangoproject.com/en/1.11/ref/models/options/

       db_table:

        db_table是用于指定自定义数据库表名的。Django有一套默认的按照一定规则生成数据模型对应的数据库表名,如果你想使用自定义的表名,就通过这个属性执行。

        若不提供该参数,Django会使用app_label + '_' + module_name作为表的名字。

    class Meta:
        db_table = 'server’ 

        Django会根据模型类的名称和包含它的应用的名称自动指定数据库表名称。一个模型数据库表名称,由这个模型的“应用名”和模型名称之间加上下划线组成。

        使用Meta类中的db_table参数来重写数据表的名称。

        当你通过db_table覆写表名称时,强烈推荐使用小字母给表命名。

      order:

        这个字段是告诉Django模型对象返回的记录结果集是按照哪个字段排序的

    class Meta:
        ordering = ['-order_date']

        它是一个字符串的猎豹或元组。每个字符串是一个字段名,前面带有可选的“-”前缀表示倒叙。前面没有“-”表示正序。使用“?”来表示随机排序。

    ordering=['order_date'] # 按订单升序排列
    ordering=['-order_date'] # 按订单降序排列,-表示降序
    ordering=['?order_date'] # 随机排序,?表示随机
    ordering = ['-pub_date', 'author'] # 对 pub_date 降序,然后对 author 升序

      app_label:

        app_label这个选项只在一种情况下使用,就是你的模型类不在默认的程序包下models.py文件中,这时候你需要指定你这个模型属于哪个应用程序。

    class Meta:
        app_label='myapp'

      get_latest_by:

        由于Django的管理方法中有个lastest()方法,就是得到最近一行记录。如果你的数据模型中有DataField或DateTimeField类型的字段,你可以通过这个选项来指定lastest()是按照哪个字段进行选取的。

        一个DataField或DateTimeField字段的名称,若提供该选项,该模块将拥有一个get_lastest()函数以得到“最新的”对象(依据那个字段):

    class Meta:
        get_latest_by = "order_date"

      verbose_name:

        verbose_name的意思很艰难,就是给你的模型类起一个更可读的名字,代码如下:

    class Meta:
    verbose_name = "Jason"

      managed:

        由于Django会自动根据类型生成映射的数据库表,如果你不希望Django这么做,可以把managed的值设置为False。

        默认值为True,这个选项为True时Django可以对数据库表进行migrate或migrations,删除等操作。在这个时间Django将管理数据库中表的声明周期。

        如果为False的时候,不户籍对数据库表进行创建,删除等操作。可以用于现有表,数据库视图等,其他操作是一样的。

    二.编写IDC模型

    1>.编写对应的数据库模型

    #!/usr/bin/env python
    #_*_conding:utf-8_*_
    #@author :yinzhengjie
    #blog:http://www.cnblogs.com/yinzhengjie/tag/python%E8%87%AA%E5%8A%A8%E5%8C%96%E8%BF%90%E7%BB%B4%E4%B9%8B%E8%B7%AF/
    
    from django.db import models
    
    class IDC(models.Model):
        name        = models.CharField("机房名称",max_length=32)
        address     = models.CharField("机房地址",max_length=200)
        phone       = models.CharField("机房联系电话",max_length=15)
        email       = models.EmailField("邮件地址",default="")
        letter      = models.CharField("机房地址缩写名称",max_length=5)
        
        class Meta:
            db_table = "idc"

    2>.数据库迁移命令

    C:UsersyinzhengjiesoftwaresGitHubDevOps>python manage.py makemigrations
    Migrations for 'dashboard':
      dashboardmigrations001_initial.py
        - Create model IDC
    
    C:UsersyinzhengjiesoftwaresGitHubDevOps>
    负责基于你的模型修改创建一个新的迁移,并把这个迁移记录到本地的当前项目中一个叫migrations目录(python manage.py makemigrations)

    C:UsersyinzhengjiesoftwaresGitHubDevOps>python manage.py migrate
    Operations to perform:
      Apply all migrations: admin, auth, contenttypes, dashboard, sessions
    Running migrations:
      Applying dashboard.0001_initial... OK
    
    C:UsersyinzhengjiesoftwaresGitHubDevOps>
    负责执行迁移,以及撤销和列出迁移的状态,我们可以简单的理解就是将我们写的python 代码翻译成SQL语句并执行(python manage.py migrate)注意,后面可以跟APP的名称,如果不加默认迁移所有

    C:UsersyinzhengjiesoftwaresGitHubDevOps>python manage.py  sqlmigrate dashboard 0001_initial
    BEGIN;
    --
    -- Create model IDC
    --
    CREATE TABLE `idc` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `name` varchar(32) NOT NULL, `address` varchar(200) NOT NULL, `phone` varchar(15) NOT NULL, `email` varchar(254) NOT NULL, `letter` varchar(5) NOT NULL);
    COMMIT;
    
    C:UsersyinzhengjiesoftwaresGitHubDevOps>
    展示迁移的SQL语句(python manage.py sqlmigrate dashboard 0001_initial)

    三.模型的增删改查操作

    1>.创建对象

      Django使用一种直观的方式把数据库表中的数据表示成Python对象:一个模型类代表数据库中的表,一个模型类的实例代表这个数据库中的一条特定的记录;

      使用关键字实例化模型实例来创建一个对象,然后调用save()方法把它保存到数据库中;

      也可以使用一条语句创建并保存一个对象,使用create()方法,此方法我们不推荐使用; 

    C:UsersyinzhengjiesoftwaresGitHubDevOps>python manage.py shell
    Python 3.6.0 (v3.6.0:41df79263a11, Dec 23 2016, 08:06:12) [MSC v.1900 64 bit (AMD64)] on win32
    Type "help", "copyright", "credits" or "license" for more information.
    (InteractiveConsole)
    >>>
    >>> from dashboard.models import IDC
    >>> idc = IDC()
    >>> idc.name = "亦庄机房"
    >>> idc.address = "北京市亦庄经济技术开发区荣华南路11号"
    >>> idc.phone = "010-53897114"
    >>> idc.email = "yinzhengjie@caiq.org.cn"
    >>> idc.letter = "yz"
    >>> idc.save()
    >>>

      执行成功后,我们可以查看数据库有相应的信息生成:

    2>.查询对象

      通过模型中管理器构造一个查询集,来从你的数据库中获取对象。

      查询集(querylist)表示从数据库中取出来的对象集合。它可以含有零个,一个或者多个过滤器。过滤器基于所给的参数限制查询的结果。从SQL的角度,查询集合SELECT语句等价,过滤器像WHERE和LIMIT一样的限制子句。

      你可以从模型的管理器那里取得查询集。每个模型都至少有一个管理器,它默认命名为objects。通过模型类来直接访问它。

      管理器只可以通过模型的类访问,而不可以通过模型的实例访问,目的是为了强制分区“表级别”的操作和“记录级别”的操作。

      对于一个模型来说,管理器是查询集的主要来源。例如,User.objects.all() 返回包含数据库中所有User对象的一个查询集。 

    3>.获取所有对象

       获取一个表中所有对象最简单的方式是全部获取。可以使用管理器的all()方法。

      all()方法返回包含数据库中所有对象的一个查询集。

    all_users = User.objects.all()

    4>.使用过滤器获取特定对象

       all()方法返回李一个包含数据库表中所有记录查询集。但在通常情况下,你往往想要获取的是完整数据集的一个子集。

      要创建这样一个子集,你需要在原始的查询集上增加一些过滤条件。两个最普遍的途经是:

        filter(**kwargs) 返回一个新的查询集,它包含满足查询参数的对象。

        exclude(**kwargs)返回一个新的查询集,它包含不满足查询参数的对象。

      查询参数(上面函数定义中的**kwargs)需要满足特定的格式。

    使用过滤器获取特定对象示例:
    要获取年份为2006的所有文章的查询集,可以使用lter()方法: Entry.objects.filter(pub_date__year
    =2006)
    利用默认的管理器,它相当于: Entry.objects.all().filter(pub_date__year
    =2006)

    5>.链式过滤

       查询集的筛选结果本身还是查询集合,所以可以将筛选语句链接在一起。如下代码所示:

    Entry.objects.filter(
        headline__startswith='What’
    ).exclude(
        pub_date__gte=datetime.date.today()
    ).filter(
        pub_date__gte=datetime(2005, 1, 30)
    )

      这个例子最开始获取数据库中所有对象的一个查询集,之后增加一个过滤器,然后又增加一个排除,再之后又是另外一个过滤器。最后的结果仍然是一个查询集,它包含标题以“What”开头,发布日期在2005年1月30日至今天之间的所有记录。

    6>.过滤后的查询集是独立的

      每次你筛选一个查询集,得到的都是全新的另一个查询集,它和之前的查询集之间没有任何绑定关系。每次筛选都会创建一个独立的查询集。它可以被存储及复制使用。

    q1 = Entry.objects.filter(headline__startswith="What")
    q2
    = q1.exclude(pub_date__gte=datetime.date.today())
    q3
    = q1.filter(pub_date__gte=datetime.date.today())

    7>.查询集是惰性执行的

       查询集是惰性执行的,创建查询集不会带来任何数据库的访问。你可以将过滤器保持一整天。直到查询集需要求值时,Django才会真正允许这个查询。

    >>> q = Entry.objects.filter(headline__startswith="What")
    >>> q = q.filter(pub_date__lte=datetime.date.today())
    >>> q = q.exclude(body_text__icontains="food")
    >>> print(q)

      虽然它看上去又三次数据库访问,但事实上只有最红一行“print(q)”时访问一次数据库。一般来说,只有在“请求”查询集的结果时才会到数据库中去获取它们。当你确实需要结果时,查询集通过访问数据库来求值。 

    8>.获取一个单一的对象-get()

       fillter()始终给你一个查询集,即使只有一个对象满足查询条件,这种情况下,查询集将只包含一个元素。

      如果你直到只有一个对象满足你的查询,你可以使用管理器的get()方法,它直接返回该对象。

    one_entry = Entry.objects.get(pk=1)

      可以对get()使用任何查询表达式,和filter()一样。

      使用get()和使用filter()的切片[0]有一点区别。如果没有结果满足查询,get()将引入一个DoesNotExsist异常。这个异常是正在查询的模型类的一个属性。所以在上面的代码中,如果没有主键为1的Entry对象,Django将引发一个Entry.DoesNotExist。

      如果有多条记录满足get()的查询条件,Django也将报错。这种情况将引发MultipleObjectsRetruned,它同样是模型类自身的一个属性。

    9>.限制查询集

      可以使用Python的切片语法来限制查询集记录的数目。它等同于SQL的LIMIT和OFFSET子句。

    >>> Entry.objects.all()[:5]
    >>> Entry.objects.all()[5:10] 

    10>.字段查询

      字段查询是只如何指定SQL WHERE子句的内容,它们通过查询方法集filter(),exclude()和get()的关键字参数指定。

      查询的关键字参数的基本形式是“field__lookuptype=value”(中间是2个下划线)

    >>> Entry.objects.filter(pub_date__lte='2006-01-01')
    SELECT * FROM blog_entry WHERE pub_date <= '2006-01-01';

      exact:精确匹配。

    >>> Entry.objects.get(headline__exact=“Man bites dog”)
    SELECTWHERE headline = ‘Man bites dog’;
    
    >>> Blog.objects.get(id__exact=14)
    >>> Blog.objects.get(id=14)

      iexact:大小写不敏感的匹配。

      contains:大小写铭感的包含指定字符串。

      icontains:大小写不铭感的包含指定字符串。

      startswith,endswith:以指定字符串开头或结尾。

      istartswith,iendswith:以指定字符串开头或结尾。

      in:在给定的列表内。

      gt:大于

      gte:大雨或者等于

      lt:小于

      lte:小于或等于

      range:在指定范围内

      year/mouth/day/week_day:对于日期和日期时间字段,匹配年/月/日/星期  

    11>.查询的快捷方式pk

      Django提供一个查询快捷方式pk,它表示‘primary key’的意思

    >>> Blog.objects.get(id__exact=14)
    >>> Blog.objects.get(id=14)
    >>> Blog.objects.get(pk=14)

    12>.Order_by

      默认情况下,QuerySet根据模型Meta类的ordering选项排序。你可以使用order_by方法给每个QuerySet指定特定的排序。

    Entry.objects.filter(pub_date__year=2005).order_by('-pub_date', 'headline')

      上面的结果将按照pub_date降序排序,然后在按照headline升序排序。“pub_date”前面的负号表示降序排序。隐式的是升序排序。若要随机排序,请使用“?”,像这样:

    Entry.objects.order_by('?')

    13>.values

          返回一个ValuesQuerySet —— QuerySet 的一个子类,迭代时返回字典而不是模型实例对象。

      每个字典表示一个对象,键对应于模型对象的属性名称。

      values() 接收可选的位置参数*elds,它指定SELECT 应该限制哪些字段。如果指定字段, 每个字典将只包含指定的字段的键/值。如果没有指定字段,每个字典将包含数据库表中所 有字段的键和值。

    User.objects.values("id", "username")

    14>.values_list

           与values() 类似,只是在迭代时返回的是元组而不是字典。每个元组包含传递给 values_list() 调用的字段的值 —— 所以第一个元素为第一个字段,以此类推。

    User.objects.values_list('id', 'username'

    15>.defer

      在一些复杂的数据建模情况下,您的模型可能包含大量字段,其中一些可能包含大量数据 (例如,文本字段),或者需要昂贵的处理来将它们转换为Python对象。如果您在某些情 况下使用查询集的结果,当您最初获取数据时不知道是否需要这些特定字段,可以告诉 Django不要从数据库中检索它们。

    User.objects.defer("username", "email")

    16>.删除对象

      删除对象使用delete()。这个方法将立即删除对象且没有返回值。 

    Entry.objects.filter(pub_date__year=2005).delete()

    17>.拷贝模型实例

      虽然没有内建的方法用于拷贝模型实例,但还是很容易创建一个新的实例并让它的所有字段都 拷贝过来。最简单的方法是,只需要将pk 设置为None。

    blog = Blog(name='My blog', tagline='Blogging is easy')
    blog.save() # blog.pk == 1
    blog.pk = None
    blog.save() # blog.pk == 2

    18>.更新对象

      更新对象使用update() 

    Entry.objects.filter(pub_date__year=2007).update(headline='Everything is the same')

      update() 方法会立即执行并返回查询匹配的行数(如果有些行已经具有新的值,返回的行 数可能和被更新的行数不相等) 

    19>.专门取对象由某列值的操作

      F()允许Django在未实际链接数据的情况下具有对数据库字段的值的引用。通常情况下我们 在更新数据时需要先从数据库里将原数据取出后方在内存里,然后编辑某些属性,最后提 交。例如

    order = Order.objects.get(orderid='123456789') order.amount += 1 order.save() 

    这时就可以使用F()方法,代码如下

     from django.db.models import F order = Order.objects.get(orderid='123456789') order.amount = F('amount') - 1 order.save()

    20>.Q() -- 对对象的复杂查询

      Q对象(django.db.models.Q)可以对关键字参数进行封装,从而更好地应用多个查询。可以 组合使用 &(and),|(or),~(not)操作符,当一个操作符是用于两个Q的对象,它产生 个新的 对象 一个新的Q对象。

    Order.objects.get( 
        Q(desc__startswith='Who'), 
        Q(create_time=date(2016, 10, 2)) | Q(create_time=date(2016,10, 6)) 
    ) 

      相当于:

     SELECT * from polls WHERE question LIKE 'Who%' AND (pub_date = '2005-05-02' OR pub_date = '2005-05-06')

    21>.序列化模型对象

    from django.core import serializers 
    
    data = serializers.serialize("json", SomeModel.objects.all()) 

      序列化子集 

    from django.core import serializers 
    
    data = serializers.serialize("json", User.objects.all()[0:10], fields=('username','is_active'))

      

    四.模型关系

      关系数据库的威力体现在表之间的相互关联,Django提供了三种最常见的数据库关系:多对一 (many-to-one),多对多(many-to-many),一对一(one-to-one)。

    1>.多对一

       django是使用django.db.models.ForeignKey 定义多对一关系

      ForeignKey需要一个位置参数来指定本Model关联的Model,ForeignKey关联的Model。是"一", ForeignKey所在的Model是"多" 比如汽车和制造商的例子,一辆汽车只能属于一个制造商,但是一个制造商有多辆汽车,这个关系,用Django的Model来表示,代码如下所示:
    class Manufacturer(models.Model):
      name = models.CharField(max_length=30)
    
    class Car(models.Model):
      manufacturer = models.ForeignKey(Manufacturer) name = models.CharField(max_length=30)

    2>.多对一查询

      正向查询( ForeignKey 所在的模型查询关联的模型)
    car = Car.objects.get(pk=2)
    
    car.manufacturer       
    #返回一条Manufacturer 对象
      反向查询( ForeignKey 指向的模型查询ForeignKey 所在的模型)

      如果模型有一个ForeignKey,那么该ForeignKey 所指的模型实例可以通过一个管理器返回 前一个有ForeignKey的模型的所有实例。默认情况下,这个管理器的名字为foo_set,其中 foo 是源模型的小写名称。该管理器返回的查询集可以用上一节提到的方式进行过滤和操作。

    manufacturer = Manufacturer.objects.get(pk=1) 

    manufacturer.car_set.all() # 返回多个car对象

    3>.处理关联对象的其它方法

    add(obj1, obj2, ...) #添加一指定的模型对象到关联的对象集中。
    
    create(**kwargs) #创建一个新的对象,将它保存并放在关联的对象集中。返回新创建的对象。
    
    remove(obj1, obj2, ...) #从关联的对象集中删除指定的模型对象。
    
    clear() #从关联的对象集中删除所有的对象。

    4>.多对多

      要实现多对多,就要使用django.db.models.ManyToManyField类,和ForeignKey一样,它 也有一个位置参数,用来指定和它关联的Model。

      如果不仅仅需要知道两个Model之间是多对多的关系,还需要知道这个关系的更多信息, 比如Person和Group是多对多的关系,每个person可以在多个group里,那么group里可以有多个person。

    class Group(models.Model):
      #...

    class Person(models.Model): groups = models.ManyToManyField(Group)
      建议以被关联模型名称的复数形式做为 ManyToManyField 的名字
      在哪个模型中设置 ManyToManyField 并不重要,在两个模型中任选一个即可——不要在两个模型中都设置

    5>.一对一 

      一对一是通过django.db.models.OneToOneField来实现的,被关联的Model会被加上 Unique的限制, OneToOneField要一个位置参数,与模型关联的类

      当某个对象想扩展自另一个对象时,最常用的方式就是在这个对象的主键上添加一对一关系。

  • 相关阅读:
    Java获取EXE文件图标的方法
    项目组:ouc海票票 第七周Scrum meeting会议记录
    NBear使用的注意点
    几个错误
    DataGrid列中如何去掉小数后的零
    自己看着视频的理解:设计模式之abstractfactory模式(2)
    SQL SERVER 与ACCESS、EXCEL之间的数据转换(转载)
    .NET 将文本转换成语音 (转)
    InstallShield 打包需要的几段脚本代码
    SQL2005性能分析一些细节功能你是否有用到? (转)
  • 原文地址:https://www.cnblogs.com/yinzhengjie/p/10278354.html
Copyright © 2020-2023  润新知