Django之ORM基础
一 ORM介绍
Django提供了一个抽象层("Model")来构建和管理Web应用程序的数据。
Django使用一种新的方式,即:关系对象映射(Object Relational Mapping,简称ORM):
- 每个模型就是一个Python类,它继承于django.db.models.Model,对应关系:类名 —> 数据库表名
- 模型中的每个属性代表一个数据库字段,对应关系:类属性 –> 数据库中的字段
- 其他:类实例 –> 数据库表中的一行数据;obj.xx –> 类实例对象的属性
ORM两大功能:
-
操作表:增删改
-
操作数据行:增删改查
注:Django中遵循 Code Frist 的原则,即:根据代码中定义的类来自动生成数据库表。
Django ORM的优势:
Django的ORM操作本质上会根据对接的数据库引擎,翻译成对应的sql语句;所有使用Django开发的项目无需关心程序底层使用的是MySQL、Oracle、sqlite....,如果数据库迁移,只需要更换Django的数据库引擎即可
二 字段
AutoField(Field) #int自增列,必须填入参数 primary_key=True *** BigAutoField(AutoField) #bigint自增列,必须填入参数 primary_key=True 注:如果model中没有自增列,则自动会创建一个列名为id的列 from django.db import models class UserInfo(models.Model): # 自动创建一个列名为id的且为自增的整数列 username = models.CharField(max_length=32) class Group(models.Model): # 自定义自增列 nid = models.AutoField(primary_key=True)
name = models.CharField(max_length=32) CharField(Field) #字符类型,必须提供max_length参数, max_length表示字符长度 *** TextField(Field) #文本类型 #字符串类 EmailField(CharField): #Django Admin以及ModelForm中提供验证机制 IPAddressField(Field) #Django Admin以及ModelForm中提供验证 IPV4 机制 URLField(CharField) #Django Admin以及ModelForm中提供验证 URL SlugField(CharField) #Django Admin以及ModelForm中提供验证支持 字母、数字、下划线、连接符(减号) CommaSeparatedIntegerField(CharField) #格式必须为逗号分割的数字 UUIDField(Field) #Django Admin以及ModelForm中提供对UUID格式的验证 GenericIPAddressField(Field) #Django Admin以及ModelForm中提供验证 Ipv4和Ipv6 - 参数: protocol,用于指定Ipv4或Ipv6, 'both',"ipv4","ipv6" unpack_ipv4, 如果指定为True,则输入::ffff:192.0.2.1时候,可解析为192.0.2.1,开启刺功能,需要protocol="both" FilePathField(Field) #Django Admin以及ModelForm中提供读取文件夹下文件的功能 - 参数: path, 文件夹路径 match=None, 正则匹配 recursive=False, 递归下面的文件夹 allow_files=True, 允许文件 allow_folders=False, 允许文件夹 FileField(Field) #路径保存在数据库,文件上传到指定目录 - 参数: upload_to = "" 上传文件的保存路径 storage = None 存储组件,默认django.core.files.storage.FileSystemStorage ImageField(FileField) #路径保存在数据库,文件上传到指定目录 - 参数: upload_to = "" 上传文件的保存路径 storage = None 存储组件,默认django.core.files.storage.FileSystemStorage width_field=None, 上传图片的高度保存的数据库字段名(字符串) height_field=None 上传图片的宽度保存的数据库字段名(字符串) #数字类 SmallIntegerField(IntegerField): #小整数 -32768 ~ 32767 PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField) #正小整数 0 ~ 32767 IntegerField(Field) #整数列(有符号的) -2147483648 ~ 2147483647 *** PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField) #正整数 0 ~ 2147483647 BigIntegerField(IntegerField): #长整型(有符号的) -9223372036854775808 ~ 9223372036854775807 DurationField(Field) #长整数,时间间隔,数据库中按照bigint存储,ORM中获取的值为datetime.timedelta类型 FloatField(Field) #浮点型 *** BinaryField(Field) #二进制类型 DecimalField(Field) #10进制小数 *** - 参数: max_digits,小数总长度 decimal_places,小数位长度 #布尔值类 BooleanField(Field) #可以为空的布尔值 NullBooleanField(Field): #时间类 DateTimeField(DateField) #日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] *** DateField(DateTimeCheckMixin, Field) #日期格式 YYYY-MM-DD TimeField(DateTimeCheckMixin, Field) #时间格式 HH:MM[:ss[.uuuuuu]]
#枚举类型适用于选项固定的情况 color_list = ( (1,'黑色'), (2,'白色'), (3,'蓝色') ) color = models.IntegerField(choices=color_list)
class UnsignedIntegerField(models.IntegerField): def db_type(self, connection): return 'integer UNSIGNED' PS: 返回值为字段在数据库中的属性,Django字段默认的值为: '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)',
1.触发Model中的验证和错误提示有两种方式: a. Django Admin中的错误信息会优先根据Admiin内部的ModelForm错误信息提示,如果都成功,才来检查Model的字段并显示指定错误信息 b. 使用ModelForm c. 调用Model对象的 clean_fields 方法,如: # models.py class UserInfo(models.Model): nid = models.AutoField(primary_key=True) username = models.CharField(max_length=32) email = models.EmailField(error_messages={'invalid': '格式错了.'}) # views.py def index(request): obj = models.UserInfo(username='11234', email='uu') try: print(obj.clean_fields()) except Exception as e: print(e) return HttpResponse('ok') # Model的clean方法是一个钩子,可用于定制操作,如:上述的异常处理。 2.Admin中修改错误提示 # admin.py from django.contrib import admin from model_club import models from django import forms class UserInfoForm(forms.ModelForm): age = forms.IntegerField(initial=1, error_messages={'required': '请输入数值.', 'invalid': '年龄必须为数值.'}) class Meta: model = models.UserInfo # fields = ('username',) fields = "__all__" exclude = ['title'] labels = { 'name':'Writer', } help_texts = {'name':'some useful help text.',} error_messages={ 'name':{'max_length':"this writer name is too long"} } widgets={'name':Textarea(attrs={'cols':80,'rows':20})} class UserInfoAdmin(admin.ModelAdmin): form = UserInfoForm admin.site.register(models.UserInfo, UserInfoAdmin)
models.CharField 对应的是MySQL的varchar数据类型
char 和 varchar的区别 :
char和varchar的共同点是存储数据的长度,不能 超过max_length限制,
不同点是varchar根据数据实际长度存储,char按指定max_length()存储数据;所有前者更节省硬盘空间;
在数据库存储枚举类型,比外键有什么优势? 1、无需连表查询性能低,省硬盘空间(选项不固定时用外键) 2、在modle文件里不能动态增加(选项一成不变用Django的choice)
三 字段参数
null 数据库中字段是否可以为空
db_column 数据库中字段的列名
default 数据库中字段的默认值
primary_key 数据库中字段是否为主键
db_index 数据库中字段是否可以建立索引
unique 数据库中字段是否可以建立唯一索引
unique_for_date 数据库中字段【日期】部分是否可以建立唯一索引
unique_for_month 数据库中字段【月】部分是否可以建立唯一索引
unique_for_year 数据库中字段【年】部分是否可以建立唯一索引
verbose_name Admin中显示的字段名称
blank Admin中是否允许用户输入为空
editable Admin中是否可以编辑
help_text Admin中该字段的提示信息
choices Admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作
如:gf = models.IntegerField(choices=[(0, '何穗'),(1, '大表姐'),],default=1)
error_messages 自定义错误信息(字典类型),从而定制想要显示的错误信息;
字典健:null, blank, invalid, invalid_choice, unique, and unique_for_date
如:{'null': "不能为空.", 'invalid': '格式错误'}
validators 自定义错误验证(列表类型),从而定制想要的验证规则
from django.core.validators import RegexValidator
from django.core.validators import EmailValidator,URLValidator,DecimalValidator,\
MaxLengthValidator,MinLengthValidator,MaxValueValidator,MinValueValidator
如:
test = models.CharField(
max_length=32,
error_messages={
'c1': '优先错信息1',
'c2': '优先错信息2',
'c3': '优先错信息3',
},
validators=[
RegexValidator(regex='root_\d+', message='错误了', code='c1'),
RegexValidator(regex='root_112233\d+', message='又错误了', code='c2'),
EmailValidator(message='又错误了', code='c3'), ]
)
四 元信息
class UserInfo(models.Model): nid = models.AutoField(primary_key=True) username = models.CharField(max_length=32) class Meta: # 数据库中生成的表名称 默认 app名称 + 下划线 + 类名 db_table = "table_name" # 联合索引 index_together = [ ("pub_date", "deadline"), ] # 联合唯一索引 unique_together = (("driver", "restaurant"),) # admin中显示的表名称 verbose_name # verbose_name加s verbose_name_plural
更多请参考:https://docs.djangoproject.com/en/1.10/ref/models/options/
五 数据库设置--MySQL
Django中默认数据库为SQLlite,settings.py内设置如下:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
所以,如果我们需要变更为MySQL。同时,又因为Django内部连接mysql时使用的是MySQLdb,而py3中还没有此模块,所以需要需要pymysql来代替。具体设置步骤如下:
第一步:创建数据库
由于Django自带的ORM是data_first类型的ORM,使用前必须先创建数据库,创建时注意设置数据的字符编码。
第二步:在settings.py中将DATABASES做如下设置以连接MySQL数据库:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME':'test11', # 数据库名称
'USER': 'root', # 用户名
'PASSWORD': '', # 密码
'HOST': 'localhost', # 主机位置
'PORT': 3306, # 端口
}
}
扩展知识:如我们需要查看ORM操作执行的原生SQL语句,我们可以在settings.py中增加以下代码:
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console':{
'level':'DEBUG',
'class':'logging.StreamHandler',
},
},
'loggers': {
'django.db.backends': {
'handlers': ['console'],
'propagate': True,
'level':'DEBUG',
},
}
}
第三步:在同工程名下的__init__文件中设置Django默认连接MySQL的方式:
import pymysql pymysql.install_as_MySQLdb()
六 创建数据表
第一步:在相应app文件夹中的modals.py进行数据库类创建
from django.db import models
class UserGroup(models.Model):
"""部门"""
department = models.CharField(max_length=32)
class UserInfo(models.Model):
"""员工"""
uid = models.AutoField(primary_key=True) # 若无指定,Django为默认生成以id命名的一列自增数据
username = models.CharField(max_length=32) # 必须指定长度
password = models.CharField(max_length=64)
age = models.IntegerField(default=1)
ug = models.ForeignKey("UserGroup",null=True) # 生成数据库后,列名称变更为ug_‘外键表的id’
第二步:在settings.py文件中注册app文件
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles', # 以上为默认
'app01',
]
注:Django新版本已经进行该步,我们不需要再进行该操作。
第三步:进行数据迁移。在终端输入以下命令(如需进行表格修改,重新执行该命令):
python manage.py makemigrations python manage.py migrate
注:我们需要更新或修改字段时,也需要执行以上代码
在执行第三步时,应用外键行可能出现如下错误:
TypeError: __init__() missing 1 required positional argument: 'on_delete'
解决办法:
ug=models.ForeignKey('UserGroup',on_delete=models.CASCADE,) # 即在外键值的后面加上 on_delete=models.CASCADE
注意:在我们修改数据表结构时,如果新增一个字段,需要设置其为空或者给其设置默认值,否则会报错。
另外,可能会报以下错误:
django.core.exceptions.ImproperlyConfigured: mysqlclient 1.3.13 or newer is required; you have 0.9.3.
解决办法:
找到python安装环境或项目虚拟环境路径下的:...\Lib\site-packages\django\db\backends\mysql\base.py文件将以下代码注释掉。
if version < (1, 3, 13): raise ImproperlyConfigured('mysqlclient 1.3.13 or newer is required; you have %s.' % Database.__version__)

浙公网安备 33010602011771号