表和表的之間關系,往往通過外鍵建立關系,那簡單介紹下外鍵。
一: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 海賊王