關系資料庫是建立在關系模型基礎上的資料庫,是以表之間的關系在資料庫程式設計中尤為重要。本節圍繞在SQLAlchemy中如何定義關系及如何使用關系進行查詢進行講解,使讀者能夠快速掌握SQLAlchemy的關系操作。
1、案例
設計3個實體表:班級表class、學生表student、老師表teacher和1個關系表:class_teacher。班級與學生為一對多關系,班級與老師之間為多對多關系。
from sqlalchemy import Table,Column,Integer,ForeignKey,String
from sqlalchemy.orm import relationship,backref
from sqlalchemy.ext.declarative import declarative_base
Base=declarative_base()
class Class(Base):
__tablename__='class'
class_id=Column(Integer,primary_key=True)
name=Column(String(50))
level=Column(Integer)
address=Column(String(50))
class_teachers=relationship("ClassTeacher",backref="class")
students=relationship("Student",backref="class")
class Student(Base):
__tablename__='student'
student_id=Column(Integer,primary_key=True)
name=Column(String(50))
age=Column(Integer)
gender=Column(String(10))
address=Column(String(50))
class_id=Column(Integer,ForeignKey('class.id'))
class Teacher(Base):
__tablename__='teacher'
teacher_id=Column(Integer,primary_key=True)
name=Column(String(50))
gender=Column(String(10))
telephone=Column(String(50))
address=Column(String(50))
class_teachers=relationship("ClassTeacher",backref="teacher")
class ClassTeacher(Base):
__tablename__='class_teacher'
teacher_id=Column(Integer,ForeignKey('teacher.teacher_id'),primary_key=True)
class_id=Column(Integer,ForeignKey("class.id"),primary_key=True)
代碼中用了4個SQLAlchemy模型對4個表進行了定義,其中與關系定義相關的部分如下:
外鍵設定:在列的定義中,為Column傳入ForeignKey進行外鍵設定。
class_id=Column(Integer,ForeignKey('class.id'))
關系設定:通過relationship關鍵字在父模型中建立對字表的引用,例如Class模型中的關系設定如下:
students=relationship("Student",backref="calss")
其中的backref參數為可選參數,如果設定backref,則此語句同時設定了 從父表對子表的引用。
一對多關系的使用:以後可以直接通過該students屬性獲得相關班級中所有學生的資訊。如下代碼可以列印班級【三年二班】的所有學生資訊。
class=session.query(Class).filter(Clss.name=="三年二班").first()
for student in class_.students:
print(student)
多對多關系的使用:通過關聯模型ClassTeacher實作,在其中分别設定模型Class和Teacher的外鍵,并且在父模型中設定相應的relationship實作。多對多關系也可以想象成一個關聯表,分别對兩個父表實作了多對一的關系。班級與老師之間為多對多的關系,如下代碼可以列印班級【三年二班】中所有老師的資訊
class=session.query(Class).filter(Class.name=="三年二班").first()
for class_teacher in class_.class_teachers:
teacher=class_teacher.teacher
print(teacher)
上述代碼中class_teacher.teacher是在模型teacher中針對ClassTeacher定義的反向引用。
2、連接配接查詢
在實際開發中,有了關系就必不可少地會有多表連接配接查詢的需求。下面通過實際例子示範如果進行多表連接配接查詢。
在查詢語句中可以使用join關鍵字進行連接配接查詢,列印出所有三年級學生的姓名:
students=session.query(Student).join(Class).filter(Class.level==3).all()
for student in students:
print(student.namr)
上述查詢函數會自動把外鍵關系作為連接配接條件,該查詢被SQLAlchemy自動翻譯為如下SQL語句并執行:
SELECT student.student_id AS student_student_id,
student.name AS student.name,
student.age AS student.age,
student.gender AS student.gender,
student.address AS student.address,
student.class_id AS student_class_id
FROM student JOIN class ON student.class_id=class.class_id
WHERE class.leve=?
(3,)
如果需要将被連接配接表的内心同樣列印出來,則可以在query中指定多個表對象。
下面的語句在列印出所有三年級學生姓名的同時,列印出其所在班級的名字。
for student,class_ in session.query(Student,Class).join(Class).filter(Class.level==3).all():
print(student.name,class_.name)
上述查詢函數會自動把外鍵關系作為連接配接條件,該查詢被SQLAlchemy自動翻譯為如下SQL語句并執行:
SELECT student.student_id AS student_student_id,
student.name AS student.name,
student.age AS student.age,
student.gender AS student.gender,
student.address AS student.address,
student.class_id AS student_class_id,
class.class_id AS class_class_id,
class.name AS class_name,
class.level AS class_level,
class.address AS class_location
FROM student JOIN class ON student.class_id=class.class_id
WHERE class.leve=?
(3,)
如果需要用除外鍵外的其他字段作為連接配接條件,則需要開發者在join中自行設定。下面列印出所有班級的address與學生的address相同的學生的姓名:
for student_name, in session.query(Student.name).join(Class,Class.address==Student.address).filter(Class.level==3).all():
print(student_name)
上述查詢函數根據開發者指定的語句作為連接配接條件,并且因為直接指定了被查詢的字段,是以減少了實際SQL中的被查詢字段,提高了性能。該查詢被SQLAlchemy自動翻譯為如下SQL語句執行:
SELECT student.name AS student_name, FROM student JOIN class ON student.address=class.address