在SQLAlchemy中使用数据库外键约束

1.SQLAlchemy外键及其约束

  • 外键可以使得几张表格之间联系更加紧密
from sqlalchemy import create_engine, and_, or_
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, DECIMAL, Boolean, Enum, DATE, DATETIME, Time, Text, ForeignKey
from sqlalchemy.dialects.mysql import LONGTEXT
from sqlalchemy.orm import sessionmaker
from datetime import datetime
import random
from sqlalchemy import func

HOSTNAME = '127.0.0.1'
DATABASE = 'flask_orm'
PORT = 3306
USERNAME = 'root'
PASSWORD = 'root'

DB_URL = 'mysql+pymysql://{}:{}@{}:{}/{}'.format(USERNAME, PASSWORD, HOSTNAME, PORT, DATABASE)

engine = create_engine(DB_URL)
Base = declarative_base(engine)


class User(Base):
    __tablename__ = 'users'

    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(String(50))

    def __str__(self):
        return 'User(name:{})'.format(self.name)


class Book(Base):
    __tablename__ = 'books'

    id = Column(Integer, primary_key=True, autoincrement=True)
    title = Column(String(50), nullable=False)
    content = Column(Text, nullable=False)
    uid = Column(Integer, ForeignKey('users.id', ondelete='RESTRICT'))


# Base.metadata.drop_all()
# Base.metadata.create_all()
Session = sessionmaker(bind=engine)
session = Session()

user = User(name='吴承恩')
session.add(user)
session.commit()

book = Book(title='西游记', content='三打白骨精', uid=1)
session.add(book)
session.commit()

# 外键的查询
# book1 = session.query(Book).first()
# id = book1.uid
# user = session.query(User).get(id)
# print(user)

user = session.query(User).filter(User.id == Book.uid).first()
print(user)

#外键的几种约束
RESTRICT:引用的父表被删除,将会阻止删除
NO ACTION:等同于RESTRICT
CASCADE:同时一起删除
SET NULL:父表可以被删除,子表数据设置为null

表与表之间的关系:

  • 一对多:
from sqlalchemy import create_engine, and_, or_
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, DECIMAL, Boolean, Enum, DATE, DATETIME, Time, Text, ForeignKey
from sqlalchemy.dialects.mysql import LONGTEXT
from sqlalchemy.orm import sessionmaker, relationship
from datetime import datetime
import random
from sqlalchemy import func

HOSTNAME = '127.0.0.1'
DATABASE = 'flask_orm'
PORT = 3306
USERNAME = 'root'
PASSWORD = 'root'

DB_URL = 'mysql+pymysql://{}:{}@{}:{}/{}'.format(USERNAME, PASSWORD, HOSTNAME, PORT, DATABASE)

engine = create_engine(DB_URL)
Base = declarative_base(engine)


class User(Base):
    __tablename__ = 'users'

    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(String(50))

    book = relationship('Book')

    def __str__(self):
        return 'User(name:{})'.format(self.name)


class Book(Base):
    __tablename__ = 'books'

    id = Column(Integer, primary_key=True, autoincrement=True)
    title = Column(String(50), nullable=False)
    content = Column(Text, nullable=False)
    uid = Column(Integer, ForeignKey('users.id', ondelete='RESTRICT'))
    author = relationship('User')#加上这句话才能构成表与表之间的联系

    def __str__(self):
        return 'Book(title:{})'.format(self.title)

# Base.metadata.drop_all()
# Base.metadata.create_all()
Session = sessionmaker(bind=engine)
session = Session()

# user = session.query(Book).first()
# print(user.uid)
#
# u = session.query(User).filter(Book.id == user.uid).first()
# print(u)

# data = session.query(Book).first()
# print(data.author)

# data = session.query(User).first()
# print(data.book)  # 一对多,输出的是列表[<__main__.Book object at 0x000002802D94C4C8>, <__main__.Book object at 0x000002802D94C648>]
# for i in data.book:
#     print(i)

user = User(name='施耐庵')

book = Book(title='水浒传',content='saf')
book2 = Book(title='笑傲江湖', content='令狐冲')

book.author = user
book2.author = user

session.add_all([book,book2])
session.commit()
  • 一对一:就是特殊的一对多,只需要在addresses = relationship(“Address”, backref=‘addresses’, uselist=False)在里边加上uselist=False即可
from sqlalchemy import create_engine, and_, or_
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, DECIMAL, Boolean, Enum, DATE, DATETIME, Time, Text, ForeignKey
from sqlalchemy.dialects.mysql import LONGTEXT
from sqlalchemy.orm import sessionmaker, relationship
from datetime import datetime
import random
from sqlalchemy import func

HOSTNAME = '127.0.0.1'
DATABASE = 'flask_orm'
PORT = 3306
USERNAME = 'root'
PASSWORD = 'root'

DB_URL = 'mysql+pymysql://{}:{}@{}:{}/{}'.format(USERNAME, PASSWORD, HOSTNAME, PORT, DATABASE)

engine = create_engine(DB_URL)
Base = declarative_base(engine)


class User(Base):
    __tablename__ = 'user'
    id = Column(Integer, primary_key=True)
    name = Column(String(50))
    fullname = Column(String(50))
    password = Column(String(100))

    addresses = relationship("Address", backref='addresses', uselist=False)#backref加上去就不用在其他表里添加。这个表示反向联系


class Address(Base):
    __tablename__ = 'addresses'
    id = Column(Integer, primary_key=True)
    email_address = Column(String(50))
    user_id = Column(Integer, ForeignKey('user.id'))
    # user = relationship('Address', backref='user')

Base.metadata.drop_all()
Base.metadata.create_all()
Session = sessionmaker(bind=engine)
session = Session()

user = User(name='duke', fullname='dk', password='123')
address = Address(email_address='xxxx.com')

user.addresses = address
session.add(user)
session.commit()
  • 多对多:创建这种类型的关系表需要建立一个中间表,导入table模块
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String ForeignKey
from sqlalchemy.orm import sessionmaker, relationship, backref
from sqlalchemy import func
from sqlalchemy import Table

HOSTNAME = '127.0.0.1'
DATABASE = 'flask_orm'
PORT = 3306
USERNAME = 'root'
PASSWORD = 'root'

DB_URL = 'mysql+pymysql://{}:{}@{}:{}/{}'.format(USERNAME, PASSWORD, HOSTNAME, PORT, DATABASE)

engine = create_engine(DB_URL)
Base = declarative_base(engine)

# 创建中间表格,是为了保存两个表格的外键
teacher_classes = Table(
    'teacher_classes',
    Base.metadata,
    Column('teacher_id', Integer, ForeignKey('teacher.id')),
    Column('classes_id', Integer, ForeignKey('classes.id')),
)
# 中间表第一个参数表示它的表名,第二个参数是base基类的类,第三第四个参数表示要连接的两个表

class Teacher(Base):
    __tablename__ = 'teacher'

    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(String(50))

    classes = relationship('Classes', backref='teachers', secondary=teacher_classes)

    def __str__(self):
        return 'Teacher(name:{})'.format(self.name)

class Classes(Base):
    __tablename__ = 'classes'

    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(String(50))

    def __str__(self):
        return 'Classes(name:{})'.format(self.name)

# Base.metadata.drop_all()
# Base.metadata.create_all()
Session = sessionmaker(bind=engine)
session = Session()

# teacher1 = Teacher(name='lihua')
# teacher2 = Teacher(name='duke')

# class1 = Classes(name='一班')
# class2 = Classes(name='二班')
#
# teacher1.classes.append(class1)
# teacher1.classes.append(class2)
#
# teacher2.classes.append(class1)
# teacher2.classes.append(class2)
#
# session.add_all([teacher1, teacher2])
# session.commit()

# 根据老师查班级
teacher = session.query(Teacher).first()
print(teacher)
for i in teacher.classes:
    print(i)

# 根据班级查老师
class1 = session.query(Classes).first()
print(class1)
for i in class1.teachers:
    print(i)

2.排序和查询高级order_by

排序

order_by:根据指定的字段进行排序,默认是升序排序,若在前面加上-表示降序排序

#默认是升序
article = session.query(Article).order_by(Article.id).all()
#倒序查询(-Article.id)或者调用desc()
article = session.query(Article).order_by(Article.id.desc()).all()
article = session.query(Article).order_by(-Article.id).all()

order_by也可以在模型中定义:

 __mapper_args__ = {
     "order_by": title
 }
 表示按照title字段进行排序。

代码示例:

from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String ForeignKey
from sqlalchemy.orm import sessionmaker, relationship, backref

HOSTNAME = '127.0.0.1'
DATABASE = 'flask_orm'
PORT = 3306
USERNAME = 'root'
PASSWORD = 'root'

DB_URL = 'mysql+pymysql://{}:{}@{}:{}/{}'.format(USERNAME, PASSWORD, HOSTNAME, PORT, DATABASE)

engine = create_engine(DB_URL)
Base = declarative_base(engine)


class Article(Base):
    __tablename__ = 'article'

    id = Column(Integer, primary_key=True, autoincrement=True)
    title = Column(String(50))

#该方法可以直接在模型中定义默认的排序
    __mapper_args__ = {
        'order_by':id
    }
    def __str__(self):
        return 'Article(title:%s)'% self.title

# Base.metadata.drop_all()
# Base.metadata.create_all()
Session = sessionmaker(bind=engine)
session = Session()

# for i in range(6):
#     article = Article(title='文章%s'%i)
#     session.add(article)
#
# session.commit()

#默认是升序
# article = session.query(Article).order_by(Article.id).all()
#倒序查询
# article = session.query(Article).order_by(Article.id.desc()).all()
# for item in article:
#     print(item)

# limit 限制查询条数
# article = session.query(Article).limit(3).all()

# offset 从哪条开始查询
# article = session.query(Article).offset(2).limit(3).all()

# 切片,把所有的数据全部取出来再显示出来
article = session.query(Article).all()[2:5]
for item in article:
    print(item)
  • 高级查询
  1. group_by:根据某个字段进行分组
result = session.query(User.gender, func.count(User.id)).group_by(User.gender).all()
  1. having:进一步过滤查找结果
result = session.query(User.age, func.count(User.age)).group_by(User.age).having(User.age<25).having(User.age>19).all()
  1. join方法:分为inner join 以及outer join。默认的是inner join,而left join和right join都是outer join。
for u,a in session.query(User,Address).filter(User.id==Address.user_id).all():
    print(u)
    print(a)

而outer join默认为左外查询

for instance in session.query(User,Address).outerjoin(Address).all():
	print(instance)
  • 别名:用于多表查询时重复使用一个表。
from sqlalchemy.orm import aliased
adalias1 = aliased(Address)
adalias2 = aliased(Address)
for username,email1,email2 in session.query(User.name,adalias1.email_address,adalias2.email_address).join(adalias1).join(adalias2).all():
    print(username,email1,email2)
  • 子查询:可以在已经查询的数据里再次查询其他数据
from sqlalchemy import create_engine, and_, or_
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, DECIMAL, Boolean, Enum, DateTime, TEXT, ForeignKey
from sqlalchemy.dialects.mysql import LONGTEXT
from sqlalchemy.orm import sessionmaker, relationship
from datetime import datetime
from sqlalchemy import func
import random
from sqlalchemy import Table

HOSTNAME = '127.0.0.1'
DATABASE = 'class'
PORT = 3306
USERNAME = 'root'
PASSWORD = 'root'

DB_URL = 'mysql+pymysql://{}:{}@{}:{}/{}'.format(USERNAME, PASSWORD, HOSTNAME, PORT, DATABASE)

engine = create_engine(DB_URL)
Base = declarative_base(engine)


class User(Base):
    __tablename__ = 'user2'

    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(String(50))
    city = Column(String(50))
    age = Column(Integer)

    def __str__(self):
        return 'User(name:%s)' % self.name


# Base.metadata.drop_all()
# Base.metadata.create_all()

Session = sessionmaker(bind=engine)
session = Session()



# 子查询
# user = session.query(User).filter(User.name == '张三').first()
# # print(user)
# data = session.query(User).filter(User.city == user.city, User.age == user.age).all()
# for item in data:
#     print(item)

sub = session.query(User.city.label('city'), User.age.label('age')).filter(User.name == '张三').subquery()
data = session.query(User).filter(User.city == sub.c.city, User.age == sub.c.age).all()
for item in data:
    print(item)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值