模型类属性命名限制:
文件app/models.py
模板格式
from django.db import models
class ModelName(models.Model): # 模型类
Field1 = models.XXXField(...)
Field2 = models.XXXField(...)
...
class Meta: #元选项
db_table = ...
other_metas = ...
每个模型类都可以被映射为数据库中的一个数据表,类类属性被映射为数据字段,除此之外,数据库表的主键、外键、约束等也通过类属性完成定义
属性 | 描述 |
---|---|
AutoField |
一个自动递增的整型字段,添加记录时会自动增长 AutoField 字段通常会用于充当数据表的主键 若模型没有指定主键字段,则Django 自动添加一个 AutoField字段 |
IntegerField |
用于保存一个整数 |
SmallIntegerField |
类似于 IntegerField 但只具有较小的输入范围,具体范围依赖于所使用的数据库 |
BigIntegerField |
64位整型字段 |
BinaryField |
二进制数据字段 只能通过 types 对其赋值 |
FloatField |
浮点型字段 定义本字段时必须传入 max_digits 和decimal_places 参数 用于定义总位数(不包括小数点和符号)和小数位数 |
DecimalField |
十进制浮点数 max_digits 参数表示总位 decimal_places 参数表示小数位数 |
CommaSeparatedIntegerField |
用于存放逗号分隔的整数值 相较与普通的 CharField, 它有特殊的表单数据验证要求 |
DurationField |
存储时间周期, 用 Python 的 timedelta 类型构建 |
EmailField |
一个带检查 Email 合法性的CharField |
FileField |
一个文件上传字段 在定义本字段时传入参数 upload_to ,用于保存上载文件的服务器文件系统路径 这个路径必须 包含 striftime formatting, 该格式将上载 文件的 date/time 替换 |
FilePathField |
按目录限制规则选择文件 定义本字段必须传入参数 path ,用于限制目录 |
ImageField |
类似于 FileField,同时验证上传对象是否是一个合法的图片 有两个可选参数 height_field 和 width_field 如果提供这两个参数,则图片将按照提供的高度和宽度规格保存 该字段要求安装 Python Imaging 库 |
IPAddressField |
一个字符串形式的IP地址 例如: 192.23.250.2 |
NullBooleanField |
类似于 BooleanField, 但比其多一个None选项 |
PhoneNumberField |
带有美国风格的电话号码校验的 CharField 格式为 XXX-XXX-XXXX |
SlugField |
只包含字母、数字、下划线和连字符的输入字段 通常用于URL |
URL |
用于保存URL |
USStateField |
美国州名的缩写字段,由两个字母组成 |
XMLField |
XML字段 是具有XML合法验证的TextField |
属性 | 描述 | 相对应的HTML标签 |
---|---|---|
BooleanField |
布尔字段 |
|
CharField |
字符串字段,用于较短的字符串 | 单行输入
|
TextField |
大容量文本字段 | 多行编辑框
|
DateField |
日期字段 | 、一个JavaScript 日期和一个“today” 快捷按键 有两个额外可选参数: auto_now 当对象被保存时,将该字段的值设置为当前时间 auto_now_add 当对象被首次创建时,将该字段的值设置为当前时间 |
DateTimeField |
类似于 DateField,但同时支持于时间的输入 | |
TimeField |
时间字段,类似于 DateTimeField 但只能表达和输入时间 |
参数 | 描述 |
---|---|
max_length | 定义字符的长度 例如 : headline = models.CharField(max_length=255) |
primary_key | 设置一个模型的主键字段 例如: primary_key=true |
null | 定义是否允许相对应的数据库字段为Null, 默认设置为 False 是一个数据库中的非空约束 |
blank | 定义字段是否可以为空 blank 用于字段的HTML表单验证,即判断用户是否可以不输入数据 |
choices | 定义字段的可选值 本字段的值应该是一个包含二维元素的元组 元组的每个元素的第一个值是实际存储的值, 第二个值是HTML页面进行选择时显示的值 |
default | 设置默认值 例如: default="please input here" |
help_text | HTML页面中输入控件的帮助字符串 |
unique | 是否为字段定义数据库的唯一约束 |
无名参数 | 可以设置该字段在HTML页面中的人性化名称 例如:level = models.CharField("请为本条信息评级",max_length=1,choices=LEVELS) 如果不设置本参数,则字段本身将被显示在 HTML 页面中作为输入提示 |
db_index | 若值为True,则在表中会为此字段创建索引 默认False |
db_column | 字段的名称 如果未指定,则使用属性的名称 |
通过此类可以定义模型元数据,比如:数据库表名,数据默认排序方式等
属性 | 描述 |
---|---|
abstract: |
标识本类是否为抽象基类 True or False |
app_label: |
定义本类所属的应用 |
db_table: |
映射的数据库表名,例如: db_table=‘moments’ 如果在Meta中不提供 db_table 字段,则Django 会为模型自动生成数据表名,生成的格式为“应用名_模型名”,例如:应用app的模型 Comment 的默认数据表名为 app_comment |
db_tablespace: |
映射的表空间名称 表空间的概念只在某些数据库如 Oracle 中存在,不存在表空间的概念的数据库将忽略此字段 |
default_related_name: |
定义本模型的反向关系引用名称,默认与模型名一致 |
get_latest_by: |
定义按哪个字段值排列以获得模型的开始或结束记录 本属性值通常指向一个日期或整型的模型字段 |
managed: |
True or False 定义 Django的 manage.py 命令行工具是否管理本模型。 默认为 True,若将其设置为 False,则运行 python manage.py migrate 时将不会在数据库中生成本模型的数据表,所以需要手工维护数据库的定义 |
order_with_respect_to: |
定义本模型可以按照某外键引用的关系排序 |
order: |
本模型记录的默认排序字段,可以设置多个字段,默认以升序排列, 若以降序排列则表示要在字段名前加负号("-") 例如:定义 user_name 字段升序 和 pub_date 降序排列 order = ['user_name','-pub_date'] |
dafault_permissions: |
模型操作权限 默认为 default_permisstions=('add','change','delete') |
proxy"=: |
True or False 本模型及所有继承自本模型的子模型是否为代理模型 |
required_db_features: |
定义底层数据库所必须具备的特性 例如: required_db_features=['gis_enabled'] 只将本数据模型生成在满足 gis_enabled 特性的数据库中 |
required_db_vendor: |
定义底层数据库类型 比如 SQLite,PostgreSQL,MySQL,Oracle 如果定义了本属性,则模型只能在其声明的数据库中被维护 |
unique_together: |
用来设置的不重复的字段组合,必须唯一(可以将多个字段做联合唯一) 例如: unique_together = (("user_name","pub_date"),) 定义了每个 user_name 在同一个 pub_date 中只能有一条数据表记录 因为 unique_together 本身是一个元组,所以可以设置多个这样的唯一约束 |
index_together: |
定义联合索引的字段,可以设置多个 例如: index_together = [["pub_date","deadline"],] |
verbose_name: |
指明一个易于理解和表述的单数形式的对象名称。如果这个值没有被设置,则Django将会使用该model的类型的分词形式作为它的对象表述名,即 CamelCase 将会被转换为camel case |
verbose_name_plural: |
指明一个易于理解和表述的复数形式的对象名称 |
修改默认生成的表名,
#-*- coding:utf-8 -*-
from django.db import models
# Create your models here.
#------------- 一对多 ----------------------
#图书类
class BookInfo(models.Model):
'''图书模型类'''
#id 自动生成
#图书名称
btitle = models.CharField(max_length=20)
#出版日期
bpub_date = models.DateField()
#阅读量
bread = models.IntegerField(default=0)
#评论量
bcomment = models.IntegerField(default=0)
#删除标记
isDelete = models.BooleanField(default=False)
def __str__(self):
# 返回书名
return self.btitle
class Meta:
db_table = 'bookinfo' #指定模型类对应的表明
模型类.objects.属性
函数名 | 功能 | 返回值 | 说明 |
---|---|---|---|
get |
返回表中满足条件的一条且只能有一条数据 | 返回值是一个模型类对象 | 参数中写查询条件 1. 如果查到多条数据,则抛异常 MultipleObjectsReturned 2. 查询不到数据,则抛异常: DoesNotExist |
all |
返回模型类对应表格中的所有数据 | 返回值是QuerySet类型 | 查询集 |
filter |
返回满足条件的数据 | 返回值是QuerySet类型 | 参数写查询条件 |
exclude |
返回不满足条件的数据 | 返回值是QuerySet类型 | 参数写查询条件 |
order_by |
对查询结果进行排序 | 返回值是QuerySet类型 | 参数中写根据哪些字段进行排序 降序:字段前加 ‘-’号 |
练习与演示
准备练习数据集:使用博客 Django_182_入门指南 图书数据表进行练习
查询集
all
, filter
, exclude
, order_by
调用这些函数会产生一个查询集,QuerySet类对象
可以继续调用上面的所有函数
查询集特性
限制查询集
3. 可以对一个查询集进行取下标或者切片操作来限制查询集的结果, 下标不允许为负数
4. 对一个查询集进行切片操作会产生一个新的查询集
取出查询集的数据
方法 | 说明 |
---|---|
b[0] |
如果b[0]不存在,抛异常:IndexError |
b[0:1].get() |
如果b[0:1].get() 不存在,抛异常:DoesNotExist |
exists()
函数判断一个查询集是否有数据,返回 True,False
查询有id=5的数据
book = BookInfo.objects.get(id=5)
等效
book = BookInfo.objects.get(id__exact=5)
使用查询的id号没有数据,抛的异常
使用get查询出多个数据,抛出异常
参数格式 模型属性名__条件名=值
exact
查询 id=5 的数据
book = BookInfo.objects.get(id__exact=5)
查询 isDelete=0 的数据
books = BookInfo.objects.filter(isDelete__exact=0)
条件名 contains
包含
查询书名包含 “传” 的图书
books = BookInfo.objects.filter(btitle__contains='传')
条件名 endswith
以…结尾
查询以 “部” 结尾的图书
books = BookInfo.objects.filter(btitle__endswith='部')
条件名 startswith
以…开头
查询 以“流” 开头的图书
books = BookInfo.objects.filter(btitle__startswith='流')
查询图书名 不为空 的图书
books = BookInfo.objects.filter(btitle__isnull=False)
books = BookInfo.objects.filter(btitle__isnull=True)
查询 id 为 5,7,17 中图书
books = BookInfo.objects.filter(id__in = [5,7,17])
gt
(great than) 大于
lt
(less than) 小于
gte
(great than equal) 大于等于
lte
(less than equal) 小于等于
查询 id>0 的图书
books = BookInfo.objects.filter(id__gt = 10)
条件名 year
年
查询 1980 年发表的图书
books = BookInfo.objects.filter(bpub_date__year=1980)
books = BookInfo.objects.filter(bpub_date__month=11)
from datetime import date
books = BookInfo.objects.filter(bpub_date__gt=date(1980,1,1))
查询 id 不等于 5 的数据
books = BookInfo.objects.exclude(id=5)
查询所有图书的信息,按照 id 从小到大进行排序
books = BookInfo.objects.all().order_by('id')
查询所有图书的信息,按照 id 从大到小进行排序
books = BookInfo.objects.all().order_by('-id')
books = BookInfo.objects.filter(id__gt=3).order_by('-bread')
查询图书阅读量>评论量的图书
from django.db.models import F
books = BookInfo.objects.filter(bread__gt=F('bcomment'))
from django.db.models import F
books = BookInfo.objects.filter(bread__gt=F('bcomment')*2)
且 &
查询 id>3 并且阅读量 大于30 的图书信息
books = BookInfo.objects.filter(id__gt=3,bread__gt=30)
等效
from django.db.models import Q
books = BookInfo.objects.filter(Q(id__gt=3)&Q(bread__gt=30))
from django.db.models import Q
books = BookInfo.objects.filter(Q(id__gt=3)|Q(bread__gt=30))
from django.db.models import Q
books = BookInfo.objects.filter(~Q(id=5))
使用aggregate()
函数来使用聚合,返回是 字典
sum
求和查询所有图书阅读量的总和
from django.db.models import Sum
bread_num = BookInfo.objects.all().aggregate(Sum('bread'))
count
统计查询所有图书的数目
from django.db.models import Count
books_num = BookInfo.objects.all().aggregate(Count('id'))
from django.db.models import Count
books_num = BookInfo.objects.aggregate(Count('id'))
count()
函数:统计满足条件的数目,返回的是一个数字
统计所有图书的数目
books_num = BookInfo.objects.all().count()
books_num = BookInfo.objects.filter(id__gt=3).count()
avg
求平均值max
求最大值min
求最小值调用一个模型类对象save()
方法的时候就可以实现对模型类对应数据表的插入和更新
调用一个模型类对象delete()
方法的时候就可以实现对模型类对应数据表的删除
例如:一本图书 有 多个英雄
models.ForeignKey()
定义在多的类中
在 CTTIC/app/models.py
中
from django.db import models
# Create your models here.
#图书类
class BookInfo(models.Model):
'''图书模型类'''
#id 自动生成
#图书名称
btitle = models.CharField(max_length=20)
#出版日期
bpub_date = models.DateField()
#阅读量
bread = models.IntegerField(default=0)
#评论量
bcomment = models.IntegerField(default=0)
#删除标记
isDelete = models.BooleanField(default=False)
def __str__(self):
# 返回书名
return self.btitle
#英雄人物类
class HeroInfo(models.Model):
#英雄名 hname
hname = models.CharField(max_length=20)
# 性别 hgender,并指定默认值
hgender = models.BooleanField(default=False)
# 备注 hcomment
hcomment = models.CharField(max_length=128)
isDelete = models.BooleanField(default=False)
#关系属性,建立图书类和英雄人物类之间的一对多关系
hbook = models.ForeignKey('BookInfo')
def __str__(self):
return self.hname
使用博客 Django_182_入门指南 图书数据表进行练习
查询图书信息,要求图书关联的英雄的描述包含‘八’
books = BookInfo.objects.filter(heroinfo__hcomment__contains='八')
books = BookInfo.objects.filter(heroinfo__id__gt=3)
from app.models import HeroInfo
heros = HeroInfo.objects.filter(hbook__btitle='天龙八部')
总结:
通过多类的条件查询一类的数据
一类名.objects.filter(多类名小写__多类属性名__条件名)
通过一类的条件查询多类的数据
多类名.objects.filter(关联属性__一类属性名__条件名)
例如:一个老师有多个学生,一个学生有多个老师
models.ManyToManyField()
定义在哪个类中都可以
#-*- coding:utf-8 -*-
from django.db import models
#老师信息
class TeacherInfo(models.Model):
#老师姓名
tname = models.CharField(max_length=20)
# 老师描述
tcomment = models.TextField()
# 学生信息
class StudentInfo(models.Model):
# 学生姓名
sname = models.CharField(max_length=20)
# 学生描述
scomment = models.TextField()
teacher = models.ManyToManyField('TeacherInfo')
例如:员工基本信息 对应 员工详细信息
models.OneToOneField()
定义在哪个类中都可以
#-*- coding:utf-8 -*-
from django.db import models
#员工基本信息类
class EmployeeBasicInfo(models.Model):
#姓名
name = models.CharField(max_length=20)
#年龄
age = models.IntegerField()
# 性别,默认False对应男
gender = models.BooleanField(default=False)
def __str__(self):
return self.name
#员工详细信息类
class EmployeeDetailInfo(models.Model):
#联系地址
addr = models.CharField(max_length=255)
#教育经历
education = models.TextField()
#关系属性,代表一对一关系
employee_basic = models.OneToOneField('EmployeeBasicInfo')
def __str__(self):
return self.addr
自关联是一种特殊的一对多的关系,使用models.ForeignKey()
关联
aParent_id
表示该地区上级所属的id号,若该地区为父级,则为NULL(为空)
#-*- coding:utf-8 -*-
from django.db import models
class AreaInfo(models.Model):
'''地区模型类'''
# 地区名称
atitle = models.CharField(max_length=20)
# 关系属性:代表当前地区的父级地区对应id,允许为空
aParent = models.ForeignKey('self',null=True,blank=True)
执行迁移文件生成表
python manage.py makemigrations
python manage.py migrate
INSERT INTO app_areainfo VALUES ('110000', '北京市', NULL);
INSERT INTO app_areainfo VALUES ('110100', '北京市', '110000');
INSERT INTO app_areainfo VALUES ('110101', '东城区', '110100');
INSERT INTO app_areainfo VALUES ('110102', '西城区', '110100');
INSERT INTO app_areainfo VALUES ('110103', '朝阳区', '110100');
INSERT INTO app_areainfo VALUES ('110104', '丰台区', '110100');
INSERT INTO app_areainfo VALUES ('110105', '石景山区', '110100');
INSERT INTO app_areainfo VALUES ('110106', '海淀区', '110100');
INSERT INTO app_areainfo VALUES ('110107', '门头沟区', '110100');
此处数据链接
链接:https://pan.baidu.com/s/1EPQ-ztSaB7n5KFGTk98phw
提取码:drye
复制这段内容后打开百度网盘手机App,操作更方便哦
显示 广东 的上级地区 及 下级地区
在 CTTIC/app/views.py
中添加视图函数
#-*- coding:utf-8 -*-
from django.shortcuts import render
from app.models import AreaInfo
def areas(request):
'''获取广州市的上级及下级地区'''
# 获取广州市的信息
area = AreaInfo.objects.get(atitle='广州市')
# 查询广州市的上级地区
parent = area.aParent
# 查询广州市的下级地区
children = area.areainfo_set.all()
context = {
'area':area,
'parent':parent,
'children':children,
}
return render(request,'app/areas.html',context)
新建 CTTIC/templates/app/areas.html
<html lang="en">
<head>
<meta charset="UTF-8">
<title>自关联案例title>
head>
<body>
<h1>当前地区h1>
{{ area.atitle }} <br/>
<h1>父级地区h1>
{{ parent.atitle }} <br/>
<h1>下级地区h1>
<ul>
{% for child in children %}
<li>{{ child.atitle }}li>
{% endfor %}
ul>
body>
html>
CTTIC/app/urls.py
配置路由
#-*- coding:utf-8 -*-
from django.conf.urls import url
from app import views
urlpatterns = [
# 通过url函数设置url配置项
url(r'^areas$',views.areas),
]
Django模型层 ORM 的一个强大之处是对模型继承的支持,该技术将Python面向对象的编程方法与数据库面向关系表的数据结构有机结合
Django支持三种风格的模型继承
abstract = True
models.Model
,但不会在底层数据库中生成相应的数据表proxy=True
来实现# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models
# Create your models here.
#父类
class MessageBase(models.Model):
content = models.CharField(max_length=100,null=True)
user_name = models.CharField(max_length=80,null=True)
pub_date = models.DateField(null=True)
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)
3个类映射到数据库后,会被定义为两个数据表
数据表 moment: 有 id,content,user_name,pub_date,headline 等5个字段
数据表 comment: 有 id,content,user_name,pub_date,level 等5个字段
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models
# Create your models here.
class MessageBase(models.Model):
content = models.CharField(max_length=100,null=True)
user_name = models.CharField(max_length=80,null=True)
pub_date = models.DateField(null=True)
class Moment(MessageBase):
headline = models.CharField(max_length=50)
class Comment(MessageBase):
level = models.CharField(max_length=1,choices=LEVELS)
生成3个数据表
数据表 MessageBase: 有 id,content,user_name,pub_date 等4个字段
数据表 Moment: 有id,headline等两个字段
数据表 Comment: 有 id,level 等两个字段
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models
# Create your models here.
class Moment(models.Model):
content = models.CharField(max_length=100,null=True)
user_name = models.CharField(max_length=80,null=True)
pub_date = models.DateField(null=True)
headline = models.CharField(max_length=50)
class OrderedMoment(Moment):
class Meta:
proxy = True;
ordering = ["-pub_date"]