python sqlalchemy 和django orm 对比
表和表的之间关系,往往通过外键建立关系,那简单介绍下外键。
一:DB角度上的上外键含义:
主键:主键是唯一标识一条记录,不能重复,有唯一性约束,不可以为空。用来保证数据的完整性,我们常用自增id来创建主键。
外键:是另一张表的主键或者带有唯一性约束的列,外键可以重复,可以为空,主要作用:用他来和其他的表建立逻辑关系。所以当我们谈到外键的时候最少涉及到2张表。
比如:
部门表dept 和员工表emp。emp表中的Dept_id就是外键,和dept表单的主键id关联。
因为一个部门多个员工,所以员工需要在知道自己归属的部门,所以emp是子表而dept是父表。
外键一定是从表中建立的,从而和主表建立关系,从表维护二者的关系。
使用外键的条件:
- 1、两张表必须都是InnodeDB表,并且没有临时表。
- 注:InnodDB是数据库引擎。mysql常见的数据库引擎:innodeDBhe 和MySIAM,而MySIM不支持外键约束!!!
- 2、建立外键关系的对应列必须有具有相似的InnoDB内部数据类型。
- 3、建立外键关系的对应列必须建立了索引,
二:从python角度理解:
在python中通过关系映射(orm),调用底层dbapi来实现数据库的操作。通过定义类和对象,(类是表,类的对象是数据库的一行数据。)来操作数据库,通过底层的转换,最终形成sql,在相应的数据库中执行。
notice:
- 无论是python通过orm(sqlalchemy和django的orm)来创建表,通过定义字段使表与表建立关系,比如外键。python层面定义的外键作用到数据库中,也是形成相应的外键。
- 所以无论哪种的orm建立的表结构,外键都是在子表中,可以理解成外键在多对一中“多”的字段中。
- 在数据库中,外键是建立在子表中。建立外键的列是另一张的表的主键。所以python设置外键的表是固定的。对应的“一对多”的“多”表中建立外键。
A:django的orm:
一对多:
比如说:作者和书籍的关系,一个作者有多本书,构成一对多的关系。
modles结构:
1 class Author(models.Model): 2 username=models.CharField(max_length=32) 3 class Book(models.Model): 4 name=models.CharField(max_length=32) 5 b_author=models.ForeignKey('Author')
插入数据:通过访问相应的url插入数据
1 def insert(request): 2 models.Author.objects.create(username="tom") 3 return HttpResponse('ok')
1 def insert(request): 2 models.Book.objects.create(name='唐吉坷德',b_author_id=1) 3 return HttpResponse('ok')
数据库本质的插入。
查询:
1、正向查询:
通过双下划线来操作。
比如:百年孤独的作者的名字是谁?
1 def insert(request): 2 ret=models.Book.objects.filter(name="百年孤独").values("b_author__username") 3 print(ret) 4 return HttpResponse('ok') 5 <QuerySet [{'b_author__username': 'tom'}]>
反向查询:一对多也支持反向查询。方法有2个。一个是通过双下划线,一个通过tablename_set字段哎查询,查询的方式不一样,方法也不一样!!!
- 通过tablename_set来反向查询,但是在这种查询,方法和manytomany 操作第三章表类似。
需求:查看tom都出 那些书,书的名字是什么?
1 def insert(request): 2 obj=models.Author.objects.filter(username='tom').first() 3 ret=obj.book_set.all() 4 for i in ret: 5 print(i.name) 6 return HttpResponse('ok')
1 百年孤独 2 唐吉坷德
- 通过双下滑线反向查询:
1 def insert(request): 2 booklist=models.Author.objects.filter(username='tom').values('book__name') 3 print(booklist) 4 return HttpResponse('ok') 5 <QuerySet [{'book__name': '百年孤独'}, {'book__name': '唐吉坷德'}]>
notice:
- 无论正向查询还是反向查询,都可以用双下划线。
- 反向查询的时候,因为对应的是“一”,所以查询的结果需要单个对象,然后查询对应“多”的表的对象集合。而使用set的字段的时候,需要注意使用的方法都是all、filter等。
对于多对多情况,正向查询的时候,使用的的是双下划线,反向查询是用含有manytomany的字段的“表”名的隐藏的列的进行反向查询。也是利用双下划线。
表结构:一个服务器有多个用户,一个用户在存在于多个服务器中。
1 class Host(models.Model): 2 ip=models.CharField(max_length=32) 3 hostname=models.CharField(max_length=32) 4 5 class User(models.Model): 6 username=models.CharField(max_length=32) 7 password=models.CharField(max_length=32) 8 user_host=models.ManyToManyField('Host')#注意引号的作用,如果没有引号的话,关联的表必须在当前表的前面,否则报错。
插入数据:
1 def insert(request): 2 for i in range(4): 3 models.Host.objects.create(ip='172.17.33.'+str(i),hostname=str(i)+'.com') 4 return HttpResponse('ok')
1 def insert(request): 2 for i in range(4): 3 models.User.objects.create(username='evil'+str(i),password=str(i)+'123') 4 return HttpResponse('ok')
- 需要注意:当我们在给含有ManyToMany的表进行插值的时候,对于字段:user_host=models.ManyToManyField('Host'),不需要插值。该列只是关联第三张关系表:mod_user_user_host。实质该列在数据库并不存在该列。
第三张表(mod_user_user_host)进行插值:第三张表存储在django层面来看是对象,实际在数据库中存储的是这2张表(host、user)的主键值。所以插入值的方法也有2种。
正向插入值:
1 def insert(request): 2 res=models.User.objects.filter(id=3).first() 3 ret=models.Host.objects.filter(id__gt=2) 4 res.user_host.add(*ret) 5 return HttpResponse('ok')
反向插入值,反向插入值,用另一张表名_set.add()方法来操作。
1 def insert(request): 2 res=models.Host.objects.filter(id=1).first() 3 ret=models.User.objects.filter(id__lt=4) 4 res.user_set.add(*ret) 5 return HttpResponse('ok')
当然相应的查询方法,也可以 用_set字段或者表名进行查询,和一对多是一样的。唯一区别是:更新第三张表的时候,最好用原生sql进行更新。
B:sqlalchemy的orm
- 对于一对多或者多对多的情况下,在sqlalchemy中使用的是relationship()来创建一个数据库中并不存在的列来构建2个表之间的关系。
- 需要注意的:在django中建立外键,直接类的名字既可,在sqlalchemy中需要写:表的名字.主键列的名字。
表结构:比如主机和主机用户来构建多对多表结构
1 class Host(Base): 2 __tablename__='host' 3 nid=Column(Integer,autoincrement=True,primary_key=True) 4 hostname=Column(String(32)) 5 ip=Column(String(32)) 6 7 class system_User(Base): 8 __tablename__='system_user' 9 nid=Column(Integer,autoincrement=True,primary_key=True) 10 username=Column(String(32)) 11 password=Column(String(32)) 12 13 class Host_to_system_User(Base): 14 __tablename__='host_to_system_user' 15 nid=Column(Integer,primary_key=True,autoincrement=True) 16 host_nid=Column(Integer,ForeignKey('host.nid')) 17 system_user_nid=Column(Integer,ForeignKey('system_user.nid'))#需要注意这个和django不一样,django直接写类名字既可。 18 host=relationship('Host',backref='ho') 19 system_user=relationship('system_User',backref='sys_u') 20 Base.metadata.create_all(engine)##执行该函数,他就会执行所有Base所有的子类。调用我们定义类并创建相应的表结构。 21 Session=sessionmaker(engine) 22 session=Session()#创建数据库连接。可以理解为django的db模块中connection。
插入数据:2张表正常插入值和django一样,不需要关注第三张表,当需要建立关系的时候,直接给第三张表插入相应的id值既可。
1 Session=sessionmaker(engine) 2 session=Session()#创建数据库连接。可以理解为django的db模块中connection。 3 host_obj=Host(hostname='c1.com',ip='172.17.22.12') 4 host_obj_1=Host(hostname='c2.com',ip='172.17.22.13') 5 host_obj_2=Host(hostname='c3.com',ip='172.17.22.14') 6 session.add_all( 7 [ 8 host_obj, 9 host_obj_1, 10 host_obj_2 11 ] 12 ) 13 system_user_obj=system_User(username='evil',password='123') 14 system_user_obj_1=system_User(username='tom',password='123') 15 system_user_obj_2=system_User(username='jack',password='123') 16 session.add_all( 17 ( 18 system_user_obj, 19 system_user_obj_1, 20 system_user_obj_2 21 ) 22 ) 23 # 24 host_to_system_user_obj=Host_to_system_User(host_nid=1,system_user_nid=1) 25 host_to_system_user_obj_1=Host_to_system_User(host_nid=1,system_user_nid=2) 26 host_to_system_user_obj_2=Host_to_system_User(host_nid=1,system_user_nid=3) 27 host_to_system_user_obj_3=Host_to_system_User(host_nid=2,system_user_nid=1) 28 host_to_system_user_obj_7=Host_to_system_User(host_nid=2,system_user_nid=2) 29 host_to_system_user_obj_4=Host_to_system_User(host_nid=2,system_user_nid=3) 30 host_to_system_user_obj_5=Host_to_system_User(host_nid=3,system_user_nid=1) 31 host_to_system_user_obj_6=Host_to_system_User(host_nid=3,system_user_nid=2) 32 session.add_all( 33 [ 34 host_to_system_user_obj, 35 host_to_system_user_obj_1, 36 host_to_system_user_obj_2, 37 host_to_system_user_obj_3, 38 host_to_system_user_obj_4, 39 host_to_system_user_obj_5, 40 host_to_system_user_obj_6, 41 host_to_system_user_obj_7 42 ] 43 ) 44 session.commit()
1 mysql> select * from host; 2 +-----+----------+--------------+ 3 | nid | hostname | ip | 4 +-----+----------+--------------+ 5 | 1 | c1.com | 172.17.22.12 | 6 | 2 | c2.com | 172.17.22.13 | 7 | 3 | c3.com | 172.17.22.14 | 8 +-----+----------+--------------+ 9 3 rows in set (0.00 sec) 10 11 mysql> select * from system_user; 12 +-----+----------+----------+ 13 | nid | username | password | 14 +-----+----------+----------+ 15 | 1 | evil | 123 | 16 | 2 | tom | 123 | 17 | 3 | jack | 123 | 18 +-----+----------+----------+ 19 3 rows in set (0.00 sec) 20 21 mysql> select * from host_to_system_user; 22 +-----+----------+-----------------+ 23 | nid | host_nid | system_user_nid | 24 +-----+----------+-----------------+ 25 | 1 | 1 | 1 | 26 | 2 | 1 | 2 | 27 | 3 | 1 | 3 | 28 | 4 | 2 | 1 | 29 | 5 | 2 | 3 | 30 | 6 | 3 | 1 | 31 | 7 | 3 | 2 | 32 | 8 | 2 | 2 | 33 +-----+----------+-----------------+ 34 8 rows in set (0.00 sec)
查询:
需求:用户evil 都在哪些服务器上?
分析:首先通过system_user查到evil的对象,通过该对象获取sys_u的列,这个列是第三张表的对象的集合,通过循环该列获取每列的我们建立的host关系列来获取对应的host表的属性值。也就是说先反向查询在正向查询。
1 ret=session.query(system_User).filter(system_User.username=='evil').first() 2 for i in ret.sys_u: 3 print(i.host.ip)
1 172.17.22.12 2 172.17.22.13 3 172.17.22.14
django orm和sqlalchemy的orm的对比:
- 在django中orm中插入和查询的时候,使用是类中定义数据库的列的名字,而在sqlalchemy中使用的调用数据库的字段是对象的属性字段。
django:
modle:
1 class Person(models.Model): 2 username=models.CharField(max_length=32) 3 4 class Fav(models.Model): 5 name=models.CharField(max_length=32) 6 per_fav=models.ForeignKey('Person')
查询语句:
比如查询名字为evil的爱好都有哪些:
1 def insert(request): 2 ret=models.Fav.objects.filter(per_fav__username='evil').values('name') 3 print(ret) 4 return HttpResponse('ok')
其中查询的字段并没有对象.字段属性。而sqlalchemy在调用表的字段的字段的时候,需要使用类.字段(其中字段属于类的静态字段。)
sqlalchemy:
1 from sqlalchemy.ext.declarative import declarative_base 2 from sqlalchemy import Column, Integer, String, ForeignKey, UniqueConstraint, Index#导入列数据类型字段。 3 from sqlalchemy.orm import sessionmaker, relationship#导入会话函数、 4 from sqlalchemy import create_engine 5 engine = create_engine("mysql+pymysql://root:@192.168.31.222:3306/django", max_overflow=15)#创建数据库引擎,通过连接池获取数据库的连接。数据库连接池数量为:15,默认值是5. 6 #创建sqlorm基类。(为声明的类定义基类。) 7 Base = declarative_base() 8 class User(Base): 9 __tablename__='user' 10 nid=Column(Integer,primary_key=True,autoincrement=True) 11 username=Column(String(32)) 12 13 def __repr__(self): 14 temp='%s-%s'%(self.nid,self.username) 15 return temp 16 Base.metadata.create_all(engine)##执行该函数,他就会执行所有Base所有的子类。调用我们定义类并创建相应的表结构。
插入数据:
1 Session=sessionmaker(engine) 2 session=Session()#创建数据库连接。可以理解为django的db模块中connection。 3 user_obj=User(username='evil')#创建类的对象。 4 user_obj1=User(username='tom') 5 user_obj2=User(username='jack') 6 session.add_all( 7 ( 8 user_obj, 9 user_obj1, 10 user_obj2 11 ) 12 ) 13 session.commit()#提交数据库事务。
1 mysql> select *from user; 2 +-----+----------+ 3 | nid | username | 4 +-----+----------+ 5 | 1 | evil | 6 | 2 | tom | 7 | 3 | jack | 8 +-----+----------+ 9 3 rows in set (0.00 sec)
查询数据库:
1 Session=sessionmaker(engine) 2 session=Session()#创建数据库连接。可以理解为django的db模块中connection。 3 ret=session.query(User).filter(User.nid>1).all() 4 print(ret) 5 [2-tom, 3-jack]
对比:
- 数据库连接:django在创建项目的时候在setting配置文件中需要配置数据库的连接串,默认使用数据库是sqlite。
1 DATABASES = { 2 'default': { 3 'ENGINE': 'django.db.backends.sqlite3', 4 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 5 } 6 }
- sqlalchemy 需要导入相应的模块,然后建立相应的连接引擎和数据库的连接池。每次执行数据库操作的时候都需要创建连接对象。而django默认帮我们做数据库连接。
1 from sqlalchemy import create_engine 2 engine = create_engine("mysql+pymysql://root:@192.168.31.222:3306/django", max_overflow=15)#创建数据库引擎,通过连接池获取数据库的连接。
- django在创建数据库的时候,创建表的类的时候需要继承(models.Model)而sqlalchemy需要继承一个基类:Base = declarative_base()
- 在django如果不指定主键的时候,django默认会创建一个名为:id的自增列。而sqlalchemy需要手动指定自增列和主键。
- 默认在django中表明是类名的小写,而在sqlalchemy中必须要指定__tablename__字段,指定数据库的表的名字否则报如下错误信息。
1 sqlalchemy.exc.InvalidRequestError: Class <class '__main__.User'> does not have a __table__ or __tablename__ specified and does not inherit from an existing table-mapped class.
django:
1 from django.db import models 2 3 # Create your models here. 4 class Person(models.Model): 5 username=models.CharField(max_length=32)
sqlalchemy:
1 from sqlalchemy.ext.declarative import declarative_base 2 from sqlalchemy import Column, Integer, String, ForeignKey, UniqueConstraint, Index # 导入列数据类型字段。 3 from sqlalchemy.orm import sessionmaker, relationship # 导入会话函数、 4 from sqlalchemy import create_engine 5 6 engine = create_engine("mysql+pymysql://root:@192.168.147.129:3306/sqlalchemy", 7 max_overflow=15) # 创建数据库引擎,通过连接池获取数据库的连接。数据库连接池数量为:15,默认值是5. 8 # 创建sqlorm基类。(为声明的类定义基类。) 9 Base = declarative_base() 10 11 class User(Base): 12 __tablename__='user' 13 nid=Column(Integer,primary_key=True,autoincrement=True) 14 name=Column(String(32)) 15 def __repr__(self): 16 return self.name
- django 默认情况不需要指定表名,而sqlalchemy需要指定表名否则报错。
- 2者在查询返回的结果都是对象的列表(django是Queryset对象,而sqlalchemy返回的是相应的类对象),django可以用__unicode__方法 输出对象的时候我们可以自定义输出的我们自定义的字段(django版本Django 1.10中是__str__方法),而sqlalchemy是__repr__方法来输出对象的自定义字段。
sqlalchemy:
1 class User(Base): 2 __tablename__='user' 3 nid=Column(Integer,primary_key=True,autoincrement=True) 4 username=Column(String(32)) 5 Session=sessionmaker(engine) 6 session=Session()#创建数据库连接。可以理解为django的db模块中connection。 7 ret=session.query(User).filter(User.nid>1).all() 8 print(ret) 9 [<__main__.User object at 0x03708210>, <__main__.User object at 0x03708250>]
django:
1 from django.db import models 2 3 # Create your models here. 4 class Person(models.Model): 5 username=models.CharField(max_length=32) 6 7 class Fav(models.Model): 8 name=models.CharField(max_length=32) 9 per_fav=models.ForeignKey('Person')
1 def insert(request): 2 ret=models.Fav.objects.filter(per_fav__username='evil').all() 3 print(ret) 4 return HttpResponse('ok')
1 <QuerySet [<Fav: Fav object>, <Fav: Fav object>]>
sqlalchemy:
1 class User(Base): 2 __tablename__='user' 3 nid=Column(Integer,primary_key=True,autoincrement=True) 4 username=Column(String(32)) 5 6 def __repr__(self): 7 temp='%s-%s'%(self.nid,self.username) 8 return temp 9 [2-tom, 3-jack]
django:
1 from django.db import models 2 3 # Create your models here. 4 class Person(models.Model): 5 username=models.CharField(max_length=32) 6 def __str__(self): 7 temp='%s-%s'%(self.id,self.username) 8 return temp 9 10 class Fav(models.Model): 11 name=models.CharField(max_length=32) 12 per_fav=models.ForeignKey('Person') 13 def __str__(self): 14 temp='%s-%s'%(self.id,self.name) 15 return temp
输出函数:
1 from django.shortcuts import render,HttpResponse 2 from mod import models 3 # Create your views here. 4 def insert(request): 5 ret=models.Fav.objects.filter(per_fav__username='evil').all() 6 for i in ret: 7 print(i) 8 return HttpResponse('ok') 9 1-bak 10 2-foot
- 在sqlalchemy中对数据库进行增删改的时候,最后需要提交事务(session.commit()),数据库才能保存我们的数据修改,在低版本的django中也需要save()进行提交事务在版本:Django 1.10中不需要提交事务。
1 User_obj=User(name='evil') 2 User_obj_1=User(name='tom') 3 User_obj_2=User(name='jack') 4 5 Session=sessionmaker(engine) 6 session=Session() 7 session.add_all( 8 [ 9 User_obj, 10 User_obj_1, 11 User_obj_2 12 ] 13 ) 14 session.commit()
1 mysql> select * from user; 2 +-----+------+ 3 | nid | name | 4 +-----+------+ 5 | 1 | evil | 6 | 2 | tom | 7 | 3 | jack | 8 +-----+------+ 9 3 rows in set (0.00 sec)
- 插入数据:在一对多的情况下,django可以有两种方式进行数据的插入,包括:django层面,对外键列插入关联表的对象,在数据库层面:实际数据库中存储的是:另一个列的主键id值。可以直接插入数字。
表结构:
1 class Author(models.Model): 2 username=models.CharField(max_length=32) 3 class Book(models.Model): 4 name=models.CharField(max_length=32) 5 b_author=models.ForeignKey('Author')
给b_author插入值,默认情况下,book表(注意是小写)中的b_author列在数据库中的列为:b_author_id.
所以我们在插入b_author列插入author表的对象,也可以直接插入author主键列里的id值。插入对象:
1 from django.shortcuts import render,HttpResponse 2 from mod import models 3 # Create your views here. 4 def insert(request): 5 author_obj=models.Author.objects.filter(id=1).first() 6 models.Book.objects.create(b_author=author_obj,name="罗兵逊漂流记") 7 return HttpResponse('ok')
插入id值:
1 from django.shortcuts import render,HttpResponse 2 from mod import models 3 # Create your views here. 4 def insert(request): 5 models.Book.objects.create(b_author_id=2,name="陈二狗的妖孽人生") 6 return HttpResponse('ok')
需要注意的是:需要使用实际数据库存在的列(b_author_id)而不是django定义字段的列名字:b_author。
- 在sqlalchemy中,插入的时候可以直接入相应类的对象(add()),或者可迭代对象集合(addall(元组、或者列表)),存在foreign key 列需要特别注意: 插入该列的值不是对象,而是关联表的主键nid值,不是对象!!!区别于django 插入外键的时候可以是对象或者id值。而且sqlalchemy定义的列名字就是数据库存储的名字。区别于django中在数据库层次的实际存储的列名字是django定义列的名字加上_id.
表结构:一个作者有多本书。book表示子表,相对author表为父表。
1 class Author(Base): 2 __tablename__='author' 3 username=Column(String(32)) 4 nid=Column(Integer,primary_key=True,autoincrement=True) 5 def __repr__(self): 6 temp='%s--%s'%(self.nid,self.username) 7 return temp 8 9 class Book(Base): 10 __tablename__ = 'book' 11 nid = Column(Integer, primary_key=True, autoincrement=True) 12 name = Column(String(32)) 13 b_a=Column(Integer,ForeignKey('author.nid')) 14 book=relationship('Author',backref='auth') 15 16 def __repr__(self): 17 temp = '%s-%s' % (self.nid, self.name) 18 return temp 19 Base.metadata.create_all(engine)##执行该函数,他就会执行所有Base所有的子类。调用我们定义类并创建相应的表结构。
插入值:
1 author1=Author(username='evil') 2 author2=Author(username='tom') 3 author3=Author(username='jack') 4 5 Session=sessionmaker(bind=engine) 6 session=Session() 7 session.add_all( 8 [ 9 author1, 10 author2, 11 author3 12 ] 13 ) 14 session.commit()
1 mysql> select * from author; 2 +----------+-----+ 3 | username | nid | 4 +----------+-----+ 5 | evil | 1 | 6 | tom | 2 | 7 | jack | 3 | 8 +----------+-----+ 9 3 rows in set (0.00 sec)
插入语句:注意外键的列插入的不是对象,而是相应的关联表的主键的值。即主表的主键nid值。
1 book1=Book(name='百年孤独',b_a=3) 2 book2=Book(name='陈二狗的妖孽人生',b_a=3) 3 book3=Book(name='海贼王',b_a=3) 4 5 session.add_all( 6 ( 7 book1, 8 book2, 9 book3 10 ) 11 ) 12 session.commit()
1 mysql> select * from book; 2 +-----+--------------------------+------+ 3 | nid | name | b_a | 4 +-----+--------------------------+------+ 5 | 2 | 百年孤独 | 2 | 6 | 3 | 陈二狗的妖孽人生 | 2 | 7 | 4 | 海贼王 | 2 | 8 | 5 | 百年孤独 | 1 | 9 | 6 | 陈二狗的妖孽人生 | 1 | 10 | 7 | 海贼王 | 1 | 11 | 8 | 百年孤独 | 3 | 12 | 9 | 陈二狗的妖孽人生 | 3 | 13 | 10 | 海贼王 | 3 | 14 +-----+--------------------------+------+ 15 9 rows in set (0.00 sec)
- 出现的问题: 编码问题,如果我们在sqlalchemy中不指定编码的时候,底层dbapi采用的编码:latin-1进行编码,如果你插入的数据含有中文的话,由于latin-1在解码的时候,不支持中文会报错:
UnicodeEncodeError: 'latin-1' codec can't encode characters in position 38-41: ordinal not in range(256)
解决方法:在数据连接引擎处指定编码,让sql语句中的中文部分按指定的编码进行解码。使用dbname?charset=utf8来指定相应的编码。
http://firefish.blog.51cto.com/298258/112794/
1 engine = create_engine("mysql+pymysql://root:@192.168.147.129:3306/sqlalchemy?charset=utf8", 2 max_overflow=15) # 创建数据库引擎,通过连接池获取数据库的连接。数据库连接池数量为:15,默认值是5.
所以以后再写引擎的时候,需要注意:直接写上面的连接串。
在mysql中修改编码的方法:在/etc/my.cnf 中添加入下语句,如果不添加client字段的话,在数据库中中文字段显示是?问号。但是程序查询的时候,还会正常显示中文。
1 [mysqld] 2 default-storage-engine=INNODB 3 default-character-set=utf8 4 [client] 5 default-character-set=utf8
因为有的版本mysql不支持参数:default-character-set=utf8 需要使用:character_set_server=utf8。
- 建立外键的区别:django 中在一对多的情况下,使用的foreign key 。 在多对多,不创建第三张表的时候,使用ManyToMany字段。如果手动创建第三张表的时候使用foreign key来构建关系。sqlalchemy中,一对多、多对多的情况下,
都是用foreign key来构建关系。而且在多对多的情况下,需要手动构建表结构关系,创建第三张表,
- 对外键列的插入方法的不同:在django中对于外键列插入值,可以是插入关联表的对象或者关联表的对应的主键列即id列2种方法,但是在sqlalchemy对于外键列只能插入父表中的定义的主键列的值比如:nid值,而不是对象。
- 对于查询建立关系的区别:在django中,默认给咱们创建相应的查询的虚拟列比如一对多,反向查询:tablename_set 和tablename2种虚拟关系列。前者不能使用双下划线,后者可以使用双下划线。在sqlalchemy中需要我们手动创建一个不存在数据库的虚拟机列,使用(本表和关联表的虚拟关系列)=relationship('classname',backref='另一张表的虚拟关系列')进行查询。正向查询用:用等号的左边的列,反向查询的时候,用等号的右边的backref定义的虚拟关系列。
sqlalchemy:
表结构:
1 class Author(Base): 2 __tablename__='author' 3 username=Column(String(32)) 4 nid=Column(Integer,primary_key=True,autoincrement=True) 5 def __repr__(self): 6 temp='%s--%s'%(self.nid,self.username) 7 return temp 8 9 class Book(Base): 10 __tablename__ = 'book' 11 nid = Column(Integer, primary_key=True, autoincrement=True) 12 name = Column(String(100)) 13 b_a=Column(Integer,ForeignKey('author.nid')) 14 book=relationship('Author',backref='auth') 15 def __repr__(self): 16 temp = '%s-%s' % (self.nid, self.name) 17 return temp
反向查询:使用子表中定义的列:book=relationship('Author',backref='auth') 建立的虚拟关系列:auth需要注意的是auth是另一个表的对象的集合。
需求场景:作者为:evil,都出那些书籍?
1 Session=sessionmaker(bind=engine) 2 session=Session() 3 res=session.query(Author).filter(Author.username=='evil').first() 4 for i in res.auth: 5 print(i.name) 6 百年孤独 7 陈二狗的妖孽人生 8 海贼王
正向查询:
需求场景:book表中nid=2的书作者是谁?
1 Session=sessionmaker(bind=engine) 2 session=Session() 3 ret=session.query(Book).filter(Book.nid==2).first() 4 print(ret.book.username) 5 6 tom
- 在django中对于大于、小于、等于、包含、不包含等使用的双下滑线:id__lt=2... 在sqlalchemy中直接使用 > < ==等。
- 在django和sqlalchemy中如果查询条件为并的时候,都是用逗号。
1 Session=sessionmaker(bind=engine) 2 session=Session() 3 ret=session.query(Book).filter(Book.nid.in_((2,3,7)) ).all() 4 for i in ret: 5 print(i.name) 6 百年孤独 7 陈二狗的妖孽人生 8 海贼王