一对多:models.ForeignKey(其余表) 应用场景: |
1 一对多python
一对多表结构是为了解决空间浪费问题,经过一张数据库表去关联另一张数据库表来解决重复出现的字段,这样在这张表中只会存储相应的ID来代替相应的字段。数据库
为何是1对多呢?由于在第2张表里,金牌会员的ID=3,而在第3张表里有好2个3,即表示1对多。django
在Model中生成一对多表结构(models.py文件) app
例1:第1种一对多(默认关联id)函数
# 用户类型类
class UserType(models.Model): user_type = models.CharField(max_length=64) #用户信息类
class UserInfo(models.Model): username = models.CharField(max_length=64) email = models.CharField(max_length=32) # 外键关联 usertype对应着UserInfo表中的1列数据,他自动关联了UserType类
usertype = models.ForeignKey(UserType)
例2:第2种一对多(指定关联字段)post
# 业务线类
class Business(models.Model):
#设置为主键 nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) # 主机类,表示主机属于哪一条业务线
class Host(models.Model): hostname = models.CharField(max_length=16) # 括号中的参数可加引号,也能够不加引号,效果同样,to_field参数表示关联哪一个字段
business = models.ForeignKey(Business,to_field='nid')
例3:第3种一对多(多级外键关联)测试
#一对多 多级外键关联
class A(models.Model): name = models.CharField(max_length=16) def __unicode__(self): return self.name class UserGroup(models.Model): caption = models.CharField(max_length=32) obj_a = models.ForeignKey(A) def __unicode__(self): return self.caption class User(models.Model): username = models.CharField(max_length=32) user_group = models.ForeignKey(UserGroup) def __unicode__(self): return self.hostname
2 多对多spa
在Zabbix监控中会存在用户与用户组的概念,在这里同一我的能够属于多个用户组,同时同一个用户组也能够包括多我的。在这个场景中一对多的表关系结构是不能解决这个问题的,从而引出了多对多的概念。
为何是多对多呢?由于在对于CEO组,有两我的,即1个组包括了多我的;同时对于alex,他分别属于两个不一样组,那么认为这种关系就是多对多。
在Model中生成多对多表结构(models.py文件)
# model中的多对多 # 应用场景:用户与用户组(一个用户能够在多个组,同时一个组能够同时存在多个用户)
class UserGroup(models.Model): group_name = models.CharField(max_length=16) class User(models.Model): name = models.CharField(max_length=16) email = models.CharField(max_length=16) mobile = models.CharField(max_length=16) # 两张表创建多对多,django默认会生成一张数据库表来创建二者的关系
relationship = models.ManyToManyField(UserGroup)
注:对于多对多,在models.py中咱们只写了两个类,即生成两张数据库表,但两张代表显不能很好的表示多对多的关系,在这种状况下Django默认为咱们生成另一张表来创建这种关系,即用3张表来表示用户和用户组之间的关系。
3 一对一
一对一不是数据库的连表结构,而是Django独有的,他是在一对多的基础伪造出来的。即在一对多中限定某个指定的字段不能重复,一旦重复数据库报错,这样就至关于构造了一个一对一的连表关系。在上述一对多中,用户级别是可重复的,但在一对一关系中,一个用户级别只能对应一个用户,不容许重复。
应用场景:假设在一个公司的全部用户中,只有alex和eric能够登陆后台管理,那么这个场景就可使用一对一的连表关系。
在Model中生成一对一表结构(models.py文件)
# model中的一对一,至关于对一对多进行限制后产生的,由Django完成,且是Django独有的 # 应用场景:在不少用户中只有某些用户可以登陆,这时id不能重复,即同一个帐号ID不能出现屡次 # 下表为全部的用户信息表
class User(models.Model): name = models.CharField(max_length=16) email = models.CharField(max_length=16) mobile = models.CharField(max_length=16) # 下表为可以登陆的用户的用户名和密码
class admim(models.Model): username = models.CharField(max_length=64) password = models.CharField(max_length=64) # django自动完成关系的创建
user_info = models.OneToOneField(User)
1 一对多连表操做
实例1:在页面建立用户,同时在页面进行展现
models.py文件
#-*- coding:utf-8 -*-
from __future__ import unicode_literals from django.db import models #一对多连表关系 #用户组表
class UserGroup(models.Model): caption = models.CharField(max_length=32) def __unicode__(self): return self.caption #用户表
class User(models.Model): username = models.CharField(max_length=32)
#user_group为对象,对应UserGroup中的一行数据 user_group = models.ForeignKey(UserGroup) def __unicode__(self): return self.hostname
forms模块中的foreign.py文件
#!/usr/bin/env python #-*- coding:utf-8 -*-
__author__ = 'mcp'
from django import forms from app01 import models class UserForm(forms.Form): # 建立用户名
username = forms.CharField() # 建立用户组的两种方法
# 第1种方法:
# group = forms.IntegerField(widget=forms.Select())
# 第2种方法:用户组字段名=models.py中User类的用户组字段名+"_id"
# 由于外键user_group字段在User数据库表中字段名默认变成了"user_group_id",这样作的好处:username和user_group_id直接组成字典
# 传给Model,由于Model建立数据时是接受字典形式参数的,就是views/foreign.py中的all_data
user_group_id = forms.IntegerField(widget=forms.Select()) def __init__(self,*args,**kwargs): # 执行父类的构造方法
super(UserForm,self).__init__(*args,**kwargs) # 配合建立用户组的第1种方法使用,这里同时注意values_list方法的使用
# self.fields['group'].widget.choices = models.UserGroup.objects.all().values_list('id','caption')
# 配合建立用户组的第2种方法使用
self.fields['user_group_id'].widget.choices = models.UserGroup.objects.all().values_list('id','caption')
views模块中foreign.py文件
#!/usr/bin/env python #-*- coding:utf-8 -*-
__author__ = 'mcp'
from django.shortcuts import HttpResponse,render from app01 import models from app01.forms import foreign as ForeignForm # 建立用户组表
def create_user_group(request): # 建立用户组的类型,运行一次后注释,防止屡次生成
# models.UserGroup.objects.create(caption='CEO')
# models.UserGroup.objects.create(caption='CTO')
# models.UserGroup.objects.create(caption='COO')
return HttpResponse('ok') # 建立用户表
def create_user(request): # 将请求数据做为参数传递给UserForm,生成相应对象
obj = ForeignForm.UserForm(request.POST) # 判断请求类型是否为'POST'类型
if request.method == 'POST': # 进行From表单验证,验证其有效性
if obj.is_valid(): # 获取请求数据
all_data = obj.clean() # 把获取的数据存储到数据库,有3种方法
# 第1种方法(对象级别操做):先获取对象
# group_obj = models.UserGroup.objects.get(id=all_data['group'])
# 为何建立数据库表时,第二个参数(关联外键)user_group=group_obj?
# 这是由于在Model里user_group = models.ForeignKey('UserGroup'),这里user_group其实是关联了一个对象,
# 因此在传递参数时要传递相应的对象参数。
# models.User.objects.create(username=all_data['username'],user_group=group_obj)
# 第2种方法(数据库级别操做,这里注意Django默认给外键字段名加上了"_id")
# models.User.objects.create(username=all_data['username'],user_group_id=all_data['group'])
# 第3种方法(传字典参数,可是要注意form中已经组成了字典数据)
models.User.objects.create(**all_data) # 打印数据库中因此信息的条数
print models.User.objects.all().count() else: # 写上报错提示信息,form表单的验证信息,这里省略了
pass
# 获取全部的用户信息列表
user_list = models.User.objects.all() return render(request,'foreign/create_user.html',{'obj':obj,'user_list':user_list})
templates/foreign目录下的create_user.html文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/create_user/" method="post">
<p>用户名:{{ obj.username }}</p> {#<p>用户组:{{ obj.user_group }}</p>#} <p>用户组:{{ obj.user_group_id }}</p>
<input type="submit" value="submit"/>
</form>
<table> {% for item in user_list %} <tr>
<td>{{ item.username }}</td>
{#注意此处的操做,user_group是1个对象(表示数据库中一行数据),而用户组在数据库中是按ID存储的,因此要转换成中文,注意模板中的.号操做#}
<td>{{ item.user_group.caption }}</td>
</tr> {% endfor %} </table>
</body>
</html>
运行效果以下图所示:
实例2:在页面查询用户,同时在页面展现该用户的相关信息
在实例1的基础上,修改views模块中foreign.py文件便可
#!/usr/bin/env python #-*- coding:utf-8 -*-
__author__ = 'mcp'
from django.shortcuts import HttpResponse,render from app01 import models from app01.forms import foreign as ForeignForm # 建立用户组表
def create_user_group(request): # 建立用户组的类型,运行一次后注释,防止屡次生成
# models.UserGroup.objects.create(caption='CEO')
# models.UserGroup.objects.create(caption='CTO')
# models.UserGroup.objects.create(caption='COO')
return HttpResponse('ok') # 建立用户表
def create_user(request): # 将请求数据做为参数传递给UserForm,生成相应对象
obj = ForeignForm.UserForm(request.POST) # 判断请求类型是否为'POST'类型
if request.method == 'POST': # 进行From表单验证,验证其有效性
if obj.is_valid(): # 获取请求数据
all_data = obj.clean() # 把获取的数据存储到数据库,有3种方法
# 第1种方法(对象级别操做):先获取对象
# group_obj = models.UserGroup.objects.get(id=all_data['group'])
# 为何建立数据库表时,第二个参数(关联外键)user_group=group_obj?
# 这是由于在Model里user_group = models.ForeignKey('UserGroup'),这里user_group其实是关联了一个对象,
# 因此在传递参数时要传递相应的对象参数。
# models.User.objects.create(username=all_data['username'],user_group=group_obj)
# 第2种方法(数据库级别操做,这里注意Django默认给外键字段名加上了"_id")
# models.User.objects.create(username=all_data['username'],user_group_id=all_data['group'])
# 第3种方法(传字典参数,可是要注意form中已经组成了字典数据)
models.User.objects.create(**all_data) # 打印数据库中因此信息的条数
print models.User.objects.all().count() else: # 写上报错提示信息,form表单的验证信息,这里省略了
pass
# 根据输入的用户名,查找该用户所在的组
# 例如URL中输入http://127.0.0.1:8000/create_user/?user=alex,表示获取数据库中username='alex'的相关数据
# 获取get请求中user的值,例如user='alex',那么下面的val='alex'
val = request.GET.get('user') # 获取数据库中对应字段username='val'的一行数据
user_list = models.User.objects.filter(username=val) return render(request,'foreign/create_user.html',{'obj':obj,'user_list':user_list})
运行效果以下图所示:
实例3:在页面查询用户组,同时在页面展现该用户组的用户
在实例1的基础上,修改views模块中foreign.py文件便可
#!/usr/bin/env python #-*- coding:utf-8 -*-
__author__ = 'mcp'
from django.shortcuts import HttpResponse,render from app01 import models from app01.forms import foreign as ForeignForm # 建立用户组表
def create_user_group(request): # 建立用户组的类型,运行一次后注释,防止屡次生成
# models.UserGroup.objects.create(caption='CEO')
# models.UserGroup.objects.create(caption='CTO')
# models.UserGroup.objects.create(caption='COO')
return HttpResponse('ok') # 建立用户表
def create_user(request): # 将请求数据做为参数传递给UserForm,生成相应对象
obj = ForeignForm.UserForm(request.POST) # 判断请求类型是否为'POST'类型
if request.method == 'POST': # 进行From表单验证,验证其有效性
if obj.is_valid(): # 获取请求数据
all_data = obj.clean() # 把获取的数据存储到数据库,有3种方法
# 第1种方法(对象级别操做):先获取对象
# group_obj = models.UserGroup.objects.get(id=all_data['group'])
# 为何建立数据库表时,第二个参数(关联外键)user_group=group_obj?
# 这是由于在Model里user_group = models.ForeignKey('UserGroup'),这里user_group其实是关联了一个对象,
# 因此在传递参数时要传递相应的对象参数。
# models.User.objects.create(username=all_data['username'],user_group=group_obj)
# 第2种方法(数据库级别操做,这里注意Django默认给外键字段名加上了"_id")
# models.User.objects.create(username=all_data['username'],user_group_id=all_data['group'])
# 第3种方法(传字典参数,可是要注意form中已经组成了字典数据)
models.User.objects.create(**all_data) # 打印数据库中因此信息的条数
print models.User.objects.all().count() else: # 写上报错提示信息,form表单的验证信息,这里省略了
pass
# 根据输入的用户组,查找该组的全部用户信息
# http://127.0.0.1:8000/create_user/?usergroup=CEO
# 获取输入的用户组信息
val = request.GET.get('usergroup') # 跨表查询,双下划线
user_list = models.User.objects.filter(user_group__caption=val) return render(request,'foreign/create_user.html',{'obj':obj,'user_list':user_list})
运行效果以下图所示:
实例4:一对多连表关系中的多级关联
models.py文件
#/usr/bin/env python #-*- coding:utf-8 -*-
from __future__ import unicode_literals from django.db import models # Create your models here. #一对多连表关系中的多级关联 #用户类型表
class UserType(models.Model): type_list = models.CharField(max_length=64,null=True,blank=True) def __unicode__(self): return self.type_list # 用户组表
class UserGroup(models.Model): caption = models.CharField(max_length=32) user_type = models.ForeignKey('UserType') def __unicode__(self): return self.caption # 用户表
class User(models.Model): username = models.CharField(max_length=32) user_group = models.ForeignKey('UserGroup') def __unicode__(self): return self.username
views模块中foreign.py文件
#!/usr/bin/env python #-*- coding:utf-8 -*-
__author__ = 'mcp'
from django.shortcuts import HttpResponse,render from app01 import models from app01.forms import foreign as ForeignForm #!/usr/bin/env python #-*- coding:utf-8 -*-
__author__ = 'mcp'
from django.shortcuts import HttpResponse,render from app01 import models from app01.forms import foreign as ForeignForm def create_user_group(request): #添加用户类型
models.UserType.objects.create(type_list='金牌会员') models.UserType.objects.create(type_list='银牌会员') models.UserType.objects.create(type_list='普通会员') #添加用户组
models.UserGroup.objects.create(caption='CEO',user_type_id=1) models.UserGroup.objects.create(caption='CTO',user_type_id=2) models.UserGroup.objects.create(caption='COO',user_type_id=3) return HttpResponse('OK') def create_user(request): obj = ForeignForm.UserForm(request.POST) if request.method == 'POST': if obj.is_valid(): all_data = obj.clean() #先获取对象,而后把对象做为参数
group_obj = models.UserGroup.objects.get(id=all_data['user_group']) models.User.objects.create(username=all_data['username'],user_group=group_obj) # 测试1:获取全部的用户信息表
# user_list = models.User.objects.all()
#测试2:从URL中获取请求的信息
val = request.GET.get('usertype') # 注意跨表多级查询外键时,双下划线的使用
user_list = models.User.objects.filter(user_group__user_type__type_list=val) return render(request,'foreign/create_user.html',{'obj':obj,'user_list':user_list})
forms模块中foreign.py文件
#!/usr/bin/env python #-*- coding:utf-8 -*-
__author__ = 'mcp'
from django import forms from app01 import models class UserForm(forms.Form): username = forms.CharField() user_group = forms.IntegerField(widget=forms.Select()) user_type = forms.IntegerField(widget=forms.Select()) def __init__(self,*args,**kwargs): super(UserForm,self).__init__(*args,**kwargs) self.fields['user_group'].widget.choices = models.UserGroup.objects.all().values_list('id','caption') self.fields['user_type'].widget.choices = models.UserType.objects.all().values_list('id','type_list')
templates/foreign目录下的create_user.html文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/create_user/" method="post">
<p>用户名:{{ obj.username }}</p>
<p>用户组:{{ obj.user_group }}</p>
<p>用户类型{{ obj.user_type }}</p>
<input type="submit" value="submit"/>
</form>
<table> {% for item in user_list %} <tr>
<td>{{ item.username }}</td>
<td>{{ item.user_group.caption }}</td>
<td>{{ item.user_group.user_type.type_list }}</td>
</tr> {% endfor %} </table>
</body>
</html>
测试1和测试2运行结果分别以下图所示:(在实例4的多级关联中,实际上用户组合用户类型是已经绑定死了的,不能选择,例如加入用户组是CEO,那么用户类型就是金牌会员,不能选择)
一对多小结: 五、在外键的多级关联中,在数据库中查询数据时,下划线能够连着使用 |
参考资料:
http://www.cnblogs.com/wupeiqi/articles/5246483.html
http://www.cnblogs.com/luotianshuai/p/5301343.html