sqlalchemy外鍵和relationship查詢


前面的文章中講解了外鍵的基礎知識和操作,上一篇文章講解了sqlalchemy的基本操作。前面兩篇文章都是作為鋪墊,為下面的文章打好基礎。記得初一時第一次期中考試時考的不好,老爸安慰我說:“學習是一個循序漸進的過程”,而我的就是按照這樣思路來學習數據庫外鍵。首先是了解外鍵基礎理論,然后是sqlalchemy基本操作,最后才到sqlalchemy操作外鍵。

一、sqlalchemy體現的外鍵特性

1.外鍵回顧

外鍵的出現是因為兩張表之間需要有關聯,為了保證數據的完整性和唯一性而產生的。有外鍵時會有兩張以上的表,分為主表和附表。附表中數據往往是主表中數據的延伸,附表中有外鍵關聯到主表的主鍵上。

在sqlalchemy的ORM模型中,定義表時指定主鍵和外鍵。

主鍵定義:在字段信息后面加上primary_key=True

name = Column(String(20),primary_key=True)

外鍵定義:在字段后面加上Foreignkey(主表.主鍵)

company_name = Column(String(32),ForeignKey("company.name"))
company = relationship("Company",backref="phone_of_company") 

另外在定義主鍵時往往還會定義一個relationship,什么作用呢?下文見分曉。

2.定義表

定義兩張表,company和phone,company中的name是主鍵,phone中的id是主鍵,並且phone中定義company_name為外鍵。

sql_foreign_models.py

#coding:utf-8
  
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column,Integer,String,DATE,ForeignKey  #導入外鍵
from sqlalchemy.orm import  relationship  #創建關系
  
engine = create_engine("mysql+mysqldb://root:123@localhost:3306/test",
                        encoding="utf-8")
 
Base = declarative_base() #生成orm基類

class Company(Base):

    __tablename__ = "company"

    name = Column(String(20),primary_key=True)
    location = Column(String(20))
  
    def __repr__(self):
        return "name:{0} location:{1}".format(self.name,self.location)
  
class Phone(Base):
     
    __tablename__ = "phone"

    id = Column(Integer,primary_key=True)
    model = Column(String(32))
    price = Column(String(32))
    company_name = Column(String(32),ForeignKey("company.name"))
    company = relationship("Company",backref="phone_of_company") 
  
    def __repr__(self):
        return "{0} model:{1},sales:{2} sales:{3} price:{4}".format(self.id,self.model,self.sales,self.price)
  
Base.metadata.create_all(engine) #創建表

 

3.創建表

python sql_foreign_models.py

4.插入數據

sql_insert.py 

#coding:utf-8

from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.dialects.mysql import INTEGER,CHAR
from sqlalchemy import create_engine,Column


def insert(new_data):

    Base = declarative_base()   
#修改用戶名、密碼、數據庫的名字 engine
= create_engine('mysql+mysqldb://root:123@localhost:3306/test') print "創建數據庫引擎" DBSession = sessionmaker(bind=engine) session = DBSession() print "創建session對象" session.add(new_data) print "添加數據到session" session.commit() print "提交數據到數據庫" session.close() print "關閉數據庫連接" if __name__ == "__main__": insert(User)

 

sql_foreign_insert.py

#coding:utf-8
  
from sql_foreign_models import * 
from sql_insert import *
  
companys = {
            "Apple":"Amercian",
            "Xiaomi":"China",
            "Huawei":"China",
            "Sungsum":"Korea",
            "Nokia":"Finland"
           }
phones = (
        [1,"iphoneX","Apple",8400],
        [2,"xiaomi2s","Xiaomi",3299],
        [3,"Huaweimate10","Huawei",3399],
        [4,"SungsumS8","SungSum",4099], 
        [5,"NokiaLumia","Nokia",2399],
        [6,"iphone4s","Apple",3800]
         )        
 
 
for key in companys:
    new_company = Company(name=key,location=companys[key]) 
    insert(new_company)
 
for phone in phones:
    id = phone[0]
    model = phone[1]
    company_name = phone[2]
    price = phone[3]
 
    new_phone = Phone(id=id,model=model,company_name=company_name,price=price)
    insert(new_phone)

 

寫入數據庫

python sql_foreign_insert.py

5.sqlalchemy外鍵操作

總結外鍵的優點有兩個:保證數據的完整性和保證數據的一致性。那么在sqlqlchemy如何體現完整性和一致性呢?通過數據的插入和刪除來體現。

 

完整性:附表插入數據時會檢查外鍵所在字段在主表中是否存在

在phone表中插入數據:(7,Blackberry,“RIM”,3200)黑莓手機,所在公司是RIM。

new_phone = Phone(id=7,model="BlackBerry",company_name="RIM",price=3200)
insert(new_phone)

報錯:不能添加或者更新一個子行,有一個外鍵關聯。

因為主表company的主鍵,也就是phone外鍵關聯的字段沒有“RIM”,所以當phone寫入數據時會檢查company_name字段的值是否在company中存在。而company中不存在該值,所以不能寫入。這樣做就保證了數據的完整性。

 

一致性:一致性表現在增刪改查外鍵時,主表相對應數據的處理。一致性的規則有多個,具體如下引用:

 

外鍵約束對父表的含義:
   在父表上進行update/delete以更新或刪除在子表中有一條或多條對應匹配行的候選鍵時,父表的行為取決於:在定義子表的外鍵時指定的on update/on delete子句, InnoDB支持5種方式, 分列如下
  
   . cascade方式
在父表上update/delete記錄時,同步update/delete掉子表的匹配記錄
On delete cascade從mysql3.23.50開始可用; on update cascade從mysql4.0.8開始可用

   . set null方式 
在父表上update/delete記錄時,將子表上匹配記錄的列設為null
要注意子表的外鍵列不能為not null
On delete set null從mysql3.23.50開始可用; on update set null從mysql4.0.8開始可用

   . No action方式
如果子表中有匹配的記錄,則不允許對父表對應候選鍵進行update/delete操作
這個是ANSI SQL-92標准,從mysql4.0.8開始支持

   . Restrict方式
同no action, 都是立即檢查外鍵約束 

  

刪除主表中的name=Sungsum的記錄。

engine = create_engine('mysql+mysqldb://root:123@localhost:3306/test')

DBSession = sessionmaker(bind=engine)
session = DBSession()

company = session.query(Company).filter_by(name="Sungsum").first()
session.delete(company)
session.commit()

 默認的外鍵關聯的動作是  “.set null”,即主表刪除數據,附表中關聯的字段設為空。

 除了默認的設置外,還可以選擇:

1、刪除主表數據,如果附表有記錄則不允許刪除

2、刪除主表數據,如果附表有記錄則一並刪除 

 

二、外鍵和查詢

在數據結構上外鍵對連表查詢並沒有太多的幫助,但是在sqlalchemy的模型下外鍵對連表查詢有一定的優化,那就是relationship字段,其配合外鍵一起使用。

在沒有relationship字段時,如果想要查詢xiaomi2s手機的生產公司的地址如何查詢呢?分為兩步走:

  1. 查詢出phone表中xiaomi2s的company_name字段
  2. 通過company_name字段查詢company表中的location字段。(phone.company_name==company.name)

有了relationship之后就不用分為兩步走了,只需要一步就能搞定。在定義表的模型時,relationship將company和phone表關聯在一起。phone表中定義:

company_name = Column(String(32),ForeignKey("company.name"))
company = relationship("Company",backref="phone_of_company") 

表明將phone表和Company表聯系在一起。backref是反向關聯,使用規則是:

  1. company是主表,phone是從表。查詢phone表,返回phone_obj,可以通過phoen_obj.Company查詢到company中外鍵關聯的數據。查phone表返回company表里的數據。這個稱之為:正向查詢。
  2. company是主表,phone是從表。查詢company表,返回company_obj,可以通過company_obj.phone_of_company查詢到phone表的外鍵關聯數據。查company表返回phone表里的數據。這個稱之為:反向查詢。

 

1.正向查詢

#coding:utf-8
 
from sqlalchemy.orm import  sessionmaker
from sqlalchemy import create_engine
from sql_foreign import *
 
#修改用戶名、密碼和數據庫的名稱為自己的
engine = create_engine("mysql+mysqldb://root:123@localhost:3306/test",)
Session_class = sessionmaker(bind=engine)
session = Session_class()
 
#查詢phone表
phone_obj = session.query(Phone).filter_by(id = 1).first()
#通過phone表關聯的relationship字段"Company"查詢出company表的數據
print(phone_obj.company.name)
print(phone_obj.company.location)

 

通過查詢phone得到company表中的字段,起作用的是relationship中的Company字段。

 

2.反向查詢

#coding:utf-8
 
from sqlalchemy.orm import  sessionmaker
from sqlalchemy import create_engine
from sql_foreign_models import *

engine = create_engine("mysql+mysqldb://root:123@localhost:3306/test",)
Session_class = sessionmaker(bind=engine)
session = Session_class()

#查詢company表
company_obj = session.query(Company).filter_by(name = "Nokia").first()

#通過phone表關聯的relationship的字段"backref="phone_of_company"",查詢phone表數據
print company_obj.phone_of_company[0].id
print company_obj.phone_of_company[0].model
print company_obj.phone_of_company[0].price
print company_obj.phone_of_company[0].company_name 

通過查詢company得到phone表中的字段,起作用的是relationship中的phone_of_compamy字段。

 

外鍵還有更多操作,比如在刪除主表時附表的動作。等到下次需要使用時再補上,我相信不會等太久。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM