目录



  • Django Model 模型
  • MODEL需要在脑子里记住的基础概念
  • 区分清楚,必须不能混淆的
  • class Meta 内嵌元数据定义类
  • 简单model创建实例
  • 数据源配置
  • 接着通过models在数据库中创建映射的表
  • Field class
  • model表示表关系
  • model.objects
  • 有关model继承
  • 有关通过model进行curd操作
  • 关于FileField 和 ImageField 字段类型类
  • 还有一个UploadedFile 对象,这个对象就是form表单post上来的文件对象。对象api参考:https://docs.djangoproject.com/en/2.1/ref/files/uploads/#module-django.core.files.uploadedfile



Django Model 模型

model 模型 是映射数据库的表模型。通过操作model类及其实例对象,对数据库的表和记录进行相关操作。

MODEL需要在脑子里记住的基础概念

  • 每一个model都是django.db.models.Model的子类。
  • 每一个model的属性代表一个数据库的一个字段。
  • 遵照以上两点,django会自动为model生成database-acesss数据库访问API

区分清楚,必须不能混淆的

  1. Model对象与Model类 两者在ORM操作使用上各自能提供的功能不同
  2. Model对象获取记录数据,字段属性是对应的数据库中的值转换到python的数据对象或者Manger对象。Model类提供全局操作,包括定义的field对象。

class Meta 内嵌元数据定义类

用于自定义一些model设置

class SomeModel(models.Model):
    pass
    class Meta:
        db_table = Cust_tablename  # 自定义的映射数据库的表名;一般用自动生成的。
        abstract = False|True  # 定义该model 类是不是一个抽象类。

简单model创建实例

from django.db import models

class author(models.Model):
    name = models.CharField(max_length=32)
    age = models.SmallIntegerField()

    def __str__(self): # 最好都设置,因为在多对多字段对对象的打印显示会用到。
        return self.name

数据源配置

利用pymysql作为访问mysql数据源的驱动

  1. 在项目目录的__init__.py中添加以下代码:
import pymysql
pymysql.install_as_MySQLdb()
  1. 通过其它数据库管理工具,在数据库中创建好库。然后配置数据库:
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'proj01',
        'USER': 'zjq',
        'PASSWORD': '123456',
        'HOST': '127.0.0.1',
        'PORT': '3306',
    }
}

# 'default'是必须设置的

这样我的mysql数据源就配好了。

接着通过models在数据库中创建映射的表

命令行执行:

  1. python manage.py makemigrations [app_label [app_label...]] # 创建migrations文件
  2. python manage.py sqlmigrate app_label migration_name # 用于打印指定migration文件会执行的sql,sql不会同步执行到数据库中,只起到查看作用。
  3. python manage.py migrate [app_label] [ migration_name]

Field class

model class 定义的field属性就是对应数据库表中的字段。model class中定义的属性所绑定的是一个匹配数据库字段类型的Field class实例.
Field实例类型决定了以下东西:

  1. 数据库column字段类型。
  2. 决定了默认的HTML widget对象,这个是用在model-forms中的。
  3. 最小限度的校验约束,用于在Django's admin 页面 和 在 自动生成的model-forms中。
Field options:Field对象实例化参数

每种field 都有自己的特定的参数,参考官方文档model field refernece

每种field也有共同相同的参数:

  • null 默认是False
  • 如果是True,那么对于empty value(空值‘’),django存入数据库中的就是NULL。否则空值就是空值存入。这是关于从python转换到数据库存储类型的问题。
  • 对于字符串类型的Field(CharField/TextField)最好用默认值,不然会存在两种表示空值的方式:即''与Null,对于字符串类型最好就null=False,避免歧义。
  • 但是对于字符类型,有一个特殊情况,如果字符串Field字段是unique约束的,如果null=False,那么空字符都被约束到了,我们如果想要对空值不约束,就将null设置为True.因为Null是不参与unique约束了。这样多个''空值就能存入到数据库中了。
  • blank 默认是False
  • 如果是True, 那么校验数据时允许空值。否则不允许空值。这是关于orm操作或者modelform相关校验的问题,对于orm操作可能空值存如;对于modelform校验,required就是False了。
    特别注意区别null和blank;null是操作到数据库相关,关系到存储到库中的值的;blank是model层面与校验相关的。
  • choices 是一个可迭代的由二元元组组成的数据类型(如list,tuple等),作为该字段限制的取值集合作用;二元元组中的第一个是数据库字段中存的值,第二个主要用于form表单中展示;相当于第一个字是value,第二个值是展示。使用了choices参数,字段对应的html widget将是select box,而不再是text input。通过model实例获取展示值使用get_FIELDNAME_display()获取
  • django baseModel中有外键 django常用模块_数据库

  • default 设置默认值,可以是value或者callable object.
  • primary_key 设置为主键;主键是只读的,如果修改只会去创建一个新的记录。

特殊的参数:

  • Date相关Field的auto_now 于 auto_now_add 参数的区别
  • 默认两个参数都是False。
  • auto_now = True 的话,自动设置为当前日期,只在调用model对象的save()方法时。所以要注意哪些API会间接调用save方法。(如modelform.save?? m2m.add()???)
  • auto_now_add = True 是只在model object首次创建时。
特别关注related_name和related_query_name

主要是有一种特殊情况,如果一个model有两个字段都是关联同一个表,那么被关联的这个表如果反向使用表名,这个表名对应的是两个字段的哪个字段的关联呢?所以就有了related_name参数的加入,来区分才行。而related_query_name 则是用于基于双下划线的反向查询时关联的字段别名。
报错fields.E304 ,就需要related_name参数进行解决了。还有就是注意这时候就不要再在后面加上_set的后缀了。

model表示表关系

  • many-to-many: ManyToManyField; 也可以自己递归引用。通过through可以给多对多关系添加额外数据字段,这种利用的就是中间人model方式。关于中间人model参见https://docs.djangoproject.com/en/2.1/topics/db/models/#extra-fields-on-many-to-many-relationships;使用了中间人model,就不能通过many-to-many的add(),create(),set(),remove()去创建关系了。因为额外数据不能通过多对多field来创建。只能通过中间人model去创建了 但是clear是可以用的,用于删除所有关系。通过中间人model的基于下划线的查询是不受影响的。
  • one-to-one: OneToOneField; 和下面的ForeignKeyField类似。
  • many-to-one : ForeignKeyField;外键引用不一定是其它表,可以自己递归,引用自己的字段,这样可以表示出树形关系。
on_delete 参数详解

在django2.0后,对OneToOneField和ManyToManyField在实例化字段时,都必须加上一个on_delete参数。
这个on_delete到底是何方神圣呢?
on_delete 的设置就是为了模仿数据库外键约束的行为,这个行为就是当被FK引用的数据(或数据对象)被删除时的处理行为。可指定的行为有以下几种:

  1. 当引用数据被删,将FK字段设置null。对应on_delete = models.SET_NULL,且FK设置了null=True。
  2. 当引用数据被删,引用该数据的数据将被删除,联级删除。对应on_delete = models.CASCADE。在django中,联级删除不会通过delete()方式删除,而是通过pre_delete 和 post_delete信号的方式,发送信号给所有应该被联级删除的对象。
  3. 当引用数据被删,抛出ProtectedError异常,避免被删。对应on_delete = models.PROTECT
  4. 当引用数据被删,将FK字段值设置为其default值。 对应on_delete = models.DEFAULT
  5. 当引用数据被删, 将FK值设置为一个回调函数返回的值。对应on_delete = models.SET(callable) ,callable就是定义的回调函数。
  6. 当引用数据被删,不做任何事情。对应on_delete = models.DO_NOTHING

model.objects

objects是model class 最重要的属性,它是一个Manager,是查询操作的接口。

有关model继承

参见《Django ORM继承关系》

有关通过model进行curd操作

参见《Django model making queries》

特别的QuerySet对象的操作,最佳实践是尽量使用链式操作(就像JQuery一样推荐链式操作)。

关于FileField 和 ImageField 字段类型类

因为model涉及到文件的这两个字段,数据库中是不最好不存文件对象,只能存一个文件的相对路径(实质就是相对于settings.MEDIA_ROOT的配置根路径). 该文件字段对象提供了丰富的api来获取文件对象,获取文件路径,获取文件相关信息等。这就是数据库model文件字段和文件管理的映射就依靠:MEDIA_ROOT+MEDIA_URL+models.filefield值 建立起映射,从而提供给api使用,这样就可以通过model的filefield对象访问到用户上传到的文件。
主要API有:

  1. model_obj.filefield 是获取到文件对象,将会是和下面的model_obj.filefield.name值相同,是定义字段时的upload_to加上文件名。
  2. model_obj.filefield.name 是获取存在数据库中的值,就是相对路径(相对于根目录)
  3. model_obj.filefield.path 是获取到path,文件系统中的绝对路径。
  4. model_obj.filefield.url 是获取url,是通过media_url设置的url能访问到的路径。如:/media/avatars/default.png。 这里一定要区分path和url的区别,path是文件系统中的路径概念,可以是相对可以是绝对,而url是网络资源路径不是和path一一对应的。

初始化FileField需要一个upload_to参数:

class MyModel(models.Model):
    # file will be uploaded to MEDIA_ROOT/uploads  // MEDIA_ROOT是配置文件设置的filesystem的绝对路径。
    upload = models.FileField(upload_to='uploads/')
    # or...
    # file will be saved to MEDIA_ROOT/uploads/2015/01/30
    upload = models.FileField(upload_to='uploads/%Y/%m/%d/')

upload_to 参数也可以是一个可执行的,只要返回一个包含文件的路径;如果是可执行的对象,那么这个可执行就需要返回一个完整的文件名和路径,因为filefield将会用这个可执行对象返回的作为这个字段的值,这时候;这个给upload_to赋值一个路径字符串不同,后者会将字符串做为路径,将赋值的文件对象的名字和路径作为数据库中该字段对应的值。

还有一个FileField参数是storage 一个django的存储引擎对象,这个对象是handle存储和检索文件的引擎。
在获取到一个model对象后,给其filefield对象赋值文件路径字符串也可以。

FileField 和 field File

前者是一个Field类,后者是一个File类,是一个file文件对象。

当访问前者时,会得到一个后者实例。注意:在使用create_user方法创建model对象时,对应的FileField参数传入的是一个UploadedFile对象,但是从前者获的field获取值是,是得到的一个FieldFile对象。两个对象是相似但是不同的:相同的是都是文件对象,都是包裹了相同的文件stream,不同是的两者对外的api不同,两者获取的名字很可能是不同的,因为django会在创建model时,如果存在相同文件名,会修改新加如的文件名,避免文件冲突的。所以上传的文件名,存入django MEDIA_ROOT目录后,文件名字可能是会被修改的。后者File对象还有了url路径,提供给外界访问用户上传文件资源的url。

现在清楚了,FileField牵扯到了 存储对象,文件对象,系统配置MEDIA_ROOT,至于MEDIA_URL是给反查url或者获取url api用的。

django系统给了一个serve view函数,来提供访问用户的上传文件和系统的静态文件的功能。这个函数需要两个参数,一个文件的path,和文件的path相对的root路径。