1.ORM
对象关系映射(英语:Object Relation Mapping,简称ORM,或O/RM,或O/R mapping),是一种程序技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换。从效果上说,它其实是创建了一个可在编程语言里使用的“虚拟对象数据库”。
一般的ORM包括以下四部分:
一个对持久类对象进行CRUD操作的API;
一个语言或API用来规定与类和类属性相关的查询;
一个规定MAPPING METADATA的工具;
一种技术可以让ORM的实现同事务对象一起进行DIRTYCHECKING, LAZY ASSOCIATION FETCHING以及其他的优化操作。
2.django的ORM和SQLalchemy
Django 的 Model 驱动对数据库层面上的实现细节关注的非常少,开发者定义模型的过程非常接近声明式而非过程式,对于新项目来说,可能是这个原因让 Django Model 比 SQLAlchemy 讨人喜欢。
传统的 SQLAlchemy 的使用方法是不入侵模型,在单独的地方定义表结构、映射规则,然后用 SQLAlchemy 驱动注入到模型类里去,这种方法可以完全避免模型与数据库的耦合,但是定义繁琐,要求开发者完全明白 engine、metadata、table、column、mapper 等概念,如果没有读过《企业应用架构模式》一类书籍会被弄得很乱。
现在 SQLAlchemy 提供了 declarative 的方式,和 Django Model 很像,但是和声明式模型还是有一定的距离,好在对于灵活性几乎没损失。但是我对比了一下 Django Model 和 SQLAlchemy declarative,发现 Django Model 还是更简洁一些。例如对于类关联,Django 只要直接声明外键,就自动产生关联对象,而 SQLAlcyhemy 要定义外键、relationship 对象,如果有多个外键还要自己指定 join 规则…… 总之灵活性是好东西,但是不是什么情况下都讨人喜欢的。
我本来想说这个是 ActiveRecord style 和 Data Mapper style 区别导致的,但是细想了一下,Django Model 并不是简单的 ActiveRecord,其对于复杂关联甚至继承的映射都有很好的适应性,应该和 SQLAlchemy 的 declarative 是同类型的,是对 Data Mapper 的 Active Record style 包装。
因为在Django世界中它的ORM就是事实标准。Django最重要的特色是什么?从ORM快速生成后台管理界面!另外还有ModelForm、数据迁移(migration)等等从Django ORM延伸出去的概念……如果你选用了SQLAlchemy,那么这一切都没有了,你必须自行搭建,或者选用第三方库。话说,没有了内置ORM、没有了内置后台管理界面、没有了内置ModelForm、没有了数据迁移的Django,还是Django吗?不如直接用其它更轻量或更松散的框架好了!
以我的观点,ORM是在SQL之上的封装,而这种封装引入了太厚的封装,使得程序员对底层的控制力明显减弱,又加入了太多新的设计。所以我是不赞同使用ORM的,还是干干净净的SQL好用的多。
3.实际对比
这里使用一位大佬的博客来看看两者区别,具体的过程我就不做演示了,直接搬过来。
表和表的之间关系,往往通过外键建立关系,那简单介绍下外键。
一: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 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的字段的“表”名的隐藏的列的进行反向查询。也是利用双下划线。
表结构:一个服务器有多个用户,一个用户在存在于多个服务器中。
class Host(models.Model): ip=models.CharField(max_length=32) hostname=models.CharField(max_length=32) class User(models.Model): username=models.CharField(max_length=32) password=models.CharField(max_length=32) 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中需要写:表的名字.主键列的名字。
表结构:比如主机和主机用户来构建多对多表结构
class Host(Base): __tablename__='host' nid=Column(Integer,autoincrement=True,primary_key=True) hostname=Column(String(32)) ip=Column(String(32)) class system_User(Base): __tablename__='system_user' nid=Column(Integer,autoincrement=True,primary_key=True) username=Column(String(32)) password=Column(String(32)) class Host_to_system_User(Base): __tablename__='host_to_system_user' nid=Column(Integer,primary_key=True,autoincrement=True) host_nid=Column(Integer,ForeignKey('host.nid')) system_user_nid=Column(Integer,ForeignKey('system_user.nid'))#需要注意这个和django不一样,django直接写类名字既可。 host=relationship('Host',backref='ho') system_user=relationship('system_User',backref='sys_u') Base.metadata.create_all(engine)##执行该函数,他就会执行所有Base所有的子类。调用我们定义类并创建相应的表结构。 Session=sessionmaker(engine) session=Session()#创建数据库连接。可以理解为django的db模块中connection。
插入数据:2张表正常插入值和django一样,不需要关注第三张表,当需要建立关系的时候,直接给第三张表插入相应的id值既可。
Session=sessionmaker(engine) session=Session()#创建数据库连接。可以理解为django的db模块中connection。 host_obj=Host(hostname='c1.com',ip='172.17.22.12') host_obj_1=Host(hostname='c2.com',ip='172.17.22.13') host_obj_2=Host(hostname='c3.com',ip='172.17.22.14') session.add_all( [ host_obj, host_obj_1, host_obj_2 ] ) system_user_obj=system_User(username='evil',password='123') system_user_obj_1=system_User(username='tom',password='123') system_user_obj_2=system_User(username='jack',password='123') session.add_all( ( system_user_obj, system_user_obj_1, system_user_obj_2 ) ) # host_to_system_user_obj=Host_to_system_User(host_nid=1,system_user_nid=1) host_to_system_user_obj_1=Host_to_system_User(host_nid=1,system_user_nid=2) host_to_system_user_obj_2=Host_to_system_User(host_nid=1,system_user_nid=3) host_to_system_user_obj_3=Host_to_system_User(host_nid=2,system_user_nid=1) host_to_system_user_obj_7=Host_to_system_User(host_nid=2,system_user_nid=2) host_to_system_user_obj_4=Host_to_system_User(host_nid=2,system_user_nid=3) host_to_system_user_obj_5=Host_to_system_User(host_nid=3,system_user_nid=1) host_to_system_user_obj_6=Host_to_system_User(host_nid=3,system_user_nid=2) session.add_all( [ host_to_system_user_obj, host_to_system_user_obj_1, host_to_system_user_obj_2, host_to_system_user_obj_3, host_to_system_user_obj_4, host_to_system_user_obj_5, host_to_system_user_obj_6, host_to_system_user_obj_7 ] ) session.commit()
mysql> select * from host; +-----+----------+--------------+ | nid | hostname | ip | +-----+----------+--------------+ | 1 | c1.com | 172.17.22.12 | | 2 | c2.com | 172.17.22.13 | | 3 | c3.com | 172.17.22.14 | +-----+----------+--------------+ 3 rows in set (0.00 sec) mysql> select * from system_user; +-----+----------+----------+ | nid | username | password | +-----+----------+----------+ | 1 | evil | 123 | | 2 | tom | 123 | | 3 | jack | 123 | +-----+----------+----------+ 3 rows in set (0.00 sec) mysql> select * from host_to_system_user; +-----+----------+-----------------+ | nid | host_nid | system_user_nid | +-----+----------+-----------------+ | 1 | 1 | 1 | | 2 | 1 | 2 | | 3 | 1 | 3 | | 4 | 2 | 1 | | 5 | 2 | 3 | | 6 | 3 | 1 | | 7 | 3 | 2 | | 8 | 2 | 2 | +-----+----------+-----------------+ 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:
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import Column, Integer, String, ForeignKey, UniqueConstraint, Index#导入列数据类型字段。 from sqlalchemy.orm import sessionmaker, relationship#导入会话函数、 from sqlalchemy import create_engine engine = create_engine("mysql+pymysql://root:@192.168.31.222:3306/django", max_overflow=15)#创建数据库引擎,通过连接池获取数据库的连接。数据库连接池数量为:15,默认值是5. #创建sqlorm基类。(为声明的类定义基类。) Base = declarative_base() class User(Base): __tablename__='user' nid=Column(Integer,primary_key=True,autoincrement=True) username=Column(String(32)) def __repr__(self): temp='%s-%s'%(self.nid,self.username) return temp Base.metadata.create_all(engine)##执行该函数,他就会执行所有Base所有的子类。调用我们定义类并创建相应的表结构。
插入数据:
Session=sessionmaker(engine) session=Session()#创建数据库连接。可以理解为django的db模块中connection。 user_obj=User(username='evil')#创建类的对象。 user_obj1=User(username='tom') user_obj2=User(username='jack') session.add_all( ( user_obj, user_obj1, user_obj2 ) ) session.commit()#提交数据库事务。
mysql> select *from user; +-----+----------+ | nid | username | +-----+----------+ | 1 | evil | | 2 | tom | | 3 | jack | +-----+----------+ 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:
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import Column, Integer, String, ForeignKey, UniqueConstraint, Index # 导入列数据类型字段。 from sqlalchemy.orm import sessionmaker, relationship # 导入会话函数、 from sqlalchemy import create_engine engine = create_engine("mysql+pymysql://root:@192.168.147.129:3306/sqlalchemy", max_overflow=15) # 创建数据库引擎,通过连接池获取数据库的连接。数据库连接池数量为:15,默认值是5. # 创建sqlorm基类。(为声明的类定义基类。) Base = declarative_base() class User(Base): __tablename__='user' nid=Column(Integer,primary_key=True,autoincrement=True) name=Column(String(32)) def __repr__(self): return self.name
- django 默认情况不需要指定表名,而sqlalchemy需要指定表名否则报错。
- 2者在查询返回的结果都是对象的列表(django是Queryset对象,而sqlalchemy返回的是相应的类对象),django可以用__unicode__方法 输出对象的时候我们可以自定义输出的我们自定义的字段(django版本Django 1.10中是__str__方法),而sqlalchemy是__repr__方法来输出对象的自定义字段。
sqlalchemy:
class User(Base): __tablename__='user' nid=Column(Integer,primary_key=True,autoincrement=True) username=Column(String(32)) Session=sessionmaker(engine) session=Session()#创建数据库连接。可以理解为django的db模块中connection。 ret=session.query(User).filter(User.nid>1).all() print(ret) [<__main__.User object at 0x03708210>, <__main__.User object at 0x03708250>]
django:
from django.db import models # Create your models here. class Person(models.Model): username=models.CharField(max_length=32) class Fav(models.Model): name=models.CharField(max_length=32) 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:
class User(Base): __tablename__='user' nid=Column(Integer,primary_key=True,autoincrement=True) username=Column(String(32)) def __repr__(self): temp='%s-%s'%(self.nid,self.username) return temp [2-tom, 3-jack]
django:
from django.db import models # Create your models here. class Person(models.Model): username=models.CharField(max_length=32) def __str__(self): temp='%s-%s'%(self.id,self.username) return temp class Fav(models.Model): name=models.CharField(max_length=32) per_fav=models.ForeignKey('Person') def __str__(self): temp='%s-%s'%(self.id,self.name) return temp
输出函数:
from django.shortcuts import render,HttpResponse from mod import models # Create your views here. def insert(request): ret=models.Fav.objects.filter(per_fav__username='evil').all() for i in ret: print(i) return HttpResponse('ok') 1-bak 2-foot
- 在sqlalchemy中对数据库进行增删改的时候,最后需要提交事务(session.commit()),数据库才能保存我们的数据修改,在低版本的django中也需要save()进行提交事务在版本:Django 1.10中不需要提交事务。
User_obj=User(name='evil') User_obj_1=User(name='tom') User_obj_2=User(name='jack') Session=sessionmaker(engine) session=Session() session.add_all( [ User_obj, User_obj_1, User_obj_2 ] ) session.commit()
mysql> select * from user; +-----+------+ | nid | name | +-----+------+ | 1 | evil | | 2 | tom | | 3 | jack | +-----+------+ 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值。插入对象:
from django.shortcuts import render,HttpResponse from mod import models # Create your views here. def insert(request): author_obj=models.Author.objects.filter(id=1).first() models.Book.objects.create(b_author=author_obj,name="罗兵逊漂流记") 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表为父表。
class Author(Base): __tablename__='author' username=Column(String(32)) nid=Column(Integer,primary_key=True,autoincrement=True) def __repr__(self): temp='%s--%s'%(self.nid,self.username) return temp class Book(Base): __tablename__ = 'book' nid = Column(Integer, primary_key=True, autoincrement=True) name = Column(String(32)) b_a=Column(Integer,ForeignKey('author.nid')) book=relationship('Author',backref='auth') def __repr__(self): temp = '%s-%s' % (self.nid, self.name) return temp Base.metadata.create_all(engine)##执行该函数,他就会执行所有Base所有的子类。调用我们定义类并创建相应的表结构。
插入值:
author1=Author(username='evil') author2=Author(username='tom') author3=Author(username='jack') Session=sessionmaker(bind=engine) session=Session() session.add_all( [ author1, author2, author3 ] ) session.commit()
mysql> select * from author; +----------+-----+ | username | nid | +----------+-----+ | evil | 1 | | tom | 2 | | jack | 3 | +----------+-----+ 3 rows in set (0.00 sec)
插入语句:注意外键的列插入的不是对象,而是相应的关联表的主键的值。即主表的主键nid值。
book1=Book(name='百年孤独',b_a=3) book2=Book(name='陈二狗的妖孽人生',b_a=3) book3=Book(name='海贼王',b_a=3) session.add_all( ( book1, book2, book3 ) ) session.commit()
mysql> select * from book; +-----+--------------------------+------+ | nid | name | b_a | +-----+--------------------------+------+ | 2 | 百年孤独 | 2 | | 3 | 陈二狗的妖孽人生 | 2 | | 4 | 海贼王 | 2 | | 5 | 百年孤独 | 1 | | 6 | 陈二狗的妖孽人生 | 1 | | 7 | 海贼王 | 1 | | 8 | 百年孤独 | 3 | | 9 | 陈二狗的妖孽人生 | 3 | | 10 | 海贼王 | 3 | +-----+--------------------------+------+ 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:
表结构:
class Author(Base): __tablename__='author' username=Column(String(32)) nid=Column(Integer,primary_key=True,autoincrement=True) def __repr__(self): temp='%s--%s'%(self.nid,self.username) return temp class Book(Base): __tablename__ = 'book' nid = Column(Integer, primary_key=True, autoincrement=True) name = Column(String(100)) b_a=Column(Integer,ForeignKey('author.nid')) book=relationship('Author',backref='auth') def __repr__(self): temp = '%s-%s' % (self.nid, self.name) return temp
反向查询:使用子表中定义的列:book=relationship('Author',backref='auth') 建立的虚拟关系列:auth需要注意的是auth是另一个表的对象的集合。
需求场景:作者为:evil,都出那些书籍?
Session=sessionmaker(bind=engine) session=Session() res=session.query(Author).filter(Author.username=='evil').first() for i in res.auth: print(i.name) 百年孤独 陈二狗的妖孽人生 海贼王
正向查询:
需求场景: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中如果查询条件为并的时候,都是用逗号。
Session=sessionmaker(bind=engine) session=Session() ret=session.query(Book).filter(Book.nid.in_((2,3,7)) ).all() for i in ret: print(i.name) 百年孤独 陈二狗的妖孽人生 海贼王
参考: https://blog.csdn.net/GeekLeee/article/details/52806385/
https://www.cnblogs.com/evilliu/articles/5981122.html
标签:__,SQLalchemy,Python,system,nid,django,models,user From: https://www.cnblogs.com/lizexiong/p/17365108.html