重庆分公司,新征程启航
为企业提供网站建设、域名注册、服务器等服务
本篇内容接上篇Python基础(Django二)
创新互联建站-成都网站建设公司,专注做网站、成都网站设计、网站营销推广,申请域名,网页空间,网站托管运营有关企业网站制作方案、改版、费用等问题,请联系创新互联建站。
七、Model
1、说明:
Model是Django为方便程序操作数据库而诞生的,使用的是ORM模式。
对象关系映射(Object Relational Mapping,简称ORM)模式是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术。简单的说,ORM是通过使用描述对象和数据库之间映射的关系,将程序中的对象自动持久化到关系数据库中。
2、使用:
2-1、创建Model(编辑应用目录下的models.py)
from django.db import models class Author(models.Model): #定义一个类(表),类名即是表名 #定义一个叫first_name的字段(列),字段类型为字符串类型,参数设置最大长度为32个字节 first_name = models.CharField(max_length=32) last_name = models.CharField(max_length=32) email = models.EmailField(null=True,blank=True) #字段类型为邮箱,会有格式验证 def __unicode__(self): #定义查询类的数据时显示的值 return '%s %s'%(self.first_name,self.last_name)
字段类型:
1、models.AutoField 自增列 = int(11)
如果没有的话,默认会生成一个名称为 id 的列,如果要显示的自定义一个自增列,必须将给列设置为主键 primary_key=True。
2、models.CharField 字符串字段
必须 max_length 参数
3、models.BooleanField 布尔类型 =tinyint(1)
不能为空
4、models.ComaSeparatedIntegerField 用逗号分割的数字 =varchar
继承CharField,所以必须有 max_lenght 参数
5、models.DateField 日期类型 date
对于参数,auto_now = True 则每次更新都会更新这个时间;auto_now_add 则只是第一次创建添加,之后的更新不再改变。
6、models.DateTimeField 日期类型 datetime
同DateField的参数
7、models.Decimal 十进制小数类型 = decimal
必须指定整数位max_digits和小数位decimal_places
8、models.EmailField 字符串类型(正则表达式邮箱) =varchar
对字符串进行正则表达式
9、models.FloatField 浮点类型 = double
10、models.IntegerField ×××
11、models.BigIntegerField 长×××
integer_field_ranges = {
'SmallIntegerField': (-32768, 32767),
'IntegerField': (-2147483648, 2147483647),
'BigIntegerField': (-9223372036854775808, 9223372036854775807),
'PositiveSmallIntegerField': (0, 32767),
'PositiveIntegerField': (0, 2147483647),
}
12、models.IPAddressField 字符串类型(ip4正则表达式)
13、models.GenericIPAddressField 字符串类型(ip4和ip6是可选的)
参数protocol可以是:both、ipv4、ipv6
验证时,会根据设置报错
14、models.NullBooleanField 允许为空的布尔类型
15、models.PositiveIntegerFiel 正Integer
16、models.PositiveSmallIntegerField 正smallInteger
17、models.SlugField 减号、下划线、字母、数字
18、models.SmallIntegerField 数字
数据库中的字段有:tinyint、smallint、int、bigint
19、models.TextField 字符串=longtext
20、models.TimeField 时间 HH:MM[:ss[.uuuuuu]]
21、models.URLField 字符串,地址正则表达式
22、models.BinaryField 二进制
23、models.ImageField 图片
24、models.FilePathField 文件
参数:
1、null=True
数据库中字段是否可以为空
2、blank=True
django的 Admin 中添加数据时是否可允许空值
3、primary_key = False
主键,对AutoField设置主键后,就会代替原来的自增 id 列
4、auto_now 和 auto_now_add
auto_now 自动创建---无论添加或修改,都是当前操作的时间
auto_now_add 自动创建---永远是创建时的时间
5、choices
GENDER_CHOICE = (
(u'M', u'Male'),
(u'F', u'Female'),
)
gender = models.CharField(max_length=2,choices = GENDER_CHOICE)
6、max_length
7、default 默认值
8、verbose_name Admin中字段的显示名称
9、name|db_column 数据库中的字段名称
10、unique=True 不允许重复
11、db_index = True 数据库索引
12、editable=True 在Admin里是否可编辑
13、error_messages=None 错误提示
14、auto_created=False 自动创建
15、help_text 在Admin中提示帮助信息
16、validators=[]
17、upload-to
#相关命令
python manage.py validate #用来检测models.py语法的正确性
python manage.py makemigrations
python manage.py migrate #根据代码中定义的类来自动创建数据库表
2-2、操作数据库表
from app01 import models # 增 # #第一种: models.Author.objects.create(first_name='zhang',last_name='san',email='z@test.com') #第二种:可以接受字典类型的数据 dic = {'first_name': 'li', 'last_name': 'si', 'email': 'z@test.com'} models.Author.objects.create(**dic) #第三种: obj = models.Author(**dic) obj.save() # 查 # models.Author.objects.all() #获取Author表里的所有数据 #过滤查询 filter()方法获取的是一个列表,get()方法获取的是单个对象 models.Author.objects.get(first_name='zhang') #Author是表名称,first_name是字段名称,zhang是查询的关键字 models.Author.objects.filter(last_name='san') models.Author.objects.filter(first_name='zhang', last_name='san') #查询条件可以有多个 models.Author.objects.exclude(first_name='zhang') #查询first_name不等于zhang的 models.Author.objects.filter(first_name='zhang').count() #获取满足查询条件的数据个数 #多重查询 models.Author.objects.filter(first_name='zhang').order_by("email") #限制查询 models.Author.objects.order_by('first_name')[0] #取查询结果QuerySet的第一个值 #排序 models.Author.objects.order_by("first_name") #根据某一个字段值对结果排序 models.Author.objects.order_by("first_name","last_name") #根据多个字段排序,第二个字段会在第一个字段值相同的情况下被使用到 models.Author.objects.order_by("-first_name") #逆向排序,字段前面加减号-前缀 #利用双下划线将查询字段和相应操作连接起来(摘自其他博客) # 大于,小于 models.Tb1.objects.filter(id__gt=1) # 获取id大于1的值 models.Tb1.objects.filter(id__lt=10) # 获取id小于10的值 models.Tb1.objects.filter(id__lt=10, id__gt=1) # 获取id大于1 且 小于10的值 # in models.Tb1.objects.filter(id__in=[11, 22, 33]) # 获取id等于11、22、33的数据 models.Tb1.objects.exclude(id__in=[11, 22, 33]) # not in # contains models.Tb1.objects.filter(name__contains="ven") #用于模糊匹配name字段。 models.Tb1.objects.filter(name__icontains="ven") #icontains大小写不敏感 models.Tb1.objects.exclude(name__icontains="ven") #取反 # range models.Tb1.objects.filter(id__range=[1, 2]) # 范围bettwen and # 改 # # 在查询的基础上增加一个修改操作 # 第一种: models.Author.objects.filter(last_name='si').update(last_name='SI') # 第二种:可以接受字典类型的数据 dic = {'first_name': 'li', 'last_name': 'si', 'email': 'z@test.com'} models.Author.objects.filter(last_name='si').update(**dic) # 第三种: obj = models.Author.objects.get(last_name='si') obj.email = 'new@test.com' obj.save() # 删 # # 在查询的基础上增加一个删除操作 models.Author.objects.filter(last_name='san').delete()
2-3、连表结构
说明:
Django的ORM有多种关系:
一对一:一个只属于一个
一对多:一个属于多个
多对多:一个既有很多个,又属于很多个
各自定义的方式为 :
一对一: models.OneToOneField(其他表)
一对多: models.ForeignKey(其他表)
多对多: models.ManyToManyField(其他表)
应用场景:
一对多:当一张表中创建一行数据时,有一个单选的下拉框(可以被重复选择)
例如:创建用户信息时候,需要选择一个用户类型【普通用户】【金牌用户】【铂金用户】等。
多对多:在某表中创建一行数据是,有一个可以多选的下拉框
例如:创建用户信息,需要为用户指定多个爱好
一对一:在某表中创建一行数据时,有一个单选的下拉框(下拉框中的内容被用过一次就消失了
举例:
#models.py
# -*- coding:utf-8 -*- from __future__ import unicode_literals from django.db import models # Create your models here. # OneToMany example 1 class UserType(models.Model): caption = models.CharField(max_length=32) def __unicode__(self): return self.caption class UserInfo(models.Model): user_type = models.ForeignKey(UserType) username = models.CharField(max_length=32) age = models.IntegerField() def __unicode__(self): return self.username # OneToMany example 2 class MyUser(models.Model): username = models.CharField(max_length=16) password = models.CharField(max_length=16) def __unicode__(self): return self.username class News(models.Model): title = models.CharField(max_length=32) content = models.CharField(max_length=32) def __unicode__(self): return self.title class Favor(models.Model): user_obj = models.ForeignKey(MyUser) new_obj = models.ForeignKey(News) def __unicode__(self): return "%s --> %s"%(self.user_obj.username,self.new_obj.title) # ManyToMany example 1 class Host(models.Model): hostname = models.CharField(max_length=32) port = models.IntegerField() def __unicode__(self): return self.hostname class HostAdmin(models.Model): username = models.CharField(max_length=32) email = models.CharField(max_length=32) host = models.ManyToManyField(Host) def __unicode__(self): return self.username # ManyToMany example 2 '''手动创建多对多关系表,不需要Django自动创建,优点是第三张表的字段可以自定义''' class Host2(models.Model): hostname = models.CharField(max_length=32) port = models.IntegerField() def __unicode__(self): return self.hostname class HostAdmin2(models.Model): username = models.CharField(max_length=32) email = models.CharField(max_length=32) host = models.ManyToManyField(Host2,through="HostRelation") def __unicode__(self): return self.username class HostRelation(models.Model): host_obj = models.ForeignKey(Host2) admin_obj = models.ForeignKey(HostAdmin2)
#views.py
# -*- coding:utf-8 -*- from django.shortcuts import render,HttpResponse from app01 import models # Create your views here. def user_info(request): # 一对多 # # models 为"OneToMany example 1" #创建数据# #第一种: ForeignKey所在的字段加 _id 进行直接赋值 models.UserInfo.objects.create(username='test1',age=13,user_type_id=1) #user_type_id是一对多关系表中Django自动生成的字段名 #第二种:ForeignKey所在的字段使用对象进行赋值 user_type_obj = models.UserType.objects.get(id=2) #先从user_type表中获取一个对象 models.UserInfo.objects.create(username='test2',age=14,user_type=user_type_obj) #使用刚获取的对象进行赋值(注意字段名称) #正向查找#(就是从ForeignKey所在字段的表去查询数据) #单表查询 models.UserInfo.objects.filter(username='test1') #查询UserInfo表中username字段值是‘test1’的数据 # 跨表查询,通过ForeignKey所在的字段 + 双下划线 + 被跨的表中的字段来查询(ForeignKey所在的字段user_type是一个对象) # models.UserInfo.objects.filter(user_type__caption='CEO') #查询UserInfo表中user_type对象中caption字段的值是CEO的数据 ret = models.UserInfo.objects.filter(user_type__id=2) #语法同上,ret是一个QuerySet对象 for i in ret: #打印获取到的QuerySet对象中每个值的username属性,以及user_type对象的caption属性(跨表操作时,查询使用__(双下划线),访问字段使用.(点)) print i.username,i.user_type.caption #反向查找#(就是从被ForeignKey字段关联的表去查询数据) #单表查询 line = models.UserType.objects.get(id=1) #从UserType表中获取一个id=1的对象 #跨表查询 # 第一种: 通过被跨的表的小写表名 + 双下划线 + 要查询的字段 来查询 models.UserType.objects.get(userinfo__username='test1') #userinfo是django自动在UserType表中创建的一个对象,也就是对端表的小写表名 # 第二种: line.userinfo_set.filter(username='test1') # line是一个对象(参考如上的获取条件) # userinfo_set是UserInfo表中满足line条件的所有值。也就是UserInfo表中所有user_type=1 的值 # 本次查询的目标是:通过UserType表去反向查询UserInfo表中user_type=1且username=test1的所有数据 line.userinfo_set.all().count() #计算满足查询条件的数据个数 #多级查询, models 为"OneToMany example 2" ret = models.News.objects.filter(favor__user_obj__username='zhangsan') # 查询的表顺序为 News -> Favor -> MyUser # 先是反向跨表查询:通过News表查询Favor表中的user_obj对象 # 再是正向跨表查询:通过user_obj对象查询Myuser表中username字段值为zhangsan的用户 # 最终得到zhangsan赞过的所有文章 for i in ret: print i.title #文章的标题 print i.favor_set.all().count() #文章一共几个赞 # 多对多 # # models为 "ManyToMany example 1" models.HostAdmin.objects.create(username='a1',email='1@qq.com') #创建一个用户,管理的主机为空 #正向添加# admin_obj = models.HostAdmin.objects.get(username='a1') #先获取一个用户对象 host_list = models.Host.objects.filter(id__lt=3) #再获取多个主机对象 admin_obj.host.add(*host_list) #为一个用户添加多个可管理的主机 #反向添加# host_obj = models.Host.objects.get(hostname='h2') #先获取一个主机对象 admin_list = models.HostAdmin.objects.filter(id__gt=1) #再获取多个用户对象 host_obj.hostadmin_set.add(*admin_list) #为一个主机添加多个用户,注意这里用到了hostadmin_set #正向查询# admin_obj = models.HostAdmin.objects.get(username='a1') #先获取一个用户对象 host_list = admin_obj.host.all() #查询该用户管理的所有主机 for i in host_list: print i.hostname,i.port #反向查询# host_obj = models.Host.objects.get(hostname='h2') #先获取一个主机对象 admin_list = host_obj.hostadmin_set.all() #查询该主机的所有管理员 for i in admin_list: print i.username,i.email #自定义多对多关系# # models为 "ManyToMany example 2" # 添加数据 models.HostRelation.objects.create( host_obj_id = 1, #等于 host_obj = models.Host2.objects.get(id=1) admin_obj_id = 1, #等于 admin_obj = models.HostAdmin2.objects.get(id=1) ) # 查询 # relation_list = models.HostRelation.objects.all() relation_list = models.HostRelation.objects.filter(admin_obj__username='user1') #通过HostRelation表查询用户名是user1的所有数据 for i in relation_list: print i.admin_obj.username #用户名 print i.host_obj.hostname #用户所管理主机的主机名 # Django 的F # # 对对象中某一列值的操作 from django.db.models import F models.Host.objects.filter(hostname='h2').update(port=F('port')+1) #把Host表中所有hostname=h2的数据的port值加1 models.Host.objects.update(port=F('port')+1) #把Host表中所有的port值加1 # Django 的Q # # 对象的复杂查询 from django.db.models import Q #单Q多条件查询 q1 = Q() #创建一个Q对象 q1.connector = 'OR' #定义查询条件是 '或' q1.children.append(('hostname__contains','h2')) #children添加的是元祖,查询字段支持使用一些自带的方法 q1.children.append(('hostname','h3')) #添加多个查询条件 q1.children.append(('hostname','h6')) ret_list = models.Host.objects.filter(q1) #使用q1对象进行查询(针对Host表) for i in ret_list: print '%s->%s'%(i.hostname,i.port) #多Q多条件查询 con = Q() #创建一个外层Q对象,Q可以嵌套 q2 = Q() q2.connector = 'OR' q2.children.append(('port','23')) #查询port字段值等于23的数据 q2.children.append(('port__gt','23')) #查询port字段值大于23的数据 con.add(q1,'AND') #把q1添加到之前定义的最外层的Q对象中,查询条件是 '和' con.add(q2,'AND') #把q2添加到之前定义的最外层的Q对象中,查询条件是 '和' ret_list = models.HostAdmin.objects.filter(con) #查询的结果是同时满足q1和q2条件的数据(针对HostAdmin表) for i in ret_list: print '%s->%s'%(i.hostname,i.port) #多Q多条件跨表查询 q1.children.append(('username','a1')) q1.children.append(('username','a2')) q1.children.append(('username','a3')) q2.children.append(('host__hostname','h5')) #支持跨表查询,host是表名 + 双下划线 + 查询的字段 con.add(q1,'AND') con.add(q2,'AND') ret_list = models.HostAdmin.objects.filter(con) #查询用户名是a1或a2或a3 且管理主机名为h5的用户(针对HostAdmin表) for i in ret_list: print i.username return HttpResponse('ok') #无特别意义,只是函数需要一个返回值。
博客的部分内容和思路整理自武沛齐的博客。