python--第二十三天总结(一对多和多对多)
Django 的 ORM 有多种关系:一对一,多对一,多对多。
操作数据表总的来说就是:
一对一和一对多
1、查找数据使用 __ 连接
2、获取数据时使用 . 连接
前提条件-正向和反向的定义:
正向:基于存在ForeignKey或ManyToManyField 字段的表查找为正向
反向:基于不存在ForeignKey或ManyToManyField表查找为反向
#反向查询
_set
注意:xx_set中的xx为小写的表名
例子如下:
#-*- coding:utf-8 -*-
from __future__ import unicode_literals from django.db import models # Create your models here. from django.db import models class UserType(models.Model):
caption = models.CharField(max_length=32) class UserInfo(models.Model):
user_type = models.ForeignKey(UserType)# user_type对象中封装id,caption
username = models.CharField(max_length=32)
age = models.IntegerField() class MyUser(models.Model):
username = models.CharField(max_length=32)
password = models.CharField(max_length=64) 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) # ########################### 多对多
class Host(models.Model):
hostname = models.CharField(max_length=32)
port = models.IntegerField() class HostAdmin(models.Model):
username = models.CharField(max_length=32)
email = models.CharField(max_length=32)
host = models.ManyToManyField(Host) #=========================== 方式二,自定义关联表 class Host1(models.Model):
hostname = models.CharField(max_length=32)
port = models.IntegerField() class HostAdmin1(models.Model):
username = models.CharField(max_length=32)
email = models.CharField(max_length=32)
host = models.ManyToManyField(Host1, through='HostRelation') class HostRelation(models.Model):
c1 = models.ForeignKey(Host1)
c2 = models.ForeignKey(HostAdmin1)
models.py
#-*- coding:utf-8 -*-
from django.shortcuts import render,HttpResponse # Create your views here. from app01 import models def user_type(request):
# dic = {'caption':'COO'}
#
# models.UserType.objects.create(**dic) return HttpResponse("OK") def user_info(request):
#添加
# dic = {"username":'xx',"age":88,'user_type_id':1}
# models.UserInfo.objects.create(**dic)
# result = models.UserInfo.objects.all() # for item in result:
# print item.username.item.age,item.user_type.caption #models.UserType.objects #反向查找
user_type_obj = models.UserType.objects.get(userinfo__username='alex')
print user_type_obj.caption
print user_type_obj.userinfo_set.all().count() return HttpResponse("OK") 2 def zan(request):
#女神实例
#new_list = models.News.objects.all() #大力赞的
new_list = models.News.objects.filter(favor__user_obj__username='dali') for item in new_list:
# item =>一条新闻
print '==========>'
print item.title
print item.content
print item.favor_set.all().count() return HttpResponse("OK") def host(request):
# models.HostAdmin.objects.create(username='dali',email='11@11.com')
# models.HostAdmin.objects.create(username='alex',email='22@11.com')
# models.HostAdmin.objects.create(username='root',email='33@11.com') #正向添加
"""
admin_obj = models.HostAdmin.objects.get(username='dali')
host_list = models.Host.objects.filter(id__lt=3)
admin_obj.host.add(*host_list)
"""
#反向添加
"""
host_obj = models.Host.objects.get(id=3)
admin_list = models.HostAdmin.objects.filter(id__gt=1)
host_obj.hostadmin_set.add(*admin_list)
""" """
#关联表
#一 方式增加
models.HostRelation.objects.create(
c1 = models.Host1.objects.get(id=1),
c2 = models.HostAdmin1.objects.get(id=2) ) #二 方式增加
models.HostRelation.objects.create(
c1_id = 2,
c2_id = 1,
)
"""
################################################
"""
#第一种 方式查询(区分正反向)
#正向查
admin_obj = models.HostAdmin.objects.get(id=1)
admin_obj.host.all() #反向查
host_obj = models.Host.objects.get(id=1)
print host_obj.hostadmin_set.all() """ #第二种 方式查询
#relation_list = models.HostRelation.objects.all()
relation_list = models.HostRelation.objects.filter(c2__username='dali')
for item in relation_list:
print item.c1.hostname
print item.c2.username return HttpResponse("OK")
views.py
一对多
增加
#一 以对象的方式增加
#二 以_id方式增加
查询:
#正向查(双下划线__)
#反向查 ( _set)
多对多
增加
#正向添加
admin_obj = models.HostAdmin.objects.get(username='dali')
host_list = models.Host.objects.filter(id__lt=3)
admin_obj.host.add(*host_list)
#反向添加
host_obj = models.Host.objects.get(id=3)
admin_list = models.HostAdmin.objects.filter(id__gt=1)
host_obj.hostadmin_set.add(*admin_list)
查询
#正向查
admin_obj = models.HostAdmin.objects.get(id=1)
admin_obj.host.all()
#反向查
host_obj = models.Host.objects.get(id=1)
print host_obj.hostadmin_set.all()
---------------------------------------------------------------------------------------------
关联关系字段 (Relationship fields)
例如,一本书由一家出版社出版,一家出版社可以出版很多书。一本书由多个作者合写,一个作者可以写很多书。
|
1
2
3
4
5
6
7
8
|
class Author(models.Model): name=models.CharField(max_length=20)class Publisher(models.Model): name=models.CharField(max_length=20)class Book(models.Model): name=models.CharField(max_length=20) pub=models.ForeignKey(Publisher) authors=models.ManyToManyField(Author) |
1.关联尚未定义的Model
如果你要与某个尚未定义的 model 建立关联 ,就使用 model 的名称,而不是使用 model 对象本身。
例子中,如果Publisher与Author在Book后面定义,需要写成下面的形式:
|
1
2
3
4
|
class Book(models.Model): name=models.CharField(max_length=20) pub=models.ForeignKey('Publisher') authors=models.ManyToManyField('Author') |
2.Model关联自身
Model可以与自身做多对一关系
|
1
2
3
|
class People(models.Model): name=models.CharField(max_length=20) leader=models.ForeignKey('self',blank=True,null=True) |
Model也可以与自身做多对多关系
|
1
2
|
class Person(models.Model): friends = models.ManyToManyField("self") |
默认情况下,这种关联关系是对称的,如果Person1是Person2的朋友,那么Person2也是Person1的朋友
|
1
2
3
4
5
6
7
|
p1=Person()p1.save()p2=Person()p2.save()p3=Person()p3.save()p1.friends.add(p2,p3) |
上述情况下,要查找p3的朋友,不用p3.person_set.all(),而直接用p3.friends.all()就可以了
如果想取消这种对称关系,将symmetrical设为False
|
1
2
|
class Person2(models.Model): friends=(models.ManyToManyField("self",symmetrical=False) |
这样查询p3的朋友,就需要p3.person_set.all()了
3.反向名称related_name
反向名称,用来从被关联字段指向关联字段。
注意,在你定义 抽象 model (abstract models) 时,你必须显式指定反向名称; 只有在你这么做了之后, 某些特别语法 (some special syntax) 才能正常使用。
#当关联同一个模型的字段大于一个时,要使用related_name参数来指定表名
|
1
2
3
4
|
class Book(models.Model): name=models.CharField(max_length=20) pub=models.ForeignKey(Publisher,related_name='pub') authors=models.ManyToManyField(Author,related_name='author') |
这样用Publisher或者Author反向查询Book时可以用related_name了:publisher1.pub.all()或者author1.author.all()。
如果不想设置反向关系,设置related_name为'+'或者以'+'结束。
|
1
|
user = models.ForeignKey(User, related_name='+') |
如果有多个ManyToManyField指向同一个Model,这样反向查询FOO_set的时候就无法弄清是哪个ManyToManyField字段了,可以禁止反向关系:
|
1
2
|
users = models.ManyToManyField(User, related_name='u+')referents = models.ManyToManyField(User, related_name='ref+') |
4.数据库表现 (Database Representation)
多对一:Django 使用ForeignKey字段名称+ "_id" 做为数据库中的列名称。在上面的例子中,BOOK model 对应的数据表中会有 一个 publisher_id 列。
你可以通过显式地指定 db_column 来改变该字段的列名称,不过,除非你想自定 义 SQL ,否则没必要更改数据库的列名称。
多对多:Django 创建一个中间表来表示ManyToManyField关系。默认情况下,中间表的名称由两个关系表名结合而成。
由于某些数据库对表名的长度有限制,所以中间表的名称会自动限制在64个字符以内,并包含一个不重复的哈希字符串。这
意味着,你可能看到类似 book_authors_9cdf4 这样的表名称。你可以使用 db_table 选项手动指定中间表名称。
但是,如果你想手动指定中间表,你可以用 through 选项来指定model 使用另外某个 model 来管理多对多关系。而这个 model 就是中间表所对应的 model :
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
class Person(models.Model): name = models.CharField(max_length=128) def __unicode__(self): return self.nameclass Group(models.Model): name = models.CharField(max_length=128) members = models.ManyToManyField(Person, through='Membership') def __unicode__(self): return self.nameclass Membership(models.Model): person = models.ForeignKey(Person) group = models.ForeignKey(Group) date_joined = models.DateField() invite_reason = models.CharField(max_length=64) |
这样,就可以记录某个person何时加入group了。
要建立Person与Group的关系就不能用add,create,remove了,而是需要通过Membership进行。
|
1
2
3
4
5
6
7
|
>>> ringo = Person.objects.create(name="Ringo Starr")>>> paul = Person.objects.create(name="Paul McCartney")>>> beatles = Group.objects.create(name="The Beatles")>>> m1 = Membership(person=ringo, group=beatles,... date_joined=date(1962, 8, 16),... invite_reason= "Needed a new drummer.")>>> m1.save() |
clear()还是可以使用的
|
1
|
>>> beatles.members.clear() |
当多对多关系关联自身时,中间表的ForeignKey是可以指向同一个Model的,但是它们必须被看做ManyToManyField的两边,而不是对称的,需要设置 symmetrical=False。
5.其它参数 (Arguments)
5.1 ForeignKey 接受下列这些可选参数,这些参数定义了关系是如何运行的。
ForeignKey.limit_choices_to
它是一个包含筛选条件和对应值的字典,用来在 Django 管理后台筛选 关联对象。例如,利用 Python 的 datetime 模块,过滤掉不符合筛选条件关联对象:
limit_choices_to = {'pub_date__lte': datetime.date.today}
只有 pub_date 在当前日期之前的关联对象才允许被选。
也可以使用 Q 对象来代替字典,从而实现更复杂的筛选。当limit_choices_to为Q对象时,如果把此外键字段放在ModelAdmin的raw_id_fields时是不可用的。
ForeignKey.to_field
指定当前关系与被关联对象中的哪个字段关联。默认情况下,to_field 指向被关联对象的主键。
ForeignKey.on_delete
当一个model对象的ForeignKey关联的对象被删除时,默认情况下此对象也会一起被级联删除的。
|
1
|
user = models.ForeignKey(User, blank=True, null=True, on_delete=models.CASCADE) |
CASCADE:默认值,model对象会和ForeignKey关联对象一起被删除
SET_NULL:将model对象的ForeignKey字段设为null。当然需要将null设为True。
SET_DEFAULT:将model对象的ForeignKey字段设为默认值。
Protect:删除ForeignKey关联对象时会生成一个ProtectedError,这样ForeignKey关联对象就不会被删除了。
SET():将model对象的ForeignKey字段设为传递给SET()的值。
|
1
2
3
4
5
|
def get_sentinel_user(): return User.objects.get_or_create(username='deleted')[0]class MyModel(models.Model): user = models.ForeignKey(User, on_delete=models.SET(get_sentinel_user)) |
DO_NOTHING:啥也不做。
5.2 ManyToManyField 接受下列可选参数,这些参数定义了关系是如何运行的。
ManyToManyField.limit_choices_to
和 ForeignKey.limit_choices_to 用法一样。
limit_choices_to 对于通过 through 参数指定了中介表的 ManyToManyField 不起作用。
ManyToManyField.symmetrical
只要定义递归的多对多关系时起作用。
ManyToManyField.through
手动指定中间表
ManyToManyField.db_table
指定数据库中保存多对多关系数据的表名称。如果没有提供该选项,Django 就会根据两个关系表的名称生成一个新的表名,做为中间表的名称。
6.OneToOneField
class OneToOneField(othermodel[, parent_link=False, **options])
用来定义一对一关系。笼统地讲,它与声明了 unique=True 的 ForeignKey 非常相似,不同的是使用反向关联的时候,得到的不是一个对象列表,而是一个单独的对象。
在某个 model 扩展自另一个 model 时,这个字段是非常有用的;例如: 多表继承 (Multi-tableinheritance) 就是通过在子 model 中添加一个指向父 model 的一对一关联而实现的。
必须给该字段一个参数:被关联的 model 类。工作方式和 ForeignKey 一样,连递归关联 (recursive) 和 延后关联 (lazy) 都一样。
此外,OneToOneField 接受 ForeignKey 可接受的参数,只有一个参数是 OnetoOneField 专有的:OneToOneField.parent_link
如果为 True ,并且作用于继承自某个父 model 的子 model 上(这里不能是延后继承,父 model 必须真实存在 ),那么该字段就会变成指向父类实例的引用(或者叫链接),
而不是象其他OneToOneField 那样用于扩展父类并继承父类属性。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
from django.db import models, transaction, IntegrityErrorclass Place(models.Model): name = models.CharField(max_length=50) address = models.CharField(max_length=80) def __unicode__(self): return u"%s the place" % self.nameclass Restaurant(models.Model): place = models.OneToOneField(Place, primary_key=True) serves_hot_dogs = models.BooleanField() serves_pizza = models.BooleanField() def __unicode__(self): return u"%s the restaurant" % self.place.nameclass Waiter(models.Model): restaurant = models.ForeignKey(Restaurant) name = models.CharField(max_length=50) def __unicode__(self): return u"%s the waiter at %s" % (self.name, self.restaurant) |
使用反向关联的时候,得到的不是一个对象列表,而是一个单独的对象:
|
1
2
3
4
5
6
7
8
9
|
>>> p1 = Place(name='Demon Dogs', address='944 W. Fullerton')>>> p1.save()>>> r = Restaurant(place=p1, serves_hot_dogs=True, serves_pizza=False)>>> r.save()>>> p1.restaurant<Restaurant: Demon Dogs the restaurant>>>> Place.objects.get(restaurant__place__name__startswith="Demon")<Place: Demon Dogs the place>>>> Waiter.objects.filter(restaurant__place__name__startswith="Demon") |
7.自定义多对多关系表
Django除了能自动创建多对多的第三张表,同样也可以自定义创建多对多的第三张表,而且操作和管理扩展等难易程度要比自动创建的好许多。所以,在之后的models表结构中,推荐使用自定义的方式。仅仅在创建时添加一个字段即可:through。
#=========================== 方式二,自定义关联表 class Host1(models.Model):
hostname = models.CharField(max_length=32)
port = models.IntegerField() class HostAdmin1(models.Model):
username = models.CharField(max_length=32)
email = models.CharField(max_length=32)
host = models.ManyToManyField(Host1, through='HostRelation') class HostRelation(models.Model):
c1 = models.ForeignKey(Host1)
c2 = models.ForeignKey(HostAdmin1) #自定义创建第三张表,其中的外键都为一对多的关系 增加数据(直接以id的方式向第三张表中添加数据)
models.HostRelation.objects.create(c1_id=2, c2_id=1,) 查询数据(双__)
relation_list = models.HostRelation.objects.filter(c2__username='dali')
for item in relation_list:
print item.c1.hostname
print item.c2.username
python--第二十三天总结(一对多和多对多)的更多相关文章
- 孤荷凌寒自学python第二十三天python类的封装
孤荷凌寒自学python第二十三天python类的封装 (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) 一.从怎么样访问类的内部代码块中定义的私有属性说起 类中定义的私有属性和私有方法是无法被 ...
- 小甲鱼Python第二十三讲课后习题--025,字典
笔记: 1.字典是Python中唯一的映射类型 2.字典包含两个要素:键(key)和值(value)他们是成对出现的,用大括号括起来,多对存在时用逗号隔开. 3.可以用dict()直接创建字典,如di ...
- python第二十三天-----作业中
#!usr/bin/env python #-*-coding:utf-8-*- # Author calmyan import os ,sys,time from core import trans ...
- python第二十三课——dict中的函数
dic1 = {...} dic2 = {...} dic1.update(dic2) 1.update(dict):dic1调用update传入dic2,如果dic2中的内容在dic1中不存在,那么 ...
- python第二十三天-----Tornado
Tornado是一个轻量级完整的web框架,在Linux系统下它会使用epoll,是一个异步非阻塞的web服务器框架,对于实时应用来说很理想,想想同是异步非阻塞的nginx的残暴程度就知道了 1.路由 ...
- Python开发【第二十三篇】:持续更新中...
Python开发[第二十三篇]:持续更新中...
- python自动开发之第二十三天(Django)
一.一大波model操作 1. 创建数据库表 # 单表 # app01_user ==> tb1 # users class User(models.Model): name = models. ...
- 简学Python第二章__巧学数据结构文件操作
#cnblogs_post_body h2 { background: linear-gradient(to bottom, #18c0ff 0%,#0c7eff 100%); color: #fff ...
- Python第十三天 django 1.6 导入模板 定义数据模型 访问数据库 GET和POST方法 SimpleCMDB项目 urllib模块 urllib2模块 httplib模块 django和web服务器整合 wsgi模块 gunicorn模块
Python第十三天 django 1.6 导入模板 定义数据模型 访问数据库 GET和POST方法 SimpleCMDB项目 urllib模块 urllib2模块 ...
- Python第二天 变量 运算符与表达式 input()与raw_input()区别 字符编码 python转义符 字符串格式化 format函数字符串格式化 帮助
Python第二天 变量 运算符与表达式 input()与raw_input()区别 字符编码 python转义符 字符串格式化 format函数字符串格式化 帮助 目录 Pychar ...
随机推荐
- adb 常用命令-转载
转自:https://blog.csdn.net/suxing_ing/article/details/54907860 显示当前运行的全部模拟器:adb devices 获取序列号:adb get- ...
- Kong(V1.0.2) Clustering Reference
介绍 Kong集群允许您通过添加更多的机器来处理更多的传入请求来水平扩展系统.它们将共享相同的配置,因为它们指向相同的数据库.指向相同数据存储的Kong节点将是相同Kong集群的一部分. 您需要在Ko ...
- 7.2 if else 语句
7.2 if else 语句 if else语句的通用形式是: if ( expression ) statement1 else statement2 如果expression为真(非0),则执行s ...
- mybatis-plus的代码生成器
简介:构建自定义mybatis-plus模板,自动生成mybatis,entity,mapper,service,controller 项目源码:https://github.com/y369q369 ...
- 了解原型设计工具pencil project
Pencil Pencil是一个功能强大的界面原型设计工具,可以设计网页和桌面程序界面,侧重点在于设计,支持自定义控件和导出模板,功能确实很强大. 内置形状集合 从2.0.2开始铅笔默认包含更多形状集 ...
- linux下各安装包的安装方法
<转>linux下各安装包的安装方法 一.rpm包安装方式步骤: 1.找到相应的软件包,比如soft.version.rpm,下载到本机某个目录: 2.打开一个终端,su -成root ...
- Windows 10(UWP)开发技巧 - PageUserControl
[本系列需要具有一定开发基础] 我们在开发中经常遇到这样的场景: 1.呈现详细信息,且包含一些操作.如:查看原图,支持放大,缩小,多图. 2.执行特定的行为,且要有回执结果.如:选择联系人,选中某图, ...
- Error occurred during initialization of VM Could not reserve enough space for object heap
Error occurred during initialization of VM Could not reserve enough space for object heap Java虚拟机(JV ...
- SVN:linux下搭建svn服务器
转载:https://www.cnblogs.com/puloieswind/p/5856326.html 1. 安装SVN服务器: 检查是否已安装 # rpm -qa subversion 安装SV ...
- python调用GDAL实现几何校正
引自https://blog.csdn.net/qq_27045589/article/details/81062586 def main(): infile = "F:\\Temp_Dat ...