Django model 层之Models与Mysql数据库小结
Django model 层之Models与Mysql数据库小结
by:授客 QQ:1033553122
测试环境:
Python版本:python-3.4.0.amd64
下载地址:https://www.python.org/downloads/release/python-340/
Win7 64位
Django 1.11.4
下载地址:https://www.djangoproject.com/download/
MySQL数据库为例,假设项目目录结构如下:
mysite/
myapp/
__init__.py
admin.py
apps.py
migrations/
__init__.py
models.py
tests.py
views.py
manage.py
mysite/
__init__.py
settings.py
urls.py
wsgi.py
配置数据库信息
打开项目根目录下,与项目同名的目录,编辑settings.py(例中mysite/mysite/settings.py文件),
找到以下代码
DATABASES = {
"default": {
……略
}
}
修改为以下内容:
DATABASES = {
"default": {
"ENGINE": "django.db.backends.mysql",
"NAME": "testdb",
"USER": "testacc",
"PASSWORD": "test1234",
"HOST": "192.168.1.102",
"PORT": "3306",
"OPTION":{
"init_command": "SET default_storage_engine=INNODB"
}
}
}
说明:
ENGINE:默认为空。可选值:
“django.db.backends.postgresql”
“django.db.backends.mysql”
“django.db.backends.sqlite3”
“django.db.backends.oracle”
NAME:数据库名字。
如果使用SQLite,数据库文件将存放在电脑上,这种情况下,NAME应该为绝对路径,包含数据库文件的文件名。默认值如下,把数据库文件存放在项目根目录下。
DATABASES = {
“default”: {
“ENGINE”: “django.db.backends.sqlite3”,
“NAME”: os.path.join(BASE_DIR, “db.sqlite3”),
}
}
如果不使用SQLite,需要设置额外参数如USER, PASSWORD,HOST, PORT。
另外,确保提供的USER具备“create database”权限。
USER: 数据库用户名,默认为””
PASSWORD:连接数据库用户密码,默认为””
HOST: 数据库服务器主机地址,默认为””,代表localhost。支持tcp socket除外的其它socket连接方式,更多详情请查看官方文档。
PORT:数据库访问端口,默认为””,代表默认端口。
AUTOCOMMIT: 自动提交事务。默认为True。设置为False,则禁用Django 事务管理,采用自己实现的事务管理。
更多选项设置,请参考官方文档。
参考链接:
https://docs.djangoproject.com/en/1.11/ref/settings/#databases
建立表
编辑应用目录下的models.py文件(例中为 mysite/myapp/models.py)
from django.db import models
# Create your models here.
class Person(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
新增以上带背景色代码
first_name和last_name为model的field。每个field映射到一个数据库列。
以上Person model将创建如下表:
CREATE TABLE myapp_person (
“id” serial NOT NULL PRIMARY KEY,
“first_name” varchar(30) NOT NULL,
“last_name” varchar(30) NOT NULL);
注意:
1、如上,表名命名方式为应用名称_转为小写的model名称,我们可以通过Meta属性实现表名自定义,如下:
CREATE TABLE myapp_person (
“id” serial NOT NULL PRIMARY KEY,
“first_name” varchar(30) NOT NULL,
“last_name” varchar(30) NOT NULL);
class Meta:
db_table = “tb_person”#数据库中创建的表名称即为 tb_person
verbose_name = “用户表”#表名称 #在admin站点中显示的名称
verbose_name_plural = verbose_name#显示的复数名称
2、自动为数据库增加 id 自增主键列。因为,默认的,Django为每个模块设置一个field:
id = models.AutoField(primary_key=True)
如果想自己指定一个自定义的主键列,则必须按上述设置,显示指定字段名称。总之,不管是默认设置还是显示设置,必须有一个自增主键列。
参考链接:
https://docs.djangoproject.com/en/1.11/topics/db/models/#automatic-primary-key-fields
class Book(models.Model):
book_name = models.CharField(max_length=30)
borrower = models.ForeignKey(Person, to_field="id", on_delete=models.CASCADE)
说明:mysql中,生成的外键列名称,会自动命名为:field_id,如上borrower field对应的mysql列为borrower_id
class Musician(models.Model):
auto_id = models.IntegerField(primary_key=True)
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
instrument = models.CharField(max_length=100)
last_update = models.DateField(auto_now=True, auto_now_add=True)
class Album(models.Model):
artist = models.ForeignKey(Musician, to_field="auto_id", on_delete=models.PROTECT)
name = models.CharField(max_length=100)
release_date = models.DateField()
num_stars = models.IntegerField()
Field 类型
AutoField
IntegerField,根据可获取的ID列值,自增
参数:verbose_name,个人推断,所有Field类型应该都有该参数,用于设置字段名称
BigAutoField
64位整型,类似AutoField,不同之处在于它可接收更大范围的数值:1 到9223372036854775807.
Django 1.10新增。
BigIntegerField
64位整型,类似IntegerField。不同之处在于它可接纳更大范围的数值:-9223372036854775808 到9223372036854775807。该field对应的默认组建:TextInput
BinaryField
用于存储原始二进制数据,仅支持字节。
BooleanField
true/false field.该field对应的默认表单组件:CheckboxInput。
如果需要接收null值,则使用NullBooleanField替代BooleanField。
如果未定义Field.default,那么BooleanField field默认值为None。
CharField
字符串类型。用于存储一定范围大小的字符串。针对大量文本,使用TextField。该field的默认组建为:TextInput
。
CharField有个额外的必填参数。CharField.max_length。设置可接纳的最大字符数。
DateField
日期类型。代表Python datetime.date实例。
class DateField(auto_now=False, auto_now_add=False, **options)[source]¶
可选参数:
DateField.auto_now
每次存储对象(仅针对调用save方法)时,自动设置该field的值为当前日期
注意:实践发现,调用Module_name.objects.Create()方法创建对象,auto_now()也起作用
DateField.auto_now_add
第一次创建对象时,自动设置field值为当前日期,所以,即便显示为该字段提供了值,也会自动忽视显示设定的值。
对于DateField:default=date.today – datetime.date.today()
对于DateTimeField: default=timezone.now – django.utils.timezone.now()
该field对应的默认表单组件为:TextInput。
注意:auto_now_add和auto_now两个参数不能同时使用。
TimeField
以python datetime.time实例表示的时间
可选参数:
DateField.auto_now
每次存储对象(仅针对调用save方法)时,自动设置该field的值为当前日期
DateField.auto_now_add
第一次创建对象时,自动设置field值为当前日期,所以,即便显示为该字段提供了值,也会自动忽视显示设定的值。
对于DateField:default=date.today – datetime.date.today()
对于DateTimeField: default=timezone.now – django.utils.timezone.now()
该field对应的默认表单组件为:TextInput。
DateTimeField
以python datetime.datetime实例表示的日期时间。
可选参数:
DateField.auto_now
每次存储对象(仅针对调用save方法)时,自动设置该field的值为当前日期时间
DateField.auto_now_add
第一次创建对象时,自动设置field值为当前日期时间,所以,即便显示为该字段提供了值,也会自动忽视显示
该field对应的默认表单组件为:TextInput。
DateTimeField字段的值,如果要保存为当前时间,可以通过timezone.now()快速获取当前时间进行赋值
>>> from django.utils import timezone
>>> update_time = timezone.now()
>>>user = User(username=”test1″, password=”passwd123″, email=”email@163.com”, update_time=update_time)
>>> user.save()
DecimalField
用Python Decimal实例表示的固定精度的数字。有两个必填参数:
DecimalField.max_digits
表示允许的最大值。必须大于等于decimal_spaces
DecimalField.decimal_places
设置精度位数。
比如field存储最大值不超过999,2位小数,设置如下:
models.DecimalField(…, max_digits=5, decimal_places=2)
该field对应的默认表单组件:当设置localize为False,则对应NumberInput,否则TextInput。
DurationField
存储以python timedelat表示的一段时间
EmailField
一个CharField,校验值是否是合法的email地址。使用EmailValidator校验输入值。
FileField
file-upload field。
注意:主键列不支持该类型。
更多详情参考官方文档。
FilePathField
一个CharField,可取值限制于系统上某个目录中的文件名
更多详情参考官方文档。
FloatField
python float实例表示的浮点数。
该field对应的默认表单组件:当设置localize为False,则对应NumberInput,否则TextInput。
ImageField
继承了FileField的所有属性和方法。校验上载对象是否是合法的图片。
更多详情参考官方文档。
IntegerField
整数。值从-2147483648 到2147483647,支持所有数据库。
该field对应的默认表单组件:当设置localize为False,则对应NumberInput,否则TextInput。
GenericIPAddressField
字符串格式(例如:192.0.2.30 or 2a02:42fe::4)表达的IPv4或IPv6地址,,针对IPv6,所有字符都会转为小写。
该field对应的默认表单组件:TextInput。
更多详情参考官方文档。
NullBooleanField
类似BooleanField,不同之处在于运行NULL值。等同BooleanField(…,null=True)。
该field对应的默认表单组件为NullBooleanSelect。
PositiveIntegerField
类似IntergerField,不同在于只接受正数,或者0.可取值范围:0 到2147483647
PositiveSmallIntegerField
类似PositiveIntegerField,可取值范围: 0 到 32767
SlugField
更多详情参考官方文档。
SmallIntegerField
类似IntegerField,取值范围:-32768 到 32767
TextField
大文本field。如果指定max_length属性,将作用于组件,但是不会是在数据库、model层起作用(If you specify a max_length attribute, it will be reflected in the Textarea widget of the auto-generated form field. However it is not enforced at the model or database level)。
该field对应的默认表单组件为:Textarea。
URLField
针对URL的CharField。可选参数:max_length,设置最大长度。默认200.
field对应的默认表单组件为:TextInput
UUIDField
存储全球唯一标识(universally unique identifier)。使用Python的UUID类。
对于主键AutoField来说,UUIDFeild是个很好的选择。但是数据库不会生成UUID,所以推荐使用default,如下:
import uuidfrom django.db import models
class MyUUIDModel(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
# other fields
参考链接:
https://docs.djangoproject.com/en/1.11/ref/models/fields/#model-field-types
常用Field option
null
如果设置null=True,保存数据到数据库时,把“空值”存储为NULL。默认null=False。
blank
如果设置blank=True, 允许Field值为空,字符型字段CharField和TextField是用空字符串来存储空值的。默认False
注意:
blank 是针对表单的,如果 blank=True,表示你的表单填写该字段的时候可以不填。
null 是针对数据库而言,如果 null=True, 表示数据库的该字段可以为空,那么在新建一个model对象的时候是不会报错的!!
choice
一个由多个2元组,组成的可迭代对象(如tuple、list)。
如果设置了该选项值,那么默认的表单组件将变为一个select box,而不是标准是text field,且将被限制从给定choice中选择choice。
choice 列表,形如以下:
YEAR_IN_SCHOOL_CHOICES = (
(“FR”, “Freshman”),
(“SO”, “Sophomore”),
(“JR”, “Junior”),
(“SR”, “Senior”),
(“GR”, “Graduate”),)
每个元组中第一个元素,将被存储在数据库中,第二个元素用于默认表单组件展示
例:
from django.db import models
class Person(models.Model):
SHIRT_SIZES = (
(“S”, “Small”),
(“M”, “Medium”),
(“L”, “Large”),
)
name = models.CharField(max_length=60)
shirt_size = models.CharField(max_length=1, choices=SHIRT_SIZES)
>>> p = Person(name=”Fred Flintstone”, shirt_size=”L”)
>>> p.save()
>>> p.shirt_size
“L”
>>> p.get_shirt_size_display()
“Large”
default
设置field的默认值。可以是可调用对象,也可以是某个值。如果是可调用对象,每次创建对象,都会被调用
help_text
同表单组件一起展示的帮助说明
primary_key
如果设置primary_key=True,那么该field将是model的主键
主键Field只读。如果修改某个已存在对象,主键列的值,并保存该对象,会在旧对象的基础上,重新构建一个对象。
例:
from django.db import models
class Fruit(models.Model):
name = models.CharField(max_length=100, primary_key=True)
>>> fruit = Fruit.objects.create(name=”Apple”)
>>> fruit.name = “Pear”
>>> fruit.save()
>>> Fruit.objects.values_list(“name”, flat=True)
<QuerySet [“Apple”, “Pear”]>
unique
如果设置unique=True,则该field不允许有重复值。
参考链接:
https://docs.djangoproject.com/en/1.11/topics/db/models/#field-options
关联关系
外键关联
假设artist model对应mysql表为 myapp_album, Musician model对应的mysql表为Musician表为myapp_musician,则以下field定义,会使两个mysql表建立外键关联关系。myapp_album.artist列引用mapp_musician.auto_id字段的值,即mapp_musician.auto_id为myapp_album表的外键。
class Album(models.Model):
artist = models.ForeignKey(Musician, to_field=“auto_id”, on_delete=models.PROTECT)
为方便理解,如上,暂时把Album、Musician Model称之为表,对应Model对象称之为表记录,存在外键关联的两个表,分别称之为参照表(如上的Album),被参照表(如上的Musician)
假设Musician代码位于 Album代码之前,那么执行以上代码时将报错,因为那会还没有定义Musician,如果不调整代码顺序,即定义表的先后顺序,那怎么办呢?
解决方案:把关联表写成字符串形式,如下:
class Album(models.Model):
artist = models.ForeignKey(“Musician”, to_field=“auto_id”, on_delete=models.PROTECT)
自身关联
假设有表appame_resource,结构如下,其中parent的值如果不为NULL则为某条记录的id值
id name parent
1 xxx1 NULL
2 xxx2 1
这种情况则需要进行自身表关联设计,model设计如下:
class Resource(models.Model):
id = models.AutoField(primary_key=True, verbose_name=“资源ID”)
parent = models.ForeignKey(“self”, to_field=“id”, null=True, blank=True, on_delete=models.CASCADE)
name = models.CharField(max_length=20, verbose_name=“资源名称“)
null参数值说明:该值默认为False,设置为True则表示允许字段为null,空值将被存储为NULL
blank参数值说明:该值默认为False,设置为True则表示允许字段为空值
on_delete参数值说明:
2.0版本,该参数值必填,更早之前的版本则默认为CASCADE。
可选值:
CASCADE
级联删除。模拟sql约束 ON DELETE CASCADE。删除被参照表的某条表记录,同时级联删除参照表中,同待删除记录存在外键关联关系的记录。
PROTECT
删除被参照表中的某条表记录,如果参照表中,存在与该记录有外键关系的记录,则不让删除。
SET_NULL
删除被参照表的某条表记录,设置参照表中,同待删除记录存在外键关联的记录的外键列值为null。当且仅当设置了null=True选项时可用。
SET_DEFAULT
删除被参照表的某条表记录,设置参照表中,同待删除记录存在外键关联的记录的外键列值为默认值。必须为外键列设置默认值。
SET()
删除被参照表的某条表记录,设置参照表中,同待删除记录存在外键关联关系的记录的外键列值为传递给SET()的参数值,如果传递给SET()的参数值是可调用对象,则设置为调用可调用对象获取的结果。
官方例子:
from django.conf import settings
from django.contrib.auth import get_user_model
from django.db import models
def get_sentinel_user():
return get_user_model().objects.get_or_create(username=”deleted”)[0]
class MyModel(models.Model):
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.SET(get_sentinel_user),
)
DO_NOTHING
删除被参照表的某条表记录,不对参照表中同待删除记录存在外键关联的记录做任何处理。
参考链接:
https://docs.djangoproject.com/en/1.11/ref/models/fields/#foreignkey
参考链接:
https://docs.djangoproject.com/en/1.11/topics/db/models/#relationships
联合主键
例子:如下,希望project_id和user_id字段组合唯一
class APIProjectFacorites(models.Model):
id = models.AutoField(primary_key=True, verbose_name=“自增id”)
project_id = models.CharField(blank=True, null=True, max_length=300, verbose_name=“项目id“)
user_id = models.CharField(blank=True, null=True, max_length=15, verbose_name=“用户id“)
class Meta:
db_table = “tb_api_project_facorities”
unique_together = (“project_id”, “user_id”)
verbose_name = “API项目收藏表“
verbose_name_plural = verbose_name
组织models
1、如果manager.py 启动app,会创建包含一个models.py的文件。如果有许多model,可以按单个文件的方式组织model。新建models包来管理,具体方法如下:
然后移除models.py,并创建一个myapp/models目录,在该目录下新建__init__.py文件,用于存放models。
例:
假设在models目录下存在models文件,organic.py 和synthetic.py,编辑myapp/models/__init__.py,新增以下内容:
from .organic import Person
from .synthetic import Robot
参考链接:
https://docs.djangoproject.com/en/1.11/topics/db/models/
https://docs.djangoproject.com/en/1.11/