使用sqlalchemy的时候经常会用到高级功能,使用关系型数据库的“关系”。

测试环境: OSX 10.12 pycharm python3.6 sqlalchemy-1.1.10

首先建立一个用户类 user.py:

# -*- encoding:utf-8 -*-
from sqlalchemy import Column, Integer, String, DateTime  
from werkzeug.security import generate_password_hash, check_password_hash  
import datetime  
from app.models import Base  
from sqlalchemy.orm import relationship


class User(Base):  
    '''
    用户数据表节构
    不一定需要__init__方法,在Base中存在构造函数,自动实例化
    '''
    __tablename__ = 'user'

    id = Column(Integer, primary_key=True, autoincrement=True)
    username = Column(String(128), index=True, unique=True, nullable=False)
    password_hash = Column(String(128), nullable=False)
    level = Column(Integer)
    mobile = Column(String(20), nullable=True)
    email = Column(String(32), unique=True, nullable=False)
    nickname = Column(String(32), nullable=True)
    created = Column(DateTime, nullable=False)

    device_group = relationship("DeviceGroup", backref="user")

#######下面跟常规定义没有区别###########


    def __init__(self, username, email, password, level, mobile, nickname):
        self.username = username
        self.email = email.lower()
        self.hash_password(password)
        self.level = level
        self.mobile = mobile
        self.nickname = nickname
        self.created = datetime.datetime.now()

    def hash_password(self, password):
        '''
        对用户注册时候使用的密码进行单项hash加密,并转存为password_hash字段
        :param password: 用户密码明码
        :return: 不返回信息,直接修改用户提交的password到password_hash字段
        '''
        self.password_hash = generate_password_hash(password)

    def verify_password(self, password):
        '''
        验证用户密码,把用户输入的密码做hash并与数据库中的密码进行比较
        :param password: 用户密码
        :return: True/False
        '''
        return check_password_hash(self.password_hash, password)

    def is_authenticated(self):
        return True

    def is_active(self):
        return True

    def is_anonymous(self):
        return False

    def get_id(self):
        return self.id

    def __repr__(self):
        '''
        重构__repr__方法后,不管直接输出对象还是通过print打印的信息都按我们__repr__方法中定义的格式进行显示了
        :return:user对象包含以下属性
        '''
        return "<User(username='%s', level='%s', mobile='%s', email='%s',nickname='%s', created='%s')>" % (
            self.username, self.level, self.mobile, self.email, self.nickname, self.created)

与常规定义不一样的地方就是最后一行,注意最后一行里面device_group是属于User对象的属性,但是它并不影响User数据表。

随后,建一个需要与这个类“发生关系”的类,我使用了device_group.py

# -*- encoding:utf-8 -*-
from sqlalchemy import Column, Integer, String, DateTime, ForeignKey  
import datetime  
from app.models import Base

class DeviceGroup(Base):  
    '''
    设备组数据表节构
    '''
    __tablename__ = 'device_group'
    id = Column(Integer, primary_key=True, autoincrement=True)
    username = Column(String(128), ForeignKey('user.username'), index=True, nullable=False)
    group_name = Column(String(128), nullable=False)
    created = Column(DateTime, nullable=False)
    status = Column(Integer)
    remarks = Column(String(256), nullable=True)

#######下面跟常规定义没有区别###########
   def __init__(self, group_name, status, remarks):
        self.group_name = group_name
        self.created = datetime.datetime.now()
        self.status = status
        self.remarks = remarks

    def __repr__(self):
        '''
        重构__repr__方法后,不管直接输出对象还是通过print打印的信息都按我们__repr__方法中定义的格式进行显示了
        :return:device_group对象包含以下属性
        '''
        return "<DeviceGroup(id='%s', username='%s' group_name='%s', created='%s', status='%s', remarks='%s')>" % \
               (self.id, self.username, self.group_name, self.created, self.status, self.remarks)

这里需要注意的地方是导入了ForeignKey,并在DeviceGroup 类的username属性定义中使用ForeignKey('user.username'),此时 DeviceGroup 里面的username就follow了 User里面的username, 在新建DeviceGroup的时候会根据User里面的username自动填充username

请注意第一段代码中 device_group = relationship("DeviceGroup", backref="user")

与第二段代码username = Column(String(128), ForeignKey('user.username'), index=True, nullable=False) 测试程序 relation-test.py

中两个 user 的对应关系。

# 做 relationship 测试,使用 user 和 device_group 表测试

from app.controller import session  
import app.models.user as muser  
from app.models.device_group import DeviceGroup

qinfei = muser.User(username="rela-test", email="rela@163.com", password="1234567890", level=0, mobile="18888888888", nickname="hahahaha")  
dg1 = DeviceGroup(group_name="relation-test", status=0, remarks="relation-test")  
qinfei.device_group.append(dg1)  
print(qinfei)  
session.add(qinfei)  
session.commit()  

测试结果:

数据表中成功建立对应 user 和 device_group 记录