定义模型
在django中,所有的模型必须继承from django.db.models import Mode这个类,字段类型需要使用models模块中定义好的字段类型
from django.db.models import Model
# Create your models here.
class PhoneField(models.Field): # 自定义的char类型的字段类
def __init__(self, max_length, *args, **kwargs):
self.max_length = max_length
super(PhoneField, self).__init__(max_length=max_length, *args, **kwargs)
def db_type(self, connection): # 限定生成数据库表的字段类型为char,长度为max_length指定的值的字符串
return 'char(%s)' % self.max_length
class Student(models.Model):
s_name = models.CharField(max_length=64,help_text="学生姓名")
s_sex = models.IntegerField(choices=((0,'男'),(1,'女')), help_text="性别")
s_phone = PhoneField(max_length=11,help_text="手机号")
# auto_now_add=True 在每一次数据被添加进去的时候,记录当前时间
create_time = models.DateTimeField(auto_now_add=True)
# auto_now=True 在每一次数据被保存的时候,记录当前时间
update_time = models.DateTimeField(auto_now=True)
class Meta:
db_table='student' # 指定表名
模型中常用属性
django提供的一些特殊属性
EmailField(CharField):
- 字符串类型,Django Admin以及ModelForm中提供验证机制
- e_mail = models.EmailField(max_length=255, unique=True)
IPAddressField(Field)
- 字符串类型,Django Admin以及ModelForm中提供验证 IPV4 机制
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"
URLField(CharField)
- 字符串类型,Django Admin以及ModelForm中提供验证 URL
SlugField(CharField)
- 字符串类型,Django Admin以及ModelForm中提供验证支持 字母、数字、下划线、连接符(减号)
CommaSeparatedIntegerField(CharField)
- 字符串类型,格式必须为逗号分割的数字
UUIDField(Field)
- 字符串类型,Django Admin以及ModelForm中提供对UUID格式的验证
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 上传图片的宽度保存的数据库字段名(字符串)
自定义字段
示例:我们发现上边没有固定长度的字符串类型,但是手机号字段一般都是定长11位的字符串,所以我们需要自定义一些字段类型
from django.db import models
# Create your models here.
class PhoneField(models.Field): # 自定义的char类型的字段类
def __init__(self, max_length, *args, **kwargs):
self.max_length = max_length
super(PhoneField, self).__init__(max_length=max_length, *args, **kwargs)
def db_type(self, connection): # 限定生成数据库表的字段类型为char,长度为max_length指定的值的字符串
return 'char(%s)' % self.max_length
Field的常用参数:
模型中Meta配置:
对于一些模型级别的配置。我们可以在模型中定义一个类,叫做Meta。然后在这个类中添加一些类属性来控制模型的作用。比如我们想要在数据库映射的时候使用自己指定的表名,而不是使用模型的名称。那么我们可以在Meta类中添加一个db_table的属性。示例代码如下:
class Book(models.Model):
name = models.CharField(max_length=20,null=False)
desc = models.CharField(max_length=100,name='description',db_column="description1")
class Meta:
db_table = 'book_model'
以下将对Meta类中的一些常用配置进行解释。
官方文档:https://docs.djangoproject.com/en/2.0/ref/models/options/
ORM模型迁移
生成迁移脚本
python manage.py makemigrations
执行迁移标本,数据库中创建新表
python manage.py migrate
根据已有的表自动生成模型:
python manage.py inspectdb
在实际开发中,有些时候可能数据库已经存在了。如果我们用Django来开发一个网站,读取的是之前已经存在的数据库中的数据。那么该如何将模型与数据库中的表映射呢?根据旧的数据库生成对应的ORM模型,需要以下几个步骤:
1.Django给我们提供了一个inspectdb的命令,可以非常方便的将已经存在的表,自动的生成模型。想要使用inspectdb自动将表生成模型。首先需要在settings.py中配置好数据库相关信息。
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': "migrations_demo",
'HOST': '127.0.0.1',
'PORT': '3306',
'USER': 'root',
'PASSWORD': 'root'
}
}
通过python manage.py inspectdb,就会将表转换为模型后的代码,显示在终端,如果想要保存到文件中。那么可以使用>重定向输出到指定的文件。比如让他输出到models.py文件中。示例命令如下:
python manage.py inspectdb > models.py
如果只是想要转换一个表为模型。那么可以指定表的名字。示例命令如下:
python manage.py inspectdb article_article > models.py
abstract 创建公共模型父类
在创建模型的时候,其实有好多字段都是模型中共同存在的,例如createtime,updatetime,mark等等,这些字段我们需要在每个模型中重复创建,这就造成了工作量的浪费,我们可以通过创建一个公共的模型父类来,子类集成该父类,这样我们就不需要重复写这些字段了
class PublicModel(models.Model):
createtime = models.DateTimeField(auto_now_add=True,verbose_name="创建日期")
update = models.DateTimeField(auto_now=True,verbose_name = '修改日期')
status = models.IntegerField(verbose_name = '状态')
class Meta:
abstract=True # 父类中必须指定该属性,否则该类会被创建到数据库
# 子类继承PublicModel类,就不需要重复写createtime,update,status三个字段的定义了
class Student(PublicModel):
s_name = models.CharField('学生姓名', max_length=64, null=False, help_text='学生姓名')
s_sex = models.CharField("性别", max_length=1, choices=(
(0, '男'),
(1, '女')
), help_text='性别:0-男;1-女')
s_age = models.PositiveIntegerField('年龄', null=False, default=0, help_text='年龄')
s_dept = models.CharField("专业", max_length=64, null=False, help_text="专业")
si_id = models.OneToOneField(to='StudentInfo', to_field="id", on_delete=models.CASCADE, db_column='si_id',
related_name="stu_stu_info")
course = models.ManyToManyField(to="Course", db_table="stu_course", related_name="course_student")
class Meta:
db_table = 'student'