zoukankan      html  css  js  c++  java
  • ORM字段上

    ORM

    • 在MVC或者说MTV设计模式中,模型(M)代表对数据库的操作。MVC或者MVC框架中包括一个重要的部分,就是ORM,它实现了数据模型与数据库的解耦,即数据模型的设计不需要依赖于特定的数据库,通过简单的配置就可以轻松更换数据库,这极大的减轻了开发人员的工作量,不需要面对因数据库变更而导致的无效劳动。
    • ORM是“对象-关系-映射”的简称。(Object Relational Mapping,简称ORM)(sqlalchemy,和它很像,但是django的orm没有独立出来让别人去使用,虽然功能比sqlalchemy更强大,但是别人用不了)
    • 类对象--->sql--->pymysql--->mysql服务端--->磁盘,ORM将一个Python的对象映射为数据库中的一张关系表。它将SQL封装起来,程序员不再需要关心数据库的具体操作,只需要专注于自己本身代码和业务逻辑的实现。

    Django的ORM系统体现在框架内就是模型层。一个Python的类,就是一个模型,代表数据库中的一张数据表。Django奉行Python优先的原则,一切基于Python代码的交流,完全封装SQL内部细节。

    图片来自于网络

    一个模型(model)就是一个单独的、确定的数据的信息源,包含了数据的字段和操作方法。通常,每个模型映射为一张数据库中的表。

    基本的原则如下:

    • 每个模型在Django中的存在形式为一个Python类

    • 每个模型都是django.db.models.Model的子类

    • 每一个字段都是一个类属性,每个类属性表示数据表中的一个列。

    • Django将自动为你生成数据库访问API

    • 表由Django自动生成,默认格式为“项目名称+下划线+小写类名”,你可以重写这个规则。

    • Django默认自动创建自增主键id,可以自己指定主键。

    • 需要将模型编写在其所属app下的models.py文件中。

    orm翻译成sql的过程,效率低了,但一般的场景用orm,开发起来速度更快,数据库升级或者变更,如从mysql变更到oracle,只需要修改一下orm的引擎,之前写的那些orm语句还是会自动翻译成对应数据库的sql语句。

    Django默认使用SQLite这种轻量级的基于文件的数据库作为生产数据库。

    使用MySQL数据库

    创建一个mysite数据库,并将字符编码设置为utf8:

    mysql> CREATE DATABASE mysite CHARACTER SET utf8;

    配置MySQL服务:由于我的环境是局域网,Django项目所在主机为192.168.43.1,而mysql所在linux为虚拟机,IP为192.168.43.127,为了能够从项目主机访问数据库主机,需要对MySQL服务进行配置。

    打开mysql配置文件:

    sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf

    将下面一行注释掉:

    # band-address = localhost
    # .....

    [mysqld]
    #
    # * Basic Settings
    #
    user            = mysql
    pid-file        = /var/run/mysqld/mysqld.pid
    socket          = /var/run/mysqld/mysqld.sock
    port            = 3306
    basedir         = /usr
    datadir         = /var/lib/mysql
    tmpdir          = /tmp
    lc-messages-dir = /usr/share/mysql
    skip-external-locking
    #bind-address= localhost
    skip-name-resolve
    character-set-server=utf8

    # .....

    如果不这么做,将会出现error:1045 deny access,拒绝访问错误。然后再重启mysql服务。

    配置Django的settings.py

    DATABASES = {
        'default': {
            'ENGINE''django.db.backends.mysql',
            'NAME':'mysite',         # NAME:数据库的名字,在mysql连接前该数据库必须已经创建
            'USER':'root',        # 连接数据库的用户名
            'PASSWORD':'',        # 连接数据库的密码
            'HOST':'192.168.43.127',  # mysql服务所在的主机ip,默认本机为127.0.0.1
            'PORT'3306            #  端口 默认3306
        },
        'app01': { # 以下设置也可以不写,每个app都可以配置自己的设置,并且数据库还可以指定别的,也就是不一定就是mysql,也可以指定sqlite等其他的数据库。
            'ENGINE''django.db.backends.mysql',
            'NAME':'mysite',         # 要连接的数据库,连接前需要创建好
            'USER':'root',        # 连接数据库的用户名
            'PASSWORD':'',        # 连接数据库的密码
            'HOST':'192.168.43.127',  # mysql服务所在的主机ip,默认本级
            'PORT'3306            #  端口 默认3306
        }
    }

    安装Python访问MySQL的模块:django默认导入的驱动是MySQLdb,Django官方不建议使用pymysql库,而是改用mysqlclient,直接pip安装即可:pip install mysqlclient

    但我用的仍为pymysql,因此再增加一些设置:需要找到项目名文件下的__init__.py,在里面写入: 

    import pymysql
    pymysql.install_as_MySQLdb()

    创建表

    from django.db import models

    # Create your models here.


    class Book(models.Model):
         id=models.AutoField(primary_key=True# 如果表里面没有写主键,表里面会自动生成一个自增主键id字段。
         title=models.CharField(max_length=32
         state=models.BooleanField()
         pub_date=models.DateField()    # 必须存这种格式"2018-12-12"
         price=models.DecimalField(max_digits=8,decimal_places=2# max_digits最大位数,decimal_places小数部分占多少位
         publish=models.CharField(max_length=32)

    最后通过两条数据库迁移命令即可在指定的数据库中创建表 :

    1. python manage.py makemigrations:生成记录,django会在相应的 app 的migration文件夹下面生成 一个python脚本文件,修改动作保存到记录文件中,方便github等工具的使用。
    2. python manage.py migrate :执行上面这个语句的记录来创建表,让操作实际应用到数据库上。

    同步指令的执行简单原理:

    django根据migration下面的脚本文件来生成数据表的,每个migration文件夹下面有多个脚本,django有一张django-migrations表,表中记录了已经执行的脚本,表中没有的就是还没执行的脚本,则执行migrate的时候就只执行表中没有记录的那些脚本。
    有时在执行migrate的时候如果发现没有生成相应的表,可以看看在 django-migrations表中看看脚本是否已经执行了,可以删除 django-migrations 表中的记录 和 数据库中相应的表,然后重新执行。

    INSTALLED_APPS = [
        'django.contrib.admin',  # 这些功能如果你注销了,那么执行同步数据库指令之后,就不会生成那些django自带的表了。因为执行数据库同步语句的时候,django会找这里面所有的应用,找到他们的models来创建表.
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        "book"
    ]

    当每次对模型进行增、删、修改时,先执行python manage.py makemigrations,再执行命令python manage.py migrate

    打印orm转换过程中的sql语句

    方法一:需要在settings中进行如下配置:

    LOGGING = {
        'version'1,
        'disable_existing_loggers'False,
        'handlers': {
            'console':{
                'level':'DEBUG',
                'class':'logging.StreamHandler',
            },
        },
        'loggers': {
            'django.db.backends': {
                'handlers': ['console'],
                'propagate'True,
                'level':'DEBUG',
            },
        }
    }  

    方法二:

    from app01 import models
    from django.db import connection  # 需要导入模块
    def add_book(request):
        '''
        增删改查语句
        '''

        print(connection.queries)   # 查看sql语句
        ...

    模型字段fields

    字段命名约束:

    • 与Python关键字冲突。这会导致语法错误。

    • 字段名中不能有两个以上下划线在一起,因为两个下划线是Django的查询语法。例如:

      class Example(models.Model): foo__bar = models.IntegerField()

    SQL语言的join、where和select等保留字可以作为字段名,因为Django对它们都进行了转义。

    常用字段类型

    字段类型的作用:

    • 决定数据库中对应列的数据类型(例如:INTEGER, VARCHAR, TEXT)。
    • HTML中对应的表单标签的类型。
    • 在admin后台和自动生成的表单中最小的数据验证需求。

    Django内置了许多字段类型,它们都位于django.db.models中。也可以自定义字段。

    下表列出了所有Django内置的字段类型,但不包括关系字段类型(字段名采用驼峰命名法):

    类型 说明
    AutoField 一个自动增加的整数类型字段。通常不需要直接使用这个字段,若不指定主键,Django会自动添加字段:id = models.AutoField(primary_key=True),如果要设置主键,那么需将字段设置为primary_key=True。Django在一个模型中只允许有一个自增字段,并且该字段必须为主键
    BigAutoField 64位整数类型自增字段,数字范围更大,从1到9223372036854775807
    BigIntegerField 64位整数字段(非自增),类似IntegerField,数字范围更大 ,-9223372036854775808 到9223372036854775807。在Django的模板表单里体现为一个textinput标签。
    BinaryField 二进制数据类型。
    BooleanField 布尔值类型。默认值是None。在HTML表单中体现为CheckboxInput标签。如果要接收null值,应使用NullBooleanField。
    CharField 字符串类型。用于较短的字符串。
    必须接收一个max_length参数,表示字符串长度不能超过该值。默认的表单标签是input text。
    CommaSeparatedIntegerField 逗号分隔的整数类型。
    必须接收一个max_length参数。常用于表示较大的金额数目,例如1,000,000元。
    DateField class DateField(auto_now=False, auto_now_add=False, **options)日期字段。一个Python中的datetime.date的实例。在HTML中表现为TextInput标签。在admin后台中,Django会自动添加一个JS的日历表和一个“Today”快捷方式,以及附加的日期合法性验证。
    两个重要参数:(参数互斥,不能共存) auto_now:每当对象被保存(更新或者添加)时将字段设为当前日期auto_now_add:每当对象被创建时,设为当前日期,不可修改。设置上面两个参数就相当于给field添加了editable=Falseblank=True属性。例子:pub_time = models.DateField(auto_now_add=True),还有一个参数:Argument,用来描述。
    DateTimeField 日期时间类型。Python的datetime.datetime的实例。与DateField相比多了小时、分和秒的显示,其它功能、参数、用法、默认值等等都一样。
    DecimalField 固定精度的十进制小数。必须提供两个指定的参数。
    参数max_digits:总位数(不包括小数点和符号),必须大于或等于小数点位数 。decimal_places:小数点位数。 当localize=False时,它在HTML表现为NumberInput标签,否则是text类型。
    DurationField 持续时间类型。存储一定期间的时间长度。类似Python中的timedelta。在不同的数据库实现中有不同的表示方法。常用于进行时间之间的加减运算。PostgreSQL等数据库之间有兼容性问题。
    EmailField 邮箱类型,默认max_length最大长度254位。可以使用DJango内置的EmailValidator进行邮箱地址合法性验证。
    FileField class FileField(upload_to=None, max_length=100, **options)上传文件类型。
    FilePathField 文件路径类型。
    FloatField 浮点数类型
    ImageField 图像类型。
    有两个可选参数:height_field和width_field
    IntegerField 整数类型。取值范围-2147483648到2147483647。在HTML中表现为NumberInput标签。
    GenericIPAddressField class GenericIPAddressField(protocol='both', unpack_ipv4=False, **options),IPV4或者IPV6地址,字符串形式,例如192.0.2.30或者2a02:42fe::4在HTML中表现为TextInput标签。参数protocol默认值为‘both’,可选‘IPv4’或者‘IPv6’,表示你的IP地址类型。
    NullBooleanField 类似布尔字段,额外允许NULL作为选项之一。admin 用一个选择框<select> (三个可选择的值: "Unknown", "Yes" 和 "No" ) 来表示这种字段数据.
    PositiveIntegerField 正整数字段,0-2147483647。
    PositiveSmallIntegerField 正整数字段,0-32767。
    SlugField slug是一个新闻行业的术语。一个slug就是一个某种东西的简短标签,包含字母、数字、下划线或者连接线,通常用于URLs中。可以设置max_length参数,默认为50。
    SmallIntegerField 小整数,包含-32768到32767。
    TextField 大量文本内容,在HTML中表现为Textarea标签。如果为它设置一个max_length参数,那么在前端页面中会受到输入字符数量限制,但在模型和数据库层面却不受影响。只有CharField才能同时作用于两者。
    TimeField 时间字段,Python中datetime.time的实例。接收同DateField一样的参数,只作用于小时、分和秒。
    URLField 一个用于保存URL地址的字符串类型,默认最大长度200。
    UUIDField 用于保存通用唯一识别码(Universally Unique Identifier)的字段。使用Python的UUID类。在PostgreSQL数据库中保存为uuid类型,其它数据库中为char(32)。这个字段是自增主键的最佳替代品,后面有例子展示。

    FileField:

    class FileField(upload_to=None, max_length=100, **options)[source]

    上传文件字段(不能设置为主键)。默认情况下,该字段在HTML中表现为一个ClearableFileInput标签。在数据库内,我们实际保存的是一个字符串类型,默认最大长度100,可以通过max_length参数自定义。真实的文件是保存在服务器的文件系统内的。必须有的参数: upload_to。

    重要参数upload_to用于设置上传地址的目录和文件名。如下例所示:

    class MyModel(models.Model):
        # 文件被传至MEDIA_ROOT/uploads目录,MEDIA_ROOT由你在settings文件中设置
        upload = models.FileField(upload_to='uploads/')
        # 或者被传到MEDIA_ROOT/uploads/2015/01/30目录,增加了一个时间划分
        upload = models.FileField(upload_to='uploads/%Y/%m/%d/')

    upload_to参数也可以接收一个回调函数,该函数返回具体的路径字符串,如下例:

    def user_directory_path(instance, filename):
        #文件上传到MEDIA_ROOT/user_<id>/<filename>目录中
        return f'user_{instance.user.id}/{filename}'

    class MyModel(models.Model):
        upload = models.FileField(upload_to=user_directory_path)

    例子中,user_directory_path这种回调函数,必须接收两个参数,然后返回一个Unix风格的路径字符串。参数instace代表一个定义了FileField的模型的实例,即当前的数据记录。filename是原本的文件名。

    ImageField

    class ImageField(upload_to=None, height_field=None, width_field=None, max_length=100, **options)[source]

    用于保存图像文件的字段。其基本用法和特性与FileField一样,多了两个属性height和width,如果提供这两个参数,则图片将按提供的高度和宽度规格保存。默认情况下,该字段在HTML中表现为一个ClearableFileInput标签。在数据库内,我们实际保存的是一个字符串类型,默认最大长度100,可以通过max_length参数自定义。真实的图片是保存在服务器的文件系统内的。

    height_field参数:保存有图片高度信息的模型字段名。 width_field参数:保存有图片宽度信息的模型字段名。

    使用Django的ImageField需要提前安装pillow模块,pip install pillow

    注意:

    使用FileField或者ImageField字段的步骤:

    1. 在settings文件中,定义一个完整路径给MEDIA_ROOT以便让 Django在此处保存上传文件(为了性能考虑,这些文件不会被储存在数据库中)。再配置MEDIA_URL,作为公用URL,指向上传文件的基本路径。并要确保Web服务器的用户账号对该目录具有写的权限。
    2. 添加FileField或者ImageField字段到模型中,定义好upload_to参数,文件最终会放在MEDIA_ROOT目录的“upload_to”子目录中。
    3. 所有真正被保存在数据库中的,只是指向你上传文件路径的字符串。可以通过url属性,在Django的模板中方便的访问这些文件。例如,假设有一个ImageField字段,名叫mug_shot,那么在Django模板的HTML文件中,可以使用{{ object.mug_shot.url }}来获取该文件。其中的object用具体的对象名称代替。
    4. 可以通过namesize属性,获取文件的名称和大小信息。
    5. 无论如何保存上传的文件,一定要注意他们的内容和格式,避免安全漏洞。务必对所有的上传文件进行安全检查,确保它们不出问题。

    FilePathField

    class FilePathField(path=None, match=None, recursive=False, max_length=100, **options)[source]

    一种用来保存文件路径信息的字段。在数据表内以字符串的形式存在,默认最大长度100,可以通过max_length参数设置。

    它包含有下面的一些参数:

    path:必须指定的参数。表示一个系统绝对路径。

    match:可选参数,一个正则表达式,用于过滤文件名。只匹配基本文件名,不匹配路径。例如FilePathField(path="/home/images", match="foo.*", recursive=True),会匹配/home/images/foo.gif而不匹配/home/images/foo/bar.gif

    recursive:可选参数,只能是True或者False。默认为False。决定是否包含子目录,也就是是否递归的意思。

    allow_files:可选参数,只能是True或者False。默认为True。决定是否应该将文件名包括在内。它和allow_folders其中,必须有一个为True。

    allow_folders: 可选参数,只能是True或者False。默认为False。决定是否应该将目录名包括在内。

    比如:

    FilePathField(path="/home/images", match="foo.*", recursive=True)

    它只匹配/home/images/foo.png,但不匹配/home/images/foo/bar.png,因为默认情况,只匹配文件名,而不管路径是怎么样的。

    UUIDField:

    数据库无法自己生成uuid,因此需要如下使用default参数:

    import uuid     # Python的内置模块
    from django.db import models

    class MyUUIDModel(models.Model):
        id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)

    自定义字段

    class UnsignedIntegerField(models.IntegerField):
        def db_type(self, connection):
            return 'integer UNSIGNED'

    自定义char类型字段:

    class FixedCharField(models.Field):
        """
        自定义的char类型的字段类
        """

        def __init__(self, max_length, *args, **kwargs):
            super().__init__(max_length=max_length, *args, **kwargs)
            self.length = max_length

        def db_type(self, connection):
            """
            限定生成数据库表的字段类型为char,长度为length指定的值
            """

            return 'char(%s)' % self.length


    class Class(models.Model):
        # 使用上面自定义的char类型的字段
        cname = FixedCharField(max_length=25)

    ORM字段与数据库实际字段的对应关系:

    AutoField: integer AUTO_INCREMENT
    BigAutoField: bigint AUTO_INCREMENT,
    BinaryField: longblob,
    BooleanField: bool,
    CharField: varchar(%(max_length)s),
    CommaSeparatedIntegerField: varchar(%(max_length)s),
    DateField: date,
    DateTimeField: datetime,
    DecimalField: numeric(%(max_digits)s, %(decimal_places)s),
    DurationField: bigint,
    FileField: varchar(%(max_length)s),
    FilePathField: varchar(%(max_length)s),
    FloatField: double precision,
    IntegerField: integer,
    BigIntegerField: bigint,
    IPAddressField: char(15),
    GenericIPAddressField: char(39),
    NullBooleanField: bool,
    OneToOneField: integer,
    PositiveIntegerField: integer UNSIGNED,
    PositiveSmallIntegerField: smallint UNSIGNED,
    SlugField: varchar(%(max_length)s),
    SmallIntegerField: smallint,
    TextField: longtext,
    TimeField: time,
    UUIDField: char(32),
  • 相关阅读:
    针式PKM的主要画面的功能简介
    程序员早日走向架构师的利器:针式PKM V8.01发布
    如何经营你的知识资产
    一般软件工程师怎样拥有更多的资产
    剪贴板的使用技巧
    不要给自己找不“深入学习”的理由了
    《小论无所事事》
    全国(1977年~2011年)历年参加高考人数和录取人数
    Sql Server中,文件批量重命名
    HTML斜线表头
  • 原文地址:https://www.cnblogs.com/wby-110/p/13387152.html
Copyright © 2011-2022 走看看