Django 之models进阶操作
到目前为止,当我们的程序涉及到数据库相关操作时,我们一般都会这么搞:
- 创建数据库,设计表结构和字段
- 使用 MySQLdb 来连接数据库,并编写数据访问层代码
- 业务逻辑层去调用数据访问层执行数据库操作
import MySQLdb def GetList(sql):
db = MySQLdb.connect(user='root', db='wupeiqidb', passwd='1234', host='localhost')
cursor = db.cursor()
cursor.execute(sql)
data = cursor.fetchall()
db.close()
return data def GetSingle(sql):
db = MySQLdb.connect(user='root', db='wupeiqidb', passwd='1234', host='localhost')
cursor = db.cursor()
cursor.execute(sql)
data = cursor.fetchone()
db.close()
return data
mysql
首先Django是通过Model操作数据库,不管你数据库的类型是MySql或者Sqlite,Django它自动帮你生成相应数据库类型的SQL语句,所以不需要关注SQL语句和类型,对数据的操作Django帮我们自动完成。只要回写Model就可以了!
django为使用一种新的方式,即:关系对象映射(Object Relational Mapping,简称ORM)。
PHP:activerecord
Java:Hibernate
C#:Entity Framework
django中遵循 Code Frist 的原则,即:根据代码中定义的类来自动生成数据库表。
对于ORM框架里:
我们写的类表示数据库的表
如果根据这个类创建的对象是数据库表里的一行数据
对象.id 对象.value 是每一行里的数据
一、创建表
1、基本结构
想看一段简单的代码:
from django.db import models # Create your models here.
class UserType(models.Model):
catption = models.CharField(max_length=32)
# 超级管理员,普通用户,游客,黑户 class UserInfo(models.Model):
user = models.CharField(max_length=32)
pwd = models.CharField(max_length=32)
user_type = models.ForeignKey('UserType')
# user_type_id
2、更多字段
首先要了解,如果Django如果不是有一个后台admin可以操作数据库的话,Model没有必要设置很多的数据类型,那么这么多的数据类型,他的存在的意义就是为了限制从admin时的操作。
还有就是不要把Form和Model弄混了!他们两个是完全独立的!Model的数据类型和Form没有关系,数据类型存在的意义就是限制admin的操作。(原因:如果不对admin进行限制的话容易造成脏数据)但是form提交的数据也必须是符合Model的存储要求的,这个可以在form哪里进行判断,然后存储即可。
在admin添加数据的时候,如果在Model设置了规则如下:
app中admin配置如下:
from django.contrib import admin # Register your models here.
from app01 import models
admin.site.register(models.UserInfo)
admin.site.register(models.UserType)
执行创建superuser命令
localhost:djano19 JasonWang$ python3 manage.py createsuperuser
Username (leave blank to use 'jasonwang'): admin
Email address:
Password:
Password (again):
Superuser created successfully.
字段:
1、models.AutoField 自增列 = int(11)
如果没有的话,默认会生成一个名称为 id 的列,如果要显示的自定义一个自增列,必须将给列设置为主键 primary_key=True。
2、models.CharField 字符串字段
必须 max_length 参数
3、models.BooleanField 布尔类型=tinyint(1)
不能为空,Blank=True
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
这里单独说下:
models.DateTimeField
class UserInfo(models.Model):
user = models.CharField(max_length=32)
pwd = models.CharField(max_length=32)
user_type = models.ForeignKey('UserType')
ctime = models.DateTimeField(auto_now=True) #默认这样写上就不用管了,每当你创建一行数据的时候就会在那一行数据中增加一个ctime字段
uptime = models.DateTimeField(auto_now_add=True)#默认写成这样也不同管了,当前表任何一行有修改的时候他就会自动更新
如何在编译器环境下插入数据,对于django1.10版本需要先做一下操作
>>> import os
>>> os.environ['DJANGO_SETTINGS_MODULE'] = 'djano19.settings'#设置环境变量
>>> import django
>>> django.setup()
>>> from app01.models import UserInfo
>>> from app01.models import UserInfo,UserType
>>> cap = UserType.objects.create(catption='superuser')
>>> cap.save()
>>> user = UserInfo.objects.create(user='jason',pwd='6666',user_type=UserType.objects.get(id=1))#通过查询User_type对应的id操作
>>> user.save()
>>> cap = UserType.objects.create(catption='generaluser')
>>> cap.save()
>>> user = UserInfo.objects.create(user='jason',pwd='6666',user_type_id=2) #直接通过外键id创建
>>> user.save()
>>>
特别说明,当创建userinfo表时,后自动生成外键对应的user_type_id外键,数据库中显示如下:
models.GenericIPAddressField
他和email类似也是字符串类型然后进行了正则表达式的判断他支持IPV4,IPV6,旧的models.IPAddressField 已经很少用了
models.ImageField 图片
models.FilePathField 文件
class UserInfo(models.Model):
user = models.CharField(max_length=32)
pwd = models.CharField(max_length=32)
user_type = models.ForeignKey('UserType')
ctime = models.DateTimeField(auto_now=True) #默认这样写上就不用管了,每当你创建一行数据的时候就会在那一行数据中增加一个ctime字段
uptime = models.DateTimeField(auto_now_add=True)#默认写成这样也不同管了,当前表任何一行有修改的时候他就会自动更新
img = models.ImageField(null=True,blank=True,upload_to='upload')
#null=True,表示数据库存储的时候可以为空,blank=True表示在admin后台提交的时候可以为空!
#upload_to='upload' 用户提交的数据保存到哪里
# user_type_id #自动生成此字段
这里需要注意:在数据库中实际保存的并不是文件,而是文件的URL
文件保存:
Model扩展知识点(1):输出Model对象默认返回值
class UserInfo(models.Model):
user = models.CharField(max_length=32)
pwd = models.CharField(max_length=32)
user_type = models.ForeignKey('UserType')
ctime = models.DateTimeField(auto_now=True) #默认这样写上就不用管了,每当你创建一行数据的时候就会在那一行数据中增加一个ctime字段
uptime = models.DateTimeField(auto_now_add=True)#默认写成这样也不同管了,当前表任何一行有修改的时候他就会自动更新
img = models.ImageField(null=True,blank=True,upload_to='upload')
#null=True,表示数据库存储的时候可以为空,blank=True表示在admin后台提交的时候可以为空!
#upload_to='upload' 用户提交的数据保存到哪里
# user_type_id
def __str__(self): #python2 _unicode__
return self.username
#上面的__str__(self)方法,是当你输出这类对象的时候某人输出,比如这个输出的是这个username这一列.
输出所有userinfo对象
def index(request):
models.UserInfo.objects.create(user='jasonwang',pwd='123',user_type_id="2")
u = models.UserInfo.objects.filter(user_type__catption='superuser')
print(models.UserInfo.objects.all())
结果:
<QuerySet [<UserInfo: jason>, <UserInfo: jason>, <UserInfo: jasonwang>, <UserInfo: jasonwang>]>
如果使用__str__(python2 __unicode__)方法默认返回的是对象:[<UserInfo: UserInfo object>]
例子(2)单独查询某一条数据:
def index(request):
test = models.UserInfo.objects.filter(username='jason')
print(test)
输出结果:
<QuerySet [<UserInfo: jason>, <UserInfo: jason>]>
Model扩展知识点(2):添加新的字段报错(添加新的列)
报错信息如下:
localhost:djano19 JasonWang$ python3 manage.py makemigrations
You are trying to add a non-nullable field 'address' to userinfo without a default; we can't do that (the database needs something to populate existing rows).
Please select a fix:
1) Provide a one-off default now (will be set on all existing rows with a null value for this column)
2) Quit, and let me add a default in models.py
报错,你准备去添加一个非空的字段的时候原表中已经有的行没有这个字段,就会导致报错!可以通过:允许为空、或者设置默认值来解决
email = models.EmailField(max_length=64,null=True)
address = models.EmailField(max_length=64,default='chaoyang')
额外说明:
Form的作用就是创建标签和获取用户的输入并进行判断,它和Model没有任何关系!通过Form我们可以获取两种状态:正确、错误! 如果是错误的话我们可以获取错误输出,正确的话通过对象.clean()来获取用户输入(字典形式)。Form里的规则主要和用户打交道! Model就是操作数据库,如果Django没有这个admin后台的话他根本不需要那么多的数据类型,几个常用的即可。Model里的规则主要和Admin打交道。 目的是为了防止用户和admin去肆意操作数据库的两套规则,只是相近的!
Model表结构
- 一对多:models.ForeignKey(其他表)
- 多对多:models.ManyToManyField(其他表)
- 一对一:models.OneToOneField(其他表)
一般创建外键关联的时候,就有一对多,或者多对多 一对一仅在Django中出现。
应用场景:
- 一对多:当一张表中创建一行数据时,有一个单选的下拉框(可以被重复选择)
例如:创建用户信息时候,需要选择一个用户类型【普通用户】【金牌用户】【铂金用户】等。
- 多对多:在某表中创建一行数据是,有一个可以多选的下拉框
例如:创建用户信息,需要为用户指定多个爱好
- 一对一:在某表中创建一行数据时,有一个单选的下拉框(下拉框中的内容被用过一次就消失了
例如:原有含10列数据的一张表保存相关信息,经过一段时间之后,10列无法满足需求,需要为原来的表再添加5列数据
1.一对多
看下面的表结构:
UserInfo:
UserType:
其中UserInfor表中的user_type_id字段即为外键关联到UserType的id字段,UserType中的id=2对应多条UserInfo表中的user_type_id,此为一对多
2、多对多
应用场景:
1.某个作者出了多本书,某本书可能是由多个作者编写的,这样的话就用到了多对多,一对多是无法实现的
2.在Zabbix监控的中,有好几个组比如:运维组、研发组、测试组、DBA组
A用户可不可以在多个组里呢?一个组里是不是可以有多个人?当然可以,但是用第一种方法(1对多)可以实现吗?不可以!
那怎么解决这个问题呢,需要第三张表把两张表关联起来。django内置的models.ManyToManyField方法帮我们自动生成了这个第三张表。
先看下实例代码:
class UserGroup(models.Model):
group_name = models.CharField(max_length=64) class User(models.Model):
name = models.CharField(max_length=64)
email = models.CharField(max_length=64)
mobile = models.CharField(max_length=64)
user_user_group = models.ManyToManyField('UserGroup') def __str__(self):
return self.name
先看下第三张表的表结构:
这样我们就可以通过这张表对另外两张表做关联啦,是不是很有用呀。
3、一对一
先看下实例代码:
class AssetInfo(models.Model):
asset_type_choices = (
('server', u'服务器'),
('switch', u'交换机'),
)
asset_type = models.CharField(choices=asset_type_choices,max_length=64,default='server')
sn_id = models.CharField(u'资产SN号',max_length=64,unique=False,auto_created=True)
cert = models.CharField(max_length=128)
location = models.CharField(max_length=128)
provider = models.CharField(max_length=64)
datacenter = models.CharField(max_length=64)
floor = models.IntegerField(blank=True,null=True)
cab = models.CharField(max_length=32)
p_cab = models.IntegerField(blank=True,null=True)
department = models.CharField(max_length=32)
status = models.CharField(max_length=32)
create_date = models.DateTimeField(blank=True,auto_now_add=True)
update_date = models.DateTimeField(blank=True,auto_now=True) def __unicode__(self):
return 'id:%s name:%s' %(self.id,self.name) class Server(models.Model):
asset = models.OneToOneField('AssetInfo')
hostname = models.CharField(max_length=32)
mac_a = models.CharField(max_length=32)
ip_a = models.GenericIPAddressField(u'内网IP',blank=True,null=True)
netmask = models.GenericIPAddressField(u'子网掩码',blank=True,null=True)
memory = models.CharField(max_length=32)
cpu_core = models.CharField(max_length=50)
product = models.CharField(max_length=50)
sn = models.CharField(max_length=50)
disk = models.CharField(max_length=50)
os_version = models.CharField(max_length=50)
create_date = models.DateTimeField(blank=True,auto_now_add=True)
update_date = models.DateTimeField(blank=True,auto_now=True) def __unicode__(self):
return 'id:%s hostname:%s'(self.id,self.hostname)
一对一不是数据库的一个连表操作,而是Django独有的一个连表操作!如下图
assetinfo表:
server表:
那么如果在创建一个资产还是用2,3就会报错,如果我们再添加一个资产字段,id=4, 在server表中添加一行数据,指定外键asset_id为4既可以
相当于我们伪造出来了一个1对1的连表操作
新增server代码:
obj = models.Server(
asset_id = '4',
hostname = 'dbserver',
mac_a = 'FA:16:3E:38:BD:30',
ip_a = '192.168.1.3',
netmask = '255.255.255.0',
memory = '32G',
cpu_core = 8,
product = 'DELL',
sn = 'DdsaAfsdw4rd',
disk = '2T',
os_version = 'Red hat 6.4(Final)',
)
obj.save()
Models 操作表
1.基本操作
1.1、增加
# 增
#
# models.Tb1.objects.create(c1='xx', c2='oo') 增加一条数据,可以接受字典类型数据 **kwargs
#
# obj = models.Tb1(c1='xx', c2='oo') 先创建一个对象,然后在save下
# obj.save()
'''
#models
class User(models.Model):
username = models.CharField(max_length=64)
password = models.CharField(max_length=64) def __str__(self):
return self.username
#views
def index(request):
models.User.objects.create(username='Jasonwang',password='6666')
print(models.User.objects.all()) obj = form.ImportForm(request.POST)
return render(request,'home/index.html',{'obj':obj})
结果:
<QuerySet [<User: Jasonwang>]>
----------------------------------(**kwargs)-------------------------------------------
我们创建的时候可以通过字典的方式来创建:
>>> import os
>>> os.environ['DJANGO_SETTINGS_MODULE'] = 'djano19.settings'
>>> import django
>>> django.setup()
>>> from app02.models import User
>>> dic = {'username':'jack','password':'123'}
>>> User.objects.create(**dic)
<User: jack>
例子:
获取用户提交的数据来创建用户:
#hmtl
<form action="/useradd/" method="post">
<p>用户名:{{ obj.username }}</p>
<p>密码:{{ obj.password }}</p>
<input type="submit" value="submit"/>
</form>
#views
from django.shortcuts import render
from django import forms
from app02 import models,form
from app02.form import AccountForm
def useradd(request):
if request.method == 'POST':
objPOST = AccountForm(request.POST)
if objPOST.is_valid():
user_input = objPOST.clean()
print(user_input)
models.User.objects.create(**user_input) #这里直接通过**加上用户的输入即可,因为用户的输入时字典类型的
print(models.User.objects.all())
return render(request,'account/useradd.html',{'obj':objPOST})
else:
objGet = AccountForm() #创建了这个对象
return render(request, 'account/useradd.html',{'obj': objGet})
##app02.form
from django import forms
from app02 import models
import json class ImportForm(forms.Form):
def __init__(self,*arg,**kwargs):
super(ImportForm,self).__init__(*arg,**kwargs)
self.fields['admin'].widget.choices = models.User.objects.all().values_list('id','username') admin = forms.IntegerField(
widget=forms.Select()
) class AccountForm(forms.Form):
username = forms.CharField(required=True, error_messages={'required': '用户名不能为空.'})
password = forms.CharField(required=True,
min_length=6,
max_length=10,
error_messages={'required': '密码不能为空.', 'min_length': "至少6位"})
-------------------------------------
#结果
--用户输入:{'username': 'lucy', 'password': '123456'}
--print(models.UserInfo.objects.all()) 返回值
<QuerySet [<User: Jasonwang>, <User: jack>, <User: Jasonwang>, <User: Jasonwang>, <User: lucy>]> #注这里我们是通过__self__方法进行输出了否则是对象!
1.2、查
惰性机制:
所谓惰性机制:
models.UserInfo.objects.all()只是返回了一个QuerySet(查询结果集对象),并不会马上执行sql,而是当调用QuerySet的时候才执行。
QuerySet特点:1 可迭代的 2.可切片
一 查询相关API: <1>get(**kwargs): 返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。 <2>all(): 查询所有结果 <3>filter(**kwargs): 它包含了与所给筛选条件相匹配的对象 <4>exclude(**kwargs): 它包含了与所给筛选条件不匹配的对象 <5>order_by(*field): 对查询结果排序 <6>reverse(): 对查询结果反向排序 <7>distinct(): 从返回结果中剔除重复纪录 <8>values(*field): 返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一 系列 model的实例化对象,而是一个可迭代的字典序列<br> [{'user': 'uesr', 'user_type__caption': '普通用户'}, {'user': 'uesr', 'user_type__caption': '普通用户'}] <9>values_list(*field): 它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列 -----【(),(),()】 <10>count(): 返回数据库中匹配查询(QuerySet)的对象数量。 <11>first(): 返回第一条记录,等价于[:1][0] <12>last(): 返回最后一条记录,等价于[::1][0] <13>exists(): 如果QuerySet包含数据,就返回True,否则返回False。
先记住一句话,values是列表里面是字典,value_list是列表里面是元组
# 查
#
##说明 get方法得到的是instance实例,filter(id='xx')得到的是queryset
# models.Tb1.objects.get(id=123) # 获取单条数据,不存在则报错(不建议使用)
# models.Tb1.objects.all() # 获取全部
# models.Tb1.objects.filter(name='seven') # 获取指定条件的数据
#models.UserInfo.objects.all().values('password') #获取指定列的值,可以传多个参数!
<QuerySet [{'password': '6666'}, {'password': '123'}, {'password': '123456'}]>
#models.UserInfo.objects.all().values_list('password') #获取指定列的值,可以传多个参数!
>>> User.objects.all().values_list('password')
<QuerySet [('6666',), ('123',), ('123456',)]>
#在前端写choices里,生成select标签就可以通过它来获取
models.UserInfo.objects.all().values_list('id','username')
>>> User.objects.all().values_list('id','username')
他输出的是一个元组如下<QuerySet [(8, 'Jasonwang'), (9, 'jack'), (12, 'lucy')]>
'''
#实例
#form
------------------------------------------------------------------------------------------------------
from django import forms
from app02 import models
import json class ImportForm(forms.Form):
def __init__(self,*arg,**kwargs):
super(ImportForm,self).__init__(*arg,**kwargs)
self.fields['admin'].widget.choices = models.User.objects.all().values_list('id','username') admin = forms.IntegerField(
widget=forms.Select()
------------------------------------------------------------------------------------------------------ #views
------------------------------------------------------------------------------------------------------
def index1(request):
obj = form.ImportForm(request.POST)
return render(request,'home/index1.html',{'obj':obj})
------------------------------------------------------------------------------------------------------ #html
------------------------------------------------------------------------------------------------------
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>可更新下拉菜单</h1>
<p>{{ obj.admin }}</p>
</body>
</html>
效果如下:(Form获取通过Model获取数据生成Select下拉菜单)
补充增加(重要):
django的get方法是从数据库的取得一个匹配的结果,返回一个对象,如果记录不存在的话,它会报错。
django的filter方法是从数据库的取得匹配的结果,返回一个对象列表,如果记录不存在的话,它会返回[]。
1.3、删
# 删
#
# models.Tb1.objects.filter(name='seven').delete() # 删除指定条件的数据
1.4、改
# 改
# models.Tb1.objects.filter(name='seven').update(gender='0') # 将指定条件的数据更新,均支持 **kwargs
#
‘’‘
----------------------------------(**kwargs)-------------------------------------------
更新和添加同理
#views
def useradd(request):
obj = AccountForm.UserAdd(request.POST)
if request.method == 'POST':
if obj.is_valid():
user_input = obj.clean()
update_username = user_input['username']
#先找到用户然后更新他
models.UserInfo.objects.filter(username=update_username).update(**user_input)
print models.UserInfo.objects.all()
return render(request,'account/useradd.html',{'obj':obj})
return render(request,'account/useradd.html',{'obj':obj})
’‘’ # obj = models.Tb1.objects.get(id=1) 通过创建对象,修改save修改单条数据
# obj.c1 = '111'
# obj.save()
2、进阶操作(了不起的双下划线)
# 获取个数
#
>>> models.Server.objects.filter(hostname='webserver').count()
1
# 大于,小于
>>> models.Server.objects.filter(id__gt=1) # 获取id大于1的值
<QuerySet [<Server: Server object>, <Server: Server object>, <Server: Server object>, <Server: Server object>, <Server: Server object>, <Server: Server object>, <Server: Server object>, <Server: Server object>, <Server: Server object>, <Server: Server object>, <Server: Server object>, <Server: Server object>, <Server: Server object>, <Server: Server object>, <Server: Server object>, <Server: Server object>, <Server: Server object>, <Server: Server object>, <Server: Server object>, <Server: Server object>, '...(remaining elements truncated)...']>
>>> models.Server.objects.filter(id__lt=10) # 获取id小于10的值
<QuerySet [<Server: Server object>, <Server: Server object>, <Server: Server object>, <Server: Server object>, <Server: Server object>, <Server: Server object>, <Server: Server object>, <Server: Server object>]>
>>> models.Server.objects.filter(id__gt=3,id__lt=10) # 获取id大于3 且 小于10的值
<QuerySet [<Server: Server object>, <Server: Server object>, <Server: Server object>, <Server: Server object>, <Server: Server object>, <Server: Server object>]>
>>>
# in
#
>>> models.Server.objects.filter(id__in=[3,4,5]) # 获取id等于3、4、5的数据
<QuerySet [<Server: Server object>, <Server: Server object>, <Server: Server object>]>
# not in
>>> models.Server.objects.exclude(id__in=[3,4,5])
<QuerySet [<Server: Server object>, <Server: Server object>, <Server: Server object>, <Server: Server object>, <Server: Server object>, <Server: Server object>, <Server: Server object>, <Server: Server object>, <Server: Server object>, <Server: Server object>, <Server: Server object>, <Server: Server object>, <Server: Server object>, <Server: Server object>, <Server: Server object>, <Server: Server object>, <Server: Server object>, <Server: Server object>, <Server: Server object>, <Server: Server object>, '...(remaining elements truncated)...']>
# contains(和数据中like语法相同)
#
>>> models.Server.objects.filter(hostname__contains="web")
<QuerySet [<Server: Server object>]>
>>> models.Server.objects.filter(hostname__icontains="web") # icontains大小写不敏感
<QuerySet [<Server: Server object>]>
>>> models.Server.objects.exclude(hostname__icontains="db")
<QuerySet [<Server: Server object>]>
# range
#
>>> models.Server.objects.filter(id__range=[2,6]) # 范围bettwen and
<QuerySet [<Server: Server object>, <Server: Server object>, <Server: Server object>, <Server: Server object>, <Server: Server object>]>
# 其他类似
#
# startswith,istartswith, endswith, iendswith, #以什么开始,以什么结束,和上面一样带i的是大小写不敏感的
#排序
# order by
#
#
>>> models.Server.objects.filter(hostname='dbserver').order_by('id')# asc正序
>>> models.Server.objects.filter(hostname='dbserver').order_by('-id')# desc反序
#分页时使用
# limit 、offset
#
>>> models.Server.objects.all()[10:20]#取所有数据的10条到20条,分页的时候用的到
#分组使用
# group by
from django.db.models import Count, Min, Max, Sum
>>> c = models.Server.objects.all().values('id').annotate(c=Count('hostname'))
>>> print(c.query)
SELECT "app01_server"."id", COUNT("app01_server"."hostname") AS "c" FROM "app01_server" GROUP BY "app01_server"."id"
分组使用实例:
model
class Score(models.Model):
name = models.CharField(max_length=64)
scores = models.IntegerField(max_length=3) def __str__(self):
return self.name
>>> print(models.Score.objects.all().values('name').annotate(cnum=Count('scores')))
<QuerySet [{'name': 'eric', 'cnum': 1}, {'name': 'jason', 'cnum': 1}, {'name': 'wade', 'cnum': 1}, {'name': 'william', 'cnum': 1}]>
所以:我们可以通过:value(‘name’).annotate(content=Count('scores')) 或者annotate中参数可以为个数、Count、最小值Min、最大值Max、合Sum、来进行输出
3.一对一操作
models:
class AssetInfo(models.Model):
asset_type_choices = (
('server', u'服务器'),
('switch', u'交换机'),
)
asset_type = models.CharField(choices=asset_type_choices,max_length=64,default='server')
sn_id = models.CharField(u'资产SN号',max_length=64,unique=False,auto_created=True)
cert = models.CharField(max_length=128)
location = models.CharField(max_length=128)
provider = models.CharField(max_length=64)
datacenter = models.CharField(max_length=64)
floor = models.IntegerField(blank=True,null=True)
cab = models.CharField(max_length=32)
p_cab = models.IntegerField(blank=True,null=True)
department = models.CharField(max_length=32)
status = models.CharField(max_length=32)
create_date = models.DateTimeField(blank=True,auto_now_add=True)
update_date = models.DateTimeField(blank=True,auto_now=True) def __str__(self):
return 'id:%s name:%s' %(self.id,self.datacenter) class Server(models.Model):
asset = models.OneToOneField('AssetInfo')
hostname = models.CharField(max_length=32)
mac_a = models.CharField(max_length=32)
ip_a = models.GenericIPAddressField(u'内网IP',blank=True,null=True)
netmask = models.GenericIPAddressField(u'子网掩码',blank=True,null=True)
memory = models.CharField(max_length=32)
cpu_core = models.CharField(max_length=50)
product = models.CharField(max_length=50)
sn = models.CharField(max_length=50)
disk = models.CharField(max_length=50)
os_version = models.CharField(max_length=50)
create_date = models.DateTimeField(blank=True,auto_now_add=True)
update_date = models.DateTimeField(blank=True,auto_now=True) def __self__(self):
return 'id:%s hostname:%s'(self.id,self.hostname)
一对一models
>>> import os
>>> os.environ['DJANGO_SETTINGS_MODULE'] = 'mysite.settings'
>>> import django
>>> django.setup()
>>> from app01 import models
>>> asset_info_obj = models.AssetInfo.objects.filter(id=2)
>>> print(asset_info_obj)
<QuerySet [<AssetInfo: id:2 name:兆维>]>
>>> asset_info_obj = models.AssetInfo.objects.filter(id=2).first()
>>> print(asset_info_obj)
id:2 name:兆维
>>> print(asset_info_obj.get_asset_type_display())
服务器
>>> print(asset_info_obj.server.hostname)
webserver
>>> asset_info_obj = models.AssetInfo.objects.filter(id=2).values('location','department').first() >>> print(asset_info_obj.keys())
dict_keys(['location', 'department'])
>>> print(asset_info_obj.values())
dict_values(['北京', '运维部'])
asset表数据库内容如下:
4、连表操作(了不起的双下划线)一对多
类似一对一
1、搜索条件使用 __ 连接
2、获取值时使用 . 连接
一对多操作
from django.db import models # Create your models here.
class UserGroup(models.Model):
caption = models.CharField(max_length=64) def __str__(self):
return self.caption class Host(models.Model):
hostname = models.CharField(max_length=64)
ip = models.CharField(max_length=64)
user_group = models.ForeignKey('UserGroup') def __str__(self):
return self.hostname
创建UserGroup字段:
>>> models.UserGroup.objects.create(caption='SA')
<UserGroup: SA>
>>> models.UserGroup.objects.create(caption='DBA')
<UserGroup: DBA>
>>> models.UserGroup.objects.create(caption='DEV')
<UserGroup: DEV>
添加Host字段
>>> models.Host.objects.create(hostname='jason.wang.com',ip='1.2.3.4',user_group=models.UserGroup.objects.get(id=1))
<Host: jason.wang.com>
>>> models.UserGroup.objects.get(id=1)
<UserGroup: SA>
>>> models.UserGroup.objects.filter(id=1)
<QuerySet [<UserGroup: SA>]>
我们需要根据对象去找到外键ID对一个的值添加!
实例:
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/app02/index2/" method="post">
<p>主机名:{{ obj.hostname }}</p>
<p>主机IP:{{ obj.ip }}</p>
<p>所属组:{{ obj.group }}</p>
<input type="submit" value="添加主机"/>
</form>
</body>
</html>
form表单
class ImportForm(forms.Form):
def __init__(self,*arg,**kwargs):
super(ImportForm,self).__init__(*arg,**kwargs)
self.fields['admin'].widget.choices = models.User.objects.all().values_list('id','username') admin = forms.IntegerField(
widget=forms.Select()
)
group_type_choice = (
(0, u'SA'),
(1, u'DBA'),
(2, u'DEV'),
)
group = forms.CharField(
# widget=forms.Select()
widget=forms.widgets.Select(choices=group_type_choice,attrs={'class':'form-control'})
)
hostname = forms.CharField()
ip = forms.GenericIPAddressField()
views重要,仔细看里面的解释(回顾时需要注意看里面的注释)
def index2(request):
if request.method == 'POST':
objPOST = form.ImportForm(request.POST)
if objPOST.is_valid():
data = objPOST.clean()
'''
#两种方式
#第一种方式先获取对象,通过对象的方式添加!
grop_obj = models.UserGroup.objects.get(id=data['group'])
print grop_obj
models.Host.objects.create(hostname=data['hostname'],
ip=data['ip'],
user_group=grop_obj)
#这里需要注意group_obj是一个对象原因如下:
[在Model里咱们的user_group = user_group = models.ForeignKey('UserGroup') 这里他对应了一个对象,所以我们添加的时候添加对象即可,咱们从前端传过来的时候不是一个对象,所以咱们需要先获取一个对象!]
'''
print(data)
"""
{'ip': '1.1.1.1', 'group': '1', 'hostname': 'webserver'} """
#第二种方式就简单了
models.Host.objects.create(hostname=data['hostname'],
ip=data['ip'],
user_group_id=data['group'])
#因为在存储的时候Django后默认在ForeignKey后面加一个_id所以我们给他加一个_id就可以直接添加了!本质上第一种方式也是通过拼接 return render(request,'home/index2.html',{'obj':objPOST})
else:
objGet = form.ImportForm()
return render(request,'home/index2.html',{'obj':objGet})
总结对于一对多,添加字段的方式两种具体如下:
>>> models.Host.objects.create(hostname='jason.wang.com',ip='1.2.3.4',user_group=models.UserGroup.objects.get(id=1))
<Host: jason.wang.com>
>>> models.Host.objects.create(hostname='jason.wang.com',ip='1.2.3.4',user_group_id=2)
<Host: jason.wang.com>
在上面的基础上,添加展示信息:
views:
def index2(request):
if request.method == 'POST':
objPOST = form.ImportForm(request.POST)
host_list = models.Host.objects.all() #获取所有的服务器列表然后展示
if objPOST.is_valid():
data = objPOST.clean()
'''
#两种方式
#第一种方式先获取对象,通过对象的方式添加!
grop_obj = models.UserGroup.objects.get(id=data['group'])
print grop_obj
models.Host.objects.create(hostname=data['hostname'],
ip=data['ip'],
user_group=grop_obj)
#这里需要注意group_obj是一个对象原因如下:
[在Model里咱们的user_group = user_group = models.ForeignKey('UserGroup') 这里他对应了一个对象,所以我们添加的时候添加对象即可,咱们从前端传过来的时候不是一个对象,所以咱们需要先获取一个对象!]
'''
print(data)
"""
{'ip': '1.1.1.1', 'group': '1', 'hostname': 'webserver'} """
#第二种方式就简单了
models.Host.objects.create(hostname=data['hostname'],
ip=data['ip'],
user_group_id=data['group'])
#因为在存储的时候Django后默认在ForeignKey后面加一个_id所以我们给他加一个_id就可以直接添加了!本质上第一种方式也是通过拼接 return render(request,'home/index2.html',{'obj':objPOST,'host_list':host_list})
else:
objGet = form.ImportForm()
return render(request,'home/index2.html',{'obj':objGet})
html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/app02/index2/" method="post">
<p>主机名:{{ obj.hostname }}</p>
<p>主机IP:{{ obj.ip }}</p>
<p>所属组:{{ obj.group }}</p>
<input type="submit" value="添加主机"/>
</form>
<table>
{% for item in host_list %}
<tr>
<td>{{ item.hostname }}</td>
{#这里存储的是ID,因为user_group是一个对象(一行数据),我们可以根据对象.caption来取出他对一个的中文#}
<td>{{ item.user_group.caption }}</td>
</tr>
{% endfor %}
</table>
</body>
</html>
效果如下图:
在上面的基础上修改为查询的时候:
request只支持两种方式POST或者GET
仅修改views即可
def index2(request):
val = request.GET.get('ip')
print(val)
host_list = models.Host.objects.filter(ip=val)
if request.method == 'POST':
objPOST = form.ImportForm(request.POST)
# host_list = models.Host.objects.all() #获取所有的服务器列表然后展示
host_list = models.Host.objects.filter(ip=val)
if objPOST.is_valid():
data = objPOST.clean()
'''
#两种方式
#第一种方式先获取对象,通过对象的方式添加!
grop_obj = models.UserGroup.objects.get(id=data['group'])
print grop_obj
models.Host.objects.create(hostname=data['hostname'],
ip=data['ip'],
user_group=grop_obj)
#这里需要注意group_obj是一个对象原因如下:
[在Model里咱们的user_group = user_group = models.ForeignKey('UserGroup') 这里他对应了一个对象,所以我们添加的时候添加对象即可,咱们从前端传过来的时候不是一个对象,所以咱们需要先获取一个对象!]
'''
print(data)
"""
{'ip': '1.1.1.1', 'group': '1', 'hostname': 'webserver'} """
#第二种方式就简单了
models.Host.objects.create(hostname=data['hostname'],
ip=data['ip'],
user_group_id=data['group'])
#因为在存储的时候Django后默认在ForeignKey后面加一个_id所以我们给他加一个_id就可以直接添加了!本质上第一种方式也是通过拼接 return render(request,'home/index2.html',{'obj':objPOST,'host_list':host_list})
else:
objGet = form.ImportForm()
return render(request,'home/index2.html',{'obj':objGet,'host_list':host_list})
效果如下图:
那我根据组怎么查询?
这里需要注意在拿数据的时候是用."点",但是在查询的时候需要用了不起的双下划线!
val = request.GET.get('usergroup')
host_list = models.Host.objects.filter(user_group__caption=val)
views
def index2(request):
# val = request.GET.get('ip')
val = request.GET.get('usergroup')
print(val)
# host_list = models.Host.objects.filter(ip=val)
host_list = models.Host.objects.filter(user_group__caption=val)
if request.method == 'POST':
objPOST = form.ImportForm(request.POST)
# host_list = models.Host.objects.all() #获取所有的服务器列表然后展示
host_list = models.Host.objects.filter(ip=val)
if objPOST.is_valid():
data = objPOST.clean()
'''
#两种方式
#第一种方式先获取对象,通过对象的方式添加!
grop_obj = models.UserGroup.objects.get(id=data['group'])
print grop_obj
models.Host.objects.create(hostname=data['hostname'],
ip=data['ip'],
user_group=grop_obj)
#这里需要注意group_obj是一个对象原因如下:
[在Model里咱们的user_group = user_group = models.ForeignKey('UserGroup') 这里他对应了一个对象,所以我们添加的时候添加对象即可,咱们从前端传过来的时候不是一个对象,所以咱们需要先获取一个对象!]
'''
print(data)
"""
{'ip': '1.1.1.1', 'group': '1', 'hostname': 'webserver'} """
#第二种方式就简单了
models.Host.objects.create(hostname=data['hostname'],
ip=data['ip'],
user_group_id=data['group'])
#因为在存储的时候Django后默认在ForeignKey后面加一个_id所以我们给他加一个_id就可以直接添加了!本质上第一种方式也是通过拼接 return render(request,'home/index2.html',{'obj':objPOST,'host_list':host_list})
else:
objGet = form.ImportForm()
return render(request,'home/index2.html',{'obj':objGet,'host_list':host_list})
效果如下:
总结:在添加的时候通过_id来建立关系、获取数据的时候通过.、如果在filter里面跨表查询的时候就得用两个下划线"__"
5.Model,多对多关联!
user_info_obj = models.UserInfo.objects.get(name=u'武沛齐')
user_info_objs = models.UserInfo.objects.all() group_obj = models.UserGroup.objects.get(caption='CEO')
group_objs = models.UserGroup.objects.all() # 添加数据
#group_obj.user_info.add(user_info_obj)
#group_obj.user_info.add(*user_info_objs) # 删除数据
#group_obj.user_info.remove(user_info_obj)
#group_obj.user_info.remove(*user_info_objs) # 添加数据
#user_info_obj.usergroup_set.add(group_obj)
#user_info_obj.usergroup_set.add(*group_objs) # 删除数据
#user_info_obj.usergroup_set.remove(group_obj)
#user_info_obj.usergroup_set.remove(*group_objs) # 获取数据
#print group_obj.user_info.all()
#print group_obj.user_info.all().filter(id=1) # 获取数据
#print user_info_obj.usergroup_set.all()
#print user_info_obj.usergroup_set.all().filter(caption='CEO')
#print user_info_obj.usergroup_set.all().filter(caption='DBA')
多对多关联操作
Models:
from django.db import models # Create your models here.
from django.db import models
class Author(models.Model):
name = models.CharField(max_length=100)
age = models.IntegerField() class Publisher(models.Model):
name = models.CharField(max_length=300)
num_awards = models.IntegerField() class Book(models.Model):
name = models.CharField(max_length=300)
pages = models.IntegerField()
price = models.DecimalField(max_digits=10, decimal_places=2)
rating = models.FloatField()
authors = models.ManyToManyField(Author)
publisher = models.ForeignKey(Publisher)
pubdate = models.DateField() class Store(models.Model):
name = models.CharField(max_length=300)
books = models.ManyToManyField(Book)
registered_users = models.PositiveIntegerField()
多对多插入数据方法:
在给Book表插入数据之前,
1.首先要添加Author表及Publisher表中的object,
2.添加Book表,authors字段无须添加
3.获取一条Author object
4.将获取的author object添加到Book表中去,具体过程如下:
>>> import os
>>> os.environ['DJANGO_SETTINGS_MODULE'] = 'djano19.settings'
>>> import django
>>> django.setup()
>>> from BookStore import models
>>> models.Author.objects.create(name='Jason',age=24)
<Author: Author object>
>>> models.Publisher.objects.create(name='FOX',num_awards=10)
<Publisher: Publisher object>
>>> author_obj = models.Author.objects.get(name='Jason')
>>> author_objs = models.Author.objects.all()
>>> models.Book.objects.create(name='black golden',pages=400,price=50,rating=0.8,)
>>> author_obj = models.Author.objects.get(name='Jason')
>>> models.Book.objects.create(name='black golden',pages=400,price=50,rating=0.8,publisher=models.Publisher.objects.get(id=1),pubdate='2016-09-06')
<Book: Book object>
>>> book_obj.authors.add(author_obj)
>>> book_objs = models.Book.objects.all()
>>>author_objs = models.Author.objects.all()
>>> book_obj.authors.add(*author_objs)
创建表之后可以看到django会自动生成两张关系表:
当我们按照上面的方法插入数据后会看到book_authors表中产生了对应关系,具体如下:
被关联表添加数据:
>>> book_obj = models.Book.objects.get(id=1)
>>> author_obj.book_set.add(book_obj)
第三张关联表book_authors会生成相应的id字段,如下图:
获取数据:
>>> print(book_obj.authors.all())
<QuerySet [<Author: Author object>, <Author: Author object>]>
>>> print(book_obj.authors.filter(id=1))
<QuerySet [<Author: Author object>]>
被关联表获取数据:
>>> print(author_obj.book_set.all())
<QuerySet [<Book: Book object>]>
>>> print(author_obj.book_set.filter(id=1))
<QuerySet [<Book: Book object>]>
>>> print(author_obj.book_set.all().filter(id=1))
<QuerySet [<Book: Book object>]>
删除数据:
>>> book_obj.authors.remove(author_obj)
>>> book_obj.authors.remove(*author_objs)
被关联表删除数据:
>>> author_obj.book_set.remove(book_obj)
>>> author_obj.book_set.remove(*book_objs)
此时第三张表中关联关系被删除,如下图
收集相关文档如下:
http://blog.csdn.net/hackerain/article/details/39838559
Django 之models进阶操作的更多相关文章
- web框架-(七)Django补充---models进阶操作及modelform操作
通过之前的课程我们可以对于Django的models进行简单的操作,今天了解下进阶操作和modelform: 1. Models进阶操作 1.1 字段操作 AutoField(Field) - int ...
- Django之Models进阶操作(字段属性)
字段属性详细介绍 一.字段 AutoField(Field) - int自增列,必须填入参数 primary_key=True BigAutoField(AutoField) - bigint自增列, ...
- python自动化之models 进阶操作二
################################################################## # PUBLIC METHODS THAT ALTER ATTRI ...
- Django中Model进阶操作
一.字段 AutoField(Field) - int自增列,必须填入参数 primary_key=True BigAutoField(AutoField) - bigint自增列,必须填入参数 pr ...
- Django之表高级操作
目录 一.如何开启自己的测试脚本? 二.对表数据的添加.更新.删除 1.create() 2.update() 3.delete() 4.查看执行的sql语句 三. 单表查询13个操作 返回Query ...
- Django中的ORM进阶操作
Django中的ORM进阶操作 Django中是通过ORM来操作数据库的,通过ORM可以很easy的实现与数据库的交互.但是仍然有几种操作是非常绕也特别容易混淆的.于是,针对这一块,来一个分类总结吧. ...
- Django之Models操作
一.字段 AutoField(Field) - int自增列,必须填入参数 primary_key=True BigAutoField(AutoField) - bigint自增列,必须填入参数 pr ...
- Django ORM models操作
title: Django ORM models操作 tags: Django --- Django ORM models操作 Django ORM基本操作 一.数据库的创建及增删改查 1 使用类创建 ...
- Django 二——models(admin、ORM),一对一、一对多、多对多操作,all、values、value_list的对比
内容概要 1.关系对象映射ORM 2.admin的配置(选修) 3.all().values().value_list()的对比 4.数据库操作(一对一.一对多.多对多) 5.HttpResponse ...
随机推荐
- elasticJob分片跑批
业务迅速发展带来了跑批数据量的急剧增加.单机处理跑批数据已不能满足需要,另考虑到企业处理数据的扩展能力,多机跑批势在必行.多机跑批是指将跑批任务分发到多台服务器上执行,多机跑批的前提是”数据分片”.e ...
- mock实例方法
1.Mockito.when(categoryService.queryTopCategory("1")).thenReturn(categories);//返回的是list列表, ...
- Java并发编程(十二)线程安全性的委托
在组合对象中如果每个组件都已经是线程安全的,是否需要再加一个额外的"线程安全层",需要视情况而定. final可以修饰未复制的属性,只要在静态代码块或者构造函数中赋值了即可. 独立 ...
- LeetCode543. Diameter of Binary Tree
Description Given a binary tree, you need to compute the length of the diameter of the tree. The dia ...
- Groovy基本类型与运算符
字符串 1.1字符串段落 def s = """Groovy Grails JAVA """ 输出结果: Groovy Grails JAV ...
- [浪风推荐]javascritp中倒计定时器和循环定时器
在javascritp中,有两个关于定时器的专用函数,分别为: 1.倒计定时器:timename=setTimeout(“function();”,delaytime); 2.循环定时器:timena ...
- 面向Internet的编程
面向Internet的编程 1994年秋天我返回工作时,这个公司的景象已经完全改变.他们决定Oak语言——跨平台的.安全的.易传输的代码——时理想的面向Internet的语言.同时他们在制作名为Web ...
- css 定位标签设置格式
td a { color: #3c8dbc; } td a:hover { color: #00bdd8; } 上例即为定位td下的a标签.即用来给表格中的链接,未访问时和hove ...
- iframe详解
如何查看是否为iframe *使用FireFox组件firebug->firepath 1.Top Window:可直接定位 2.iframe#i:根据id定位 定位方法: switch_to. ...
- OpenCV学习笔记五:opencv_legacy模块
opencv_legacy,顾名思义,该模块是用于兼容以前的opencv代码而设立的. 如果你希望用最新的opencv代码和特性,请勿使用该模块.