一 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
在数据库存储枚举类型,比外键有什么优势?
1、无需连表查询性能低,省硬盘空间(选项不固定时用外键)
2、在modle文件里不能动态增加(选项一成不变用Django的choice)
扩展2
三 字段参数
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
View Code
更多请参考: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__)