参考:
https://www.cnblogs.com/wupeiqi/articles/6216618.html
一.书籍-作者-出版社数据库结构:
作者模型:作者有1个姓名
作者详细模型:把作者的详情放到详情表,包含性别/email地址/出生日期
和作者模型之间是one-to-one;也可以和作者模型和成1张表
出版商模型:出版商有名称/地址/所在城市/省/国家/网站
书籍模型:书籍有书名/出版日期,1本书可能有多个作者,反之亦然,1本书只应该由1家出版商出版,所以出版商和书籍是one-to-many(外键)
1.表的创建:
ORM中创建表实际上就是创建类;创建记录实际上就是实例化类,生成对象
#实例:
from django.db import models<br>
class Publisher(models.Model):#继承models.Model对象
name=models.CharField(max_length=30,verbose_name="名称")#varchar类型
address=models.CharField("地址",max_length=50)
city=models.CharField('城市',max_length=60)
state_province=models.CharField(max_length=30)
country=models.CharField(max_length=50)
website=models.URLField()
class Meta:
verbose_name='出版商'
verbose_name_plural=verbose_name
def __str__(self):#打印实例对象时显式其name属性
return self.name
class Author(models.Model):
name=models.CharField(max_length=30)
def __str__(self):
return self.name
class AuthorDetail(models.Model):
sex=models.BooleanField(max_length=1,choices=((0,'男'),(1,'女'),))
email=models.EmailField()
address=models.CharField(max_length=50)
birthday=models.DateField()
author=models.OneToOneField(Author)#一对一的外键
class Book(models.Model):
title=models.CharField(max_length=100)
authors=models.ManyToManyField(Author)#多对多的外键
publisher=models.ForeignKey(Publisher)
publication_date=models.DateField()#date类型
price=models.DecimalField(max_digits=5,decimal_places=2,default=10)#decimal类型
def __str__(self):
return self.title
#然后在Pycharm的终端中执行:
python manage.py makemigrations
#在应用文件夹下的migrations文件夹中创建了1个0001_initial.py
#0001_initial.py中生成了了以上代码中创建的类
#然后在Pycharm的终端中执行:
python manage.py migrate
#创建了表(除了以上各表,还有默认的表)
#注意:
1.先在settings里的INSTALLED_APPS中加入'app01',然后同步数据库
2.models.ForeignKey("Publish") & models.ForeignKey(Publish)
3.在1张表中如果没有主键,会自动创建id字段并设为主键
4.对字段的大小写不敏感
2.说明:
1.每个数据模型都是django.db.models.Model的子类
其父类Model包含了所有必要的和数据库交互的方法,并提供了简介漂亮的定义数据库字段的语法
2.每个模型(类)相当于单个数据库表(多对多关系例外,会多生成1张关系表)
每个属性也是这个表中的字段,属性名就是字段名,属性的类型(如CharField)相当于数据库的字段类型(如varchar)
二.字段参数
1.常用字段类型:
全部在models下面,即models.<field_type>()
通过Django Admin及ModelForm验证合法性
所有参数均为关键字参数
##############################################################################
AutoField(Field):添加记录时会自动增长的IntegerField
#相当于MySQL中的Auto Increment
#通常不需要直接使用这个字段的数据
#自定义1个主键:如果不指定主键,系统会自动添加1个名为id的主键字段
my_id=models.AutoField(primary_key=True)#该字段类型必须被指定为主键
##############################################################################
BinaryField(Field):二进制类型字段
##############################################################################
BigAutoField(AutoField):Bigint自增字段(和AutoField的区别在于存储的范围更大)
#该字段类型必须被指定为主键
##############################################################################
BigIntegerField(IntegerField):长整型字段
范围为[-9223372036854775808,9223372036854775807]
##############################################################################
BooleanField(Field):布尔值字段
#admin用1个checkbox来表示此类字段的数据
##############################################################################
CharField(CharField):字符字段,用于较短的字符串
#参数说明:
max_length:从数据库层和Django校验层限制该字段的最大字符数
#为int;必选
##############################################################################
CommaSeparatedIntegerField(CharField):用逗号分隔的整数值字段
#类似于CharField
#参数说明:必选
maxlength:字段的最大字符数
##############################################################################
DateField(DateTimeCheckMixin,Field):日期字段
格式:YYYY-MM-DD
#参数说明:均可选
Argument:描述
auto_now:对象被保存时,自动将该字段的值设为当前时间
#通常用于表示"last-modified"时间戳
auto_now_add:对象首次被创建时,自动将该字段的值设为当前时间
#通常用于表示对象创建时间
#仅在admin中有意义...
##############################################################################
DateTimeField(DateField):日期时间字段,类似 DateField,支持同样的附加选项
格式:YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]
##############################################################################
DecimalField(Field):10进制小数字段(没有误差)
#实际是把num当成str来存储
#参数说明:
max_digits:总位数
decimal_places:小数点后位数
##############################################################################
DurationField(Field):时间间隔字段
在数据库中按Bigint存储,在ORM中获取的值为datetime.timedelta类型
##############################################################################
EmailField(CharField):带有检查Email合法性的CharField
#不接受maxlength参数
##############################################################################
FileField(Field):文件上传字段
#admin用1个<input type="file">部件表示该字段保存的数据(1个文件上传部件)
#参数说明:必选
upload_to:用于保存上载文件的本地文件系统路径
#这个路径必须包含strftime #formatting,该格式将被上载文件的date/time替换(so that uploaded files don't fill up the given directory)
storage:存储组件;默认django.core.files.storage.FileSystemStorage
#注意:在model中使用FileField/ImageField需要以下步骤:
1.在settings.py中定义1个完整路径给MEDIA_ROOT以便让 Django在此处保存上传文件
#出于性能考虑,这些文件并不保存到数据库
#定义MEDIA_URL作为该目录的公共URL,要确保该目录对WEB服务器用户帐号是可写的
2.在model中添加FileField/ImageField
并确保定义了upload_to 选项,以告诉Django使用MEDIA_ROOT的哪个子目录保存上传文件
#数据库中要保存的只是文件的路径(相对于MEDIA_ROOT)
#出于习惯你一定想使用Django提供的get_<#fieldname>_url函数
#举例来说,如果你的ImageField叫作mug_shot,你就可以在模板中以{{ object.#get_mug_shot_url }}的方式得到图像的绝对路径
##############################################################################
FilePathField(Field):文件系统中某个特定目录下的文件
#参数说明:path必选,其余可选
path:文件的系统绝对路径,如:"/home/images";用于得到文件
match:1个正则表达式;为str;用于过滤文件名
#如:match="foo.*\.txt^",将匹配文件foo23.txt而不匹配bar.txt/foo23.gif
#注意:该参数仅应用到base filename而非路径全名
#如:FilePathField(path="/home/images",match="foo.*",recursive=True)
#会匹配 /home/images/foo.gif而不匹配/home/images/foo/bar.gif
recursive:是否包括path下的全部子目录;为bool;默认为False
allow_files:是否允许文件;默认为True
allow_folders:是否允许文件夹;默认为False
##############################################################################
FloatField(Field):浮点数字段(可能存在误差)
#admin用1个文本框(<input type="text">)表示该字段的数据
#参数说明:
max_digits:总位数(不包括小数点和符号)
decimal_places:小数位数
#实例:
#保存最大值为999(小数点后保留2位)的浮点数:
models.FloatField(max_digits=5,decimal_places=2)
#保存最大值为一百万(小数点后保存10位):
models.FloatField(max_digits=19,decimal_places=10)
##############################################################################
GenericIPAddressField(Field):可支持IPv4和IPv6的IPAddressField
#参数说明:均可选
protocol:指定支持IPv4还是Ipv6;可为"both"(默认值)/"ipv4"/"ipv6"
unpack_ipv4:如为True,则输入::ffff:192.0.2.1时,可解析为192.0.2.1;默认为False
#开启此功能需要protocol="both"
##############################################################################
ImageField(FileField):类似FileField,不过要校验上传对象是否是合法图片
#路径保存在数据库,文件上传到指定目录
#参数说明:均可选
upload_to:文件的保存路径
storage:存储组件;默认django.core.files.storage.FileSystemStorage
height_field:指定图片保存的高度规格
width_field:指定图片保存的宽度规格
##############################################################################
IntegerField(Field):整数字段
范围为[-2147483648,2147483647]
##############################################################################
IPAddressField(Field):str形式的IP地址字段,仅支持IPv4
#如:"24.124.1.30"
##############################################################################
NullBooleanField(Field):类似BooleanField,不过允许NULL作为其中的选项
#推荐使用这个字段而不要用BooleanField并设置null=True
#admin用1个选择框<select>(3个可选择的值:"Unknown"/"Yes"/"No")来表示该种类型
##############################################################################
PositiveIntegerField(PositiveIntegerRelDbTypeMixin,,IntegerField):正整数字段
范围为[0,2147483647]
##############################################################################
PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin,IntegerField):正小整数字段
范围为[0,32767]
##############################################################################
SlugField(CharField):短签字段,即只包含字母/数字/下划线(_)/减号(-),通常用于URLs
#参数说明:
max_length:字段的最大字符数;默认为50
#在旧版本中无法更改默认值
##############################################################################
SmallIntegerField(IntegerField):小整数字段
范围为[-32768,32767]
##############################################################################
TextField(Field):文本字段,用于长文本
#admin用1个文本区域(<textarea>)来表示该字段的数据
#文本区域是1个多行编辑框
##############################################################################
TimeField(DateTimeCheckMixin,Field):时间字段
格式:HH:MM[:ss[.uuuuuu]]
##############################################################################
URLField(CharField):URL字段
#admin用1个<input type="text">文本框表示该字段保存的数据(1个单行编辑框)
#参数说明:
verify_exists:若为True(默认),给定的URL会预先检查是否存在( 即URL是否被有效装入且没有返回404响应)
##############################################################################
UUIDField(Field):UUID字段
##############################################################################
XMLField:用于校验值是否为合法XML的TextField
#参数说明:必选
schema_path:用来校验文本的RelaxNG schema的文件系统路径
向表中添加字段时表中可能已经有记录,会提示设置默认值还是取消本次操作
2.主要字段共用参数:
- 这些参数可以用于任何字段类型
- 均为关键字参数
blank:在Admin中是否允许用户输入空值;为bool
##############################################################################
choices:选择框中的选项
为1个2维tuple构成的tuple;第1个值是实际存储的值,第2个用来进行选择
#把不变的数据放在内存中从而避免跨表操作
如:SEX_CHOICES=(('F','Female'),('M','Male'),)
gender=models.CharField(max_length=2,choices=SEX_CHOICES)
##############################################################################
db_column:数据库中的字段名;为str;默认和Model中相同
##############################################################################
db_index:是否在数据库中为该字段建立索引;为bool
#索引其实是存储在另1个文件中的二叉树,可以加速查找
##############################################################################
default:字段的默认值
##############################################################################
editable:在Admin中是否允许编辑;为bool;默认为True
##############################################################################
error_messages:自定义的错误信息(用于定制显示的错误信息);为dict
字典的健可为:null/blank/invalid/invalid_choice/unique/unique_for_date
如:{"null":"不能为空.","invalid":"格式错误"}
##############################################################################
help_text:在Admin中该字段的提示信息;为str
##############################################################################
null:在数据库中字段是否可为空;为bool;默认为True
##############################################################################
primary_key:是否为主键;为bool
如果没有设置django创建表时会自动加上:
id=meta.AutoField('ID',primary_key=True)
primary_key=True implies blank=False,null=False and unique=True.
Only one primary key is allowed on an object.
#也是1种特殊的索引,可以加速查找+限制字段值唯一且非空
##############################################################################
unique:是否在数据库中为该字段建立唯一索引;为bool
OneToOneField=Foreign Key+唯一索引
##############################################################################
unique_for_date:是否在数据库中为该字段[日]部分建立唯一索引;为bool
#除了可以加速查找,还可以约束字段中的值唯一
##############################################################################
unique_for_month:是否在数据库中为该字段[月]部分建立唯一索引;为bool
##############################################################################
unique_for_year:是否在数据库中为该字段[年]部分建立唯一索引;为bool
##############################################################################
validators:自定义错误验证(用于定制验证规则);为list
#需要:
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'
),
]
##############################################################################
verbose_name:Admin中显示的字段名称;为str
3.Model中字段类型在MySQL中的属性:
'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)',
4.自定义无符号的整数字段:
class UnsignedIntegerField(models.IntegerField):
def db_type(self,connection):
return 'integer UNSIGNED'
#注意:返回值为字段在数据库中的属性
三.其他相关事项
1.原生SQL:
Raw SQL(原生SQL):
Django中Models的操作,也是调用了ORM框架来实现的,PyMySQL或MySQLdb
所以也可以使用原生SQL语句来操作数据库
#每次创建1个对象,想显示对应的原生SQL语句(Raw SQL)
#需要在settings.py中加上日志记录(LOGGING)部分:
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console':{
'level':'DEBUG',
'class':'logging.StreamHandler',
},
},
'loggers': {
'django.db.backends': {
'handlers': ['console'],
'propagate': True,
'level':'DEBUG',
},
}
}
2.元信息:
更多属性参见:https://www.cnblogs.com/flash55/p/6265405.html
class Info(models.Model):
nid=models.AutoField(primary_key=True)
name=models.CharField(max_length=32)
date=models.DateField()
pub=models.CharField(max_length=32)
writer=models.CharField(max_length=16)
class Meta:
#当前类是不是1个抽象类:
#抽象类不对应表:一般用来归纳公共属性字段,然后继承它的子类可以继承这些字段
abstract=False
#数据库中生成的表名:
#默认为:<应用名>_<类名>
db_table="table_name"
#联合索引:
index_together=[
("date","name"),
]
#联合唯一索引:
#ManyToManyField就在多对多关系中的第3张表中使用了本约束
#以防止2个表中相同字段重复建立关联
unique_together=(
("pub","writer"),
)
#admin中显示的表名称:
verbose_name="BookInfo"
3.关于验证和错误提示:
1.触发错误提示:
a.在Admin中优先显示Admin内的ModelForm的错误信息,然后才是Model字段的错误信息
b.调用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()是1个钩子函数,可用于定制操作,如:上述的异常处理
##############################################################################
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 help text.',}
error_messages={'name':{'max_length':"The name is too long"}}
widgets={'name':Textarea(attrs={'cols':80,'rows':20})}
class UserInfoAdmin(admin.ModelAdmin):
form=UserInfoForm
admin.site.register(models.UserInfo, UserInfoAdmin)