模型基础
模型是关于数据的唯一的、确定的信息源。它包含您正在存储的数据的基本字段和行为。通常,每个模型映射到一个数据库表。
基础:
- 模型是一个继承django.db.models.Model的class类
- 每个属性对应一个数据库字段
- django提供了一个自动生成的数据库访问API
例子:
from django.db import models
class Person(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
生成数据库文件
CREATE TABLE myapp_person (
"id" serial NOT NULL PRIMARY KEY,
"first_name" varchar(30) NOT NULL,
"last_name" varchar(30) NOT NULL
);
注:table名是django自动添加的(可自定义) id是django自动添加的(可自定义) SQL语句是django自动生成的,可针对不同的数据库进行迁移
当迁移models时,需要在INSTALLED_APPS中注册当前app
迁移指令:
python manage.py makemigrations myAPP
python manage.py sqlmigrate myAPP
python manage.py migrate
Filed
模型最重要的部分就是字段,避免字段名字与models API名相同
Filed Types
每个字段都必须是Field类的实例,Django使用filed类来描述一些信息:
- column type 告诉数据库数据的类型(int,varchar,text...)
- widget 自动生成的form表单类型(<input type="text">)
- 由Django管理和自动生成表单的验证需求
内置Filed Types
AutoField 主键,不指定主键django将自动添加一个名为id的主键。
BigAutoField 主键 biginteger
BinaryField 二进制类型
默认情况下,BinaryField的editable属性为False,不允许包含在ModelForm中
慎用,此字段不能代替真正的文件处理
BooleanField 布尔类型
widget默认为CheckboxInput,如果null=True则为NullBolleanSelect
如果Field.default没有指定,BooleanField默认值为None
CharField string类型
如果数据量很大,使用TextFiled
widget默认为TextInput
DateField datetime.date类型
auto_now属性,设置为True时执行model.save自动更新此字段为当前时间,且修改此字段值将无效
auto_now_add属性,设置为True时执行model.add自动添加此字段为当前时间,且修改此字段值将无效
如果你只想修改这个字段,使用defalut=tdate.today,它将datetime.date.today()赋值给此字段,且支持修改。对于DateTimeField类型,使用default=timezone.noe,它将django.utils.timezone.now()赋值给此字段。
auto_now_add, auto_now, default是独有的,不能混合使用
auto_now or auto_now_add to True将导致 editable=False and blank=True
auto_now和auto_now_add选项在创建或更新时总是使用默认时区中的日期
DateTimeField datetime.datetime类型
与DateField类似
DecimalField Decimal类型
max_digits属性 最大位数
decimal_places属性 小数位数
最大位数-小数位数=最大整数位数
DurationField 时间间隔字段
在大多数情况下,使用DurationField算法是可行的。然而,在除PostgreSQL之外的所有数据库上,将DurationField的值与DateTimeField实例上的算术值进行比较将无法正常工作
EmailField email类型
FileField 文件上传类型
upload_to属性 设置文件上传的路径
upload = models.FileField(upload_to='uploads/')
upload = models.FileField(upload_to='uploads/%Y/%m/%d/')
使用 FileField,需要对settings.py做如下配置
# 与用户上传相关的配置
MEDIA_URL="/media/" # 访问路径
MEDIA_ROOT=os.path.join(BASE_DIR,"media") # 保存路径
upload_to也可以是一个方法
def user_directory_path(instance, filename):
# file will be uploaded to MEDIA_ROOT/user_<id>/<filename>
return 'user_{0}/{1}'.format(instance.user.id, filename)
class MyModel(models.Model):
upload = models.FileField(upload_to=user_directory_path)
当访问FileField时,会得到一个FieldFile实例,作为访问底层文件的代理。
FilePathField 文件路径类型
当你只想保存已存在的文件路径而不是获取用户上传的文件时使用此字段,不使用FileField
class FilePathField(path=None, match=None, recursive=False, max_length=100, **options)
一个CharField,其选择仅限于文件系统上某个目录中的文件名。有三个特殊的参数,第一个是必须的
path:文件路径,最好配置在settings.py中
match:文件名正则匹配表达式
recursive:指定是否应包括路径的所有子目录
allow_files:指定是否应包括指定位置中的文件 必须是True
allow_folders:指定是否包含指定位置的文件夹 必须是True
FloatField 浮点类型
将被解析成python Float类型
ImageField 图片类型
继承了FileField类,将验证是否为图片
height_field属性:文件save时将被保存成此字段高
width_field属性:文件save时将被保存成此字段宽
IntegerField 整数类型
保存int类型
GenericIPAddressField IP类型
IPv4 or IPv6地址,默认widget是TextInput
protocol属性:value in('both'(default) 'IPv4' 'IPv6')
unpack_ipv4属性:解包IPv4映射地址,比如::ffff:192.0.2.1。如果启用此选项,该地址将解压缩到192.0.2.1。默认是禁用的。只能在协议设置为'both'时使用。
NullBooleanField 布尔类型
与 BooleanField with null=True效果一样
PositiveIntegerField 正整数类型
与 IntegerField类似,只能保存正整数
PositiveSmallIntegerField 正整数类型
与 PositiveIntegerField类似,范围:0 to 32767
SlugField 限定string类型
slug是对某物的缩写,仅包含字母、数字、下划线或连字符。它们通常用于url中。
allow_unicode:设置为True时,除了ASCII还可以使用unicode字符,默认为False
SmallIntegerField 整数类型
与 IntegerField类似,范围:-32768 to 32767
TextField 文本类型
large text filed
TimeField 时间类型
datetime.time
URLField
A CharField for a URL, validated by URLValidator
The default form widget for this field is a TextInput.
UUIDField UUID类型
import uuid
from django.db import models
class MyUUIDModel(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
# other fields
Relationship fields
Django还定义了一组表示关系的字段
ForeignKey 外键类型
在多对一关系使用它
from django.db import models
class Car(models.Model):
manufacturer = models.ForeignKey(
'Manufacturer',
on_delete=models.CASCADE,
)
# ...
class Manufacturer(models.Model):
# ...
pass
#ForeignKey与抽象类
from django.db import models
class AbstractCar(models.Model):
manufacturer = models.ForeignKey('Manufacturer', on_delete=models.CASCADE)
class Meta:
abstract = True
from django.db import models
from products.models import AbstractCar
class Manufacturer(models.Model):
pass
class Car(AbstractCar):
pass
on_delete属性:指向的表数据删除时如果操作此字段
limit_choices_to属性:限制指向表数据的字段值
staff_member = models.ForeignKey(
User,
on_delete=models.CASCADE,
limit_choices_to={'is_staff': True}, # 只有User表中的is_staff属性为True的才可以赋值给此字段
)
# limit_choices_to可以指定给一个函数
def limit_pub_date_choices():
return {'pub_date__lte': datetime.date.utcnow()}
limit_choices_to = limit_pub_date_choices
related_name属性:从相关对象返回到此对象的关系使用的名称。请参阅相关对象文档。注意,在定义抽象模型上的关系时,必须设置此值;当你这样做的时候,一些特殊的语法是可用的。
如果您希望Django不要创建反向关系,可以将related_name设置为'+'或以'+'结束它。默认为 表名_set
related_query_name属性:用于目标模型中反向筛选器名称的名称。
# Declare the ForeignKey with related_query_name
class Tag(models.Model):
article = models.ForeignKey(
Article,
on_delete=models.CASCADE,
related_name="tags",
related_query_name="tag",
)
name = models.CharField(max_length=255)
# That's now the name of the reverse filter
article_obj = Article.objects.filter(tag__name="important")
article_obj.tags.all()
to属性:关系所在的对象
to_field属性:关系所在的相关对象上的字段。默认情况下,Django使用相关对象的主键。如果引用不同的字段,则该字段必须具有惟一=True。
db_constraint属性:控制是否应该在数据库中为该外键创建约束。默认为真,这几乎肯定是你想要的;将此设置为False可能对数据完整性非常不利。
swappable属性:如果这个ForeignKey指向一个可切换的模型,则控制迁移框架的反应。如果它是True(默认值),那么如果ForeignKey指向的模型与设置的当前值匹配。AUTH_USER_MODEL(或另一个可切换模型设置)关系将使用对该设置的引用而不是直接对模型的引用存储在迁移中。
如果您确信您的模型应该始终指向被签入的模型——例如,如果它是专门为您的自定义用户模型设计的配置文件模型,那么您只希望将其重写为False。
将它设置为False并不意味着你可以引用一个可切换模型即使是换出——假只是意味着迁移用此ForeignKey总是参考的模型指定(这将会失败如果用户试图运行一个用户模型你不支持,例如)。
如果有疑问,让它默认为True
ManyToManyField
多对多关系
limit_choices_to在ManyToManyField上使用使用through参数指定的自定义中间表时没有任何效果
through属性:Django将自动生成一个表来管理多对多关系。但是,如果要手动指定中间表,可以使用through选项指定Django模型,该模型表示要使用的中间表。
through_fields属性:指定through的表后,需要声明表中关联的字段
tags = models.ManyToManyField(
to="Tag",
through='Article2Tag',
through_fields=('article', 'tag'),
)
class Article2Tag(models.Model):
nid = models.AutoField(primary_key=True)
article = models.ForeignKey(verbose_name='文章', to="Article", to_field='nid', on_delete=models.CASCADE)
tag = models.ForeignKey(verbose_name='标签', to="Tag", to_field='nid', on_delete=models.CASCADE)
db_table属性:django自动生成关系表的名称,不指定此值将有一个默认值
OneToOneField
一对一关系
related_name属性:如果不为OneToOneField指定related_name参数,Django将使用当前模型的小写名称作为默认值。