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

原文地址:https://www.cnblogs.com/jasonwang-2016/p/5867962.html