from django.db import models class ModelName(models.Model): field1 = models.xxField(……) field2 = models.xxField(……) class Meta: db_table = …… other_metas = ……
解析:
Meta类的属性由Django预定义,常用的Meta类属性如下:
abstract: True or False 标识本类是否为抽象基类
app_label: 定义本类所属的应用,比如app_lable='app'
db_table: 映射的数据表名,比如db_table='moments'
如果Meta中不提供db_table字段,则Django会为模型自动生成数据表名,生成的格式为"应用名_模型名"
db_tablespace: 映射的表空间名称。表空间的概念只在某些数据库如Oracle中存在,不存在表空间概念的数据库将忽略本字段
default_related_name: 定义本模型的反向关系引用名称,默认与模型名一致。
get_latest_by: 定义按那个字段值进行排列以获得模型的开始或结束的记录,本属性通常指向一个日期或整型的模型字段
managed: True or False ,定义Django的manage.py 命令行工具是否管理本模型。本属性默认为True,如果将其设为False,则运行python manage.py migrate时不会在数据库中生成本模型的数据表,所以需要手工维护数据库的定义
order_with_resect_to: 定义本模型可以按照某外检引用的关系排序
ordering: 本模型记录的默认排序字段,可以设置多个字段,默认以升序排列,如果以降序排列则需要再字段名钱加"负号",比如
pythonclass Meta:
ordering=['user_name','-pub_date']
pythonclass Meta:
unique_together = (("user_name","pub_date"))
# 上述意识是定义每个user_name在同一个pub_date中只能有一条数据表记录。
class Meta: index_together = [["pub_date","deadline"],]
普通字段是指模型类中除外键关系外的数据字段属性,所有数据字段的属性必须集成自抽象类django.db.models.Field,开发者可以定义自己的继承自该类的字段类型。
字段类型 | 说明 |
---|---|
AutoField | 一个自动递增的整型字段,添加记录时他会自动增长。通常只用于充当数据表的主键,如果没有,django会自动添加一个 |
BigIntegreField | 64位整型字段 |
BinaryField | 二进制数据字段,只能通过bytes对其进行赋值 |
BooleanField | 布尔字段,相对应的Html标签是 |
CharField | 字符串字段,用于较短的字符串,相对应的Html标签是单行输入框 input type="text">" |
TextField | 大容量文本字段,相对应的HTML标签是多行编辑框 textarea>" |
CommaSeparatedIntegerField | 用于存放分号分割的整数值,相对于普通的CharField,它有特殊的表单数据验证要求 |
DateField | 日期字段,相对应的HTML标签是 input type="text">、一个JavaScript日历和一个"Today"快捷键。有以下额外的可选参数,当对象被保存时,将该字段的指设置为当前时间,当对象首次被创建时,将该字段的值设置为当前时间 |
DateTimeField | 类似于DateField,同时支持时间的输入 |
DurationField | 存储时间周期,用python的timedelta类型构建 |
EmailField | 一个带有检查的Email合法性的CharField |
FileField | 一个文件上传字段。在定义本字段时必须传入参数upload_to,用户保存上载文件的服务器文件系统的路径。这个路径必须包含strftime formatting,该格式将被上载的文件date/time替换 |
FilePathField | 按目录限制规则选择文件,定义本字段时必须传入参数path |
FloatFiled | 浮点型字段,定义本字段时必须传入参数max_digits和decimal_places,用以定义总位数(不包括小数点和符号)和小整位数 |
ImageField | 类似FileField,同时验证上传对象是否是一个合法图片。他有两个可选参数,即height_field和width_field,如果提供这两个参数,则图片将按照提供的高度和宽度保存,该字段要求安装Python Imaging |
IntegerField | 用于保存一个整数 |
IPAddressField | 一个字符串形式的IP地址 |
NullBooleanField | 类似于BooleanField,但比其多一个None选项 |
PhoneNumberField | 带有美国风格的电话号码校验 |
PositiveIntegerField | 只能输入非负数的IntegerField |
SlugField | 只包含字母、数字、下划线和连字符的输入字段,它通常用于URL |
SmallIntegerField | 类似于IntegerField,但只具有较小的输入范围,具体范围依赖所使用的数据库 |
TimeField | 时间字段,类似于DateTimeField,但只能表达和输入时间 |
URLField | 用于保存URL |
USSSateField | 美国州的缩写字段 |
每个字段类型都有一些特定的HTML标签和表单验证参数,比如height_field、path等。但同时有一些每个字段都可以设置的公共参数,比如:
pythonfrom django.db import models
LEVELS=(
('1','very good'),
('2','Good'),
('3','Normal'),
('4','Bad'),
)
class Comment(models.Model):
id = models.AutoField(primary_key=True)
level = models.CharField(max_length=1,choices=LEVELS)
除了这些有名称的字段参数,django中的所有Field数据类型还有一个无名参数,可以设置该字段在HTML页面中的人性化名称,比如:
pythonclass Comment(models.Model):
id = models.AutoField(primary_key=True)
level = models.CharField("请为本条信息评级",max_length=1,choices=LEVELS)
pythonfrom django.db import models
class Comment(models.Model):
id = models.AutoField(primary_key=True)
headline = models.CharField(max_length=255)
body_text = models.TextField()
pub_date = models.DateField()
n_visits = models.IntegerField()
def __str__(self):
return self.headline
查询Comment模型的所有数据
Comment.objects.all()
获取单条记录;
Comment.objects.get(id_exact=1)
排序操作
Comment.objects.order_by('head_line')
Django两种过滤器用于筛选记录:
多个filter和exclude可以连接在一起查询
Comment.objects.filter(pub_date__year=2015)
其中的pub_date__year,它不是模型中定义的一个字段,而是Django的定义的一种独特的字段查询(field lookup)表达方式,本例中该查询的含义是"pub_date字段的year属性为2015".
field lookup基本的表现形式是
字段名称__谓词
常见的谓词有如下
谓词 | 含义 | 示例 | 等价的SQL语句 |
---|---|---|---|
exact | 精确等于 | Comment.objects.filter(id__exact=14) | select * from Comment where id=14 |
iexact | 大小写不敏感的等于 | Comment.objects.filter(headline__iexact='I like this') | select * from Comment where upper(headline)='I LIKE THIS' |
contains | 模糊匹配 | Comment.objects.filter(headline__contains="good") | select * from Comment where headline like "%good%" |
in | 包含 | Comment.objects.filter(id__in=[1,5,9]) | select * from Comment where id in (1,5,9) |
gt/gte/lt/lte | 大于 | Comment.objects.filter(n_visits__gt=30) | select * from Comment where n_visits >30 |
startswith | 以……开头 | Comment.objects.filter(body_text__startwith="Hello") | select * from Comment where body_text like 'Hello%' |
endswith | 以……结尾 | Comment.objects.filter() | |
range | 在……范围内 | Comment.objects.filter(pub_date__range=(start_date,end_date)) | |
year/month/day/week_day | 年/月/日/星期几 | Comment.objects.filter(pub_date__year=2015) | |
isnull | 是否为空 | Comment.objects.filter(pub_date__isnull=True) | select * from Comment where pub_date is NUll |
与传统SQL相比,Django的一个较大优势是定义了一个统一的方法save(),用于完成模型的Insert和Update模型。在执行模型实例的save()函数时,Django会根据模型的主键,判断记录是否存在,如果存在则执行Update操作,否则执行Delete操作。比如:
shell# 新增记录
newObj = Comment(headline="I like this",body_text="……",pub_date=datetime.datetime.now(),n_visits=0)
newObj.save()
# 打印新增对象的主键
print newObject.id
# 修改记录数据
newObj.body_text="This comment is just what I want"
newObj.save()
# 打印主键,与新增后的id相同
print newObj.id
# 删除所有2014的记录
Comment.objects.filter(pub_date__year=2014).delete()
# 删除id=3的单条记录
Comment.objects.get(id=3).delete()
利用数据表之间的关系进行数据建模和业务开发是关系数据库最主要的功能。
在SQL语言中,一对一关系通过在两个表之间定义相同的主键来完成。如下代码在模型Account和Contact之间定义了一对一关系
pythonfrom django.db import models
class Account(models.Model):
user_name = models.CharField(max_length=80)
password = models.CharField(max_length=255)
reg_date = models.DateField()
def __unicode__(self):
return "Account :%s"% self.user_name
class Contact(models.Model):
account = models.OneToOneField(Account,on_delete=models.CASCADE,primary_key=True)
zip_code = models.CharField(max_length=10)
address = models.CharField(max_length=80)
mobile = models.CharField(max_length=20)
def __unicode__(self):
return "%s, %s"%(self.account.user_name,self.mobile)
shell>>> a1 = Account(user_name="david")
>>> a1.save()
>>> a2 = Account(user_name="Rose")
>>> a2.save()
# 用a1初始化Contact的account字段,并保存
>>> c1 = Contact(account=a1,mobile="13912345000")
>>> c1.save()
>>> print a1
<Account: david>
>>> print c1
<Contact: david,13912345000>
>>> print a1.contact
<Contact: david,13912345000>
>>> print c1.account
<Account: david>
在SQL语言中,1:N关系通过在"附表"中设置到"主表"的外键引用来完成,在Django模型层,可以用models.ForeignKey类型的字段定义外键
pythonfrom django.db import models
class Account(models.Model):
user_name = models.CharField(max_length=80)
password = models.CharField(max_length=255)
reg_date = models.DateField()
def __unicode__(self):
return "Account :%s"% self.user_name
class Contact(models.Model):
account = models.ForeignKey(Account,on_delete=models.CASCADE)
zip_code = models.CharField(max_length=10)
address = models.CharField(max_length=80)
mobile = models.CharField(max_length=20)
def __unicode__(self):
return "%s, %s"%(self.account.user_name,self.mobile)
对模型的操作代码:
shell>>> a1 = Account(user_name="Rose")
>>> a1.save()
>>> c1 = Contact(account=a1,mobile="13912345001")
>>> c1.save()
>>> c2 = Contact(account=a1,mobile="13912345002")
>>> c2.save()
>>>print c1.account
<Account: Rose>
>>>print c2.account
<Account: Rose>
>>>print a1.contact_set
[<Contact: Rose, 13912345001>,<Contact: Rose, 13912345002>]
>>>print a1.contact_set.count()
2
在一对多关系中,每个主模型对象可以关联多个子对象,所以本例中从主模型Account对象中寻找附模型Contact的属性是contact_set,即通过一个集合返回结果
在SQL语言找那个,M
关系通过建立一个中间关系表来完成,该中间表中定义了到两个主表的外键。在Django模型层中,可以选择用两个1关系来定义M:N关系。这种方式同样通过models.ForeignKey来实现pythonfrom django.db import models
class Account(models.Model):
user_name = models.CharField(max_length=80)
password = models.CharField(max_length=255)
reg_date = models.DateField()
def __unicode__(self):
return "Account :%s"% self.user_name
class Contact(models.Model):
accounts = models.ManyToManyField(Account)
zip_code = models.CharField(max_length=10)
address = models.CharField(max_length=80)
mobile = models.CharField(max_length=20)
def __unicode__(self):
return "%s, %s"%(self.account.user_name,self.mobile)
模型操作:
shell>>> a1 = Account(user_name="Leon")
>>> a1.save()
>>> c1 = Contact(mobile="13912345003")
>>> c1.save()
>>> c1.accounts.add(a1)
>>> a2 = Account(user_name="Terry")
>>> a2.save()
>>> c1.accounts.add(a2)
>>> a3 = Account(user_name="Leon")
>>> c1.accounts.add(a3) # 这时候就会报错,因为a3还有保存呢
>>> a1.contact_set.remove(c1) # 取消单个对象关联
>>> a1.contact_set.clear() # 取消a1与所有其他Contact对象的关联
Django模型层ORM的一个强大之处是对模型继承的支持,该技术将Python面向对象的编程方法与数据库面向关系表的数据结构有机地结合。Django支持三种风格的模型继承:
抽象类继承的作用是在多个表有若干相同的字段时,可以使开发者将这些字段统一定义在抽象基类,免于重复定义这些字段。抽象基类的定义通过在模型的Meta中定义属性abstract=True来实现。代码如下:
pythonfrom django.db import models
class MessageBase(models.Model):
id = models.AutoField()
content = models.CharField(max_length=100)
user_name = models.CharField(max_length=80)
pub_date = models.DateField()
class Meta:
abstract=True # 定义本类为抽象基类
class Moment(MessageBase):
headline = models.CharField(max_length=50)
LEVELS = (
('1','very good'),
('2','good'),
('3','normal'),
('4','bad'),
)
class Comment(MessageBase):
level = models.CharField(max_length=1,choices=LEVELS)
此时,Moment和Comment的数据库,都是有了MessageBase的字段。在子类模型的编程中,可以直接引用父类定义的字段,比如有:
shellm1 = Moment(user_name="Terry",headline="hello world") # 新建Moment对象 m1.content = "reference parent field in subclass" m1.save()
在多表继承技术中,无论是父表还是子表都会用数据库中相对应的数据表维护模型数据,父类中的字段不会重复地在多个子类的相关数据表中定义。从某种意义上来讲,多表继承才是真正面向对象的ORM技术
多表继承的定义不需要特殊的关键字
pythonfrom django.db import models
class MessageBase(models.Model):
id = models.AutoField()
content = models.CharField(max_length=100)
user_name = models.CharField(max_length=80)
pub_date = models.DateField()
class Moment(MessageBase):
headline = models.CharField(max_length=50)
LEVELS = (
('1','very good'),
('2','good'),
('3','normal'),
('4','bad'),
)
class Comment(MessageBase):
level = models.CharField(max_length=1,choices=LEVELS)
3个数据表:
在对模型的编程过程中,子类仍然可以直接引用父类定义的字段;同时子类可以通过父类对象引用访问父类示例,比如:
shell>>>m1 = Moment(user_name="Terry",headline="hello world") # 新建Moment对象
>>>m1.content = "reference parent field in subclass"
>>>m1.save()
>>>print m1.messagebase.content
reference parent field in subclass
# 在多表继承时,子类实例中通过小写的父类的名字可以引用父亲的实例
在前联众继承模型中子类模型都有实际存储数据的作用;而代理模型中继承中子类只用于管理父类的数据,而不实际存储数据。代理模型继承通过在子类的Meta中定义proxy=True属性来实现.
pythonfrom django.db import models
class Moment(models.Model):
id = models.AutoField()
content = models.CharField(max_length=100)
user_name = models.CharField(max_length=80)
pub_date = models.DateField()
head_line = models.CharField(max_length=50)
class OrderedMoment(Moment):
class Meta:
proxy = True
ordering = ["-pub_date"]
本文作者:Eric
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!