本博文将一步步揭秘京东等大型网站的领域驱动模型,致力于让读者完全掌握这种网络架构中的 "高富帅"。
python 中并没有类似 java 等其它语言中的接口类型,但是 python 中有抽象类和抽象方法。如果一个抽象类有抽象方法,那么继承它的子类必须实现抽象类的所有方法,因此,我们基于 python 的抽象类和抽象方法实现接口功能。
示例代码:
接口示例代码
- from abc import ABCMeta from abc import abstractmethod#导入抽象方法class Father(metaclass = ABCMeta) : #创建抽象类@abstractmethod def f1(self) : pass@abstractmethod def f2(self) : pass class F1(Father) : def f1(self) : pass def f2(self) : pass def f3(self) : pass obj = F1()
依赖注入的作用是将一系列无关的类通过注入参数的方式实现关联,例如将类 A 的对象作为参数注入给类 B,那么当调用类 B 的时候,类 A 会首先被实例化。
示例代码:
依赖注入示例
- class Mapper: __mapper_ralation = {}@staticmethod def regist(cls, value) : Mapper.__mapper_ralation[cls] = value@staticmethod def exist(cls) : if cls in Mapper.__mapper_ralation: return True
- else: return False@staticmethod def value(cls) : return Mapper.__mapper_ralation[cls] class Mytype(type) : def __call__(cls, *args, **kwargs) : obj = cls.__new__(cls, *args, **kwargs) arg_list = list(args) if Mapper.exist(cls) : value = Mapper.value(cls) arg_list.append(value) obj.__init__( * arg_list) return obj class Foo(metaclass = Mytype) : def __init__(self, name) : self.name = name def f1(self) : print(self.name) class Bar(metaclass = Mytype) : def __init__(self, name) : self.name = name def f1(self) : print(self.name) Mapper.regist(Foo, "666") Mapper.regist(Bar, "999") f = Foo() print(f.name) b = Bar() print(b.name)
注:原理:首先需要明确一切事物皆对象类也是对象,类是有 Type 创建的,当类实例化的时候,会调用 type 类的 call 方法,call 方法会调用 new 方法,new 方法调用 init 方法。
备注:
文件目录:
本文主要以用户管理为例进行介绍,因此我们来关注一下 User.py 文件:
代码结构:
下面对上述代码结构做一一介绍:
- IUseRepository类:接口类,用于约束数据库访问类的方法示例代码:
- class IUseRepository: """
- 用户信息仓库接口
- """def fetch_one_by_user_pwd(self, username, password) : """
- 根据用户名密码获取模型对象
- :param username: 主键ID
- :param password: 主键ID
- :return:
- """def fetch_one_by_email_pwd(self, email, password) : """
- 根据邮箱密码获取模型对象
- :param email: 主键ID
- :param password: 主键ID
- :return:
- """def update_last_login_by_nid(self, nid, current_date) : """
- 根据ID更新最新登陆时间
- :param nid:
- :return:
- """
从上述代码可以看出,数据库访问类如果继承 IUseRepository 类,就必须实现其中的抽象方法。
接下来的三个类,VipType、UserType、User 是与用户信息相关的类,是数据库需要保存的数据,我们希望存入数据库的数据格式为:nid 、username、email、last_login、user_type_id、vip_type_id,其中 User 类用于保存上述数据。因为 user_type_id、vip_type_id 存的是数字,即 user_type_id、vip_type_id 是外键,不能直接在前端进行展示,因此,我们创建了 VipType、UserType 类,用于根据 id,获取对应的 VIP 级别和用户类型。
示例代码:
User 类
- class User: """领域模型"""def __init__(self, nid, username, email, last_login, user_type, vip_type) : self.nid = nid self.username = username self.email = email self.last_login = last_login self.user_type = user_type self.vip_type = vip_type
UserType 类
- class UserType: USER_TYPE = ({
- 'nid': 1,
- 'caption': '用户'
- },
- {
- 'nid': 2,
- 'caption': '商户'
- },
- {
- 'nid': 3,
- 'caption': '管理员'
- },
- ) def __init__(self, nid) : self.nid = nid def get_caption(self) : caption = None
- for item in UserType.USER_TYPE: if item['nid'] == self.nid: caption = item['caption']
- break
- return caption caption = property(get_caption)
VipType 类
- class VipType: VIP_TYPE = ({
- 'nid': 1,
- 'caption': '铜牌'
- },
- {
- 'nid': 2,
- 'caption': '银牌'
- },
- {
- 'nid': 3,
- 'caption': '金牌'
- },
- {
- 'nid': 4,
- 'caption': '铂金'
- },
- ) def __init__(self, nid) : self.nid = nid def get_caption(self) : caption = None
- for item in VipType.VIP_TYPE: if item['nid'] == self.nid: caption = item['caption']
- break
- return caption caption = property(get_caption)
注:VipType、UserType 这两个类获取对应的 caption 均是通过类的普通特性访问,即类似字段方式访问。
接下来的类 UserService 是本 py 文件的重中之重,它负责调用对应的数据库访问类的方法,并被服务层 service 调用,具有承上启下的作用:
示例代码:
- class UserService: def __init__(self, user_repository) : self.userRepository = user_repository def check_login(self, username = None, email = None, password = None) : if username: user_model = self.userRepository.fetch_one_by_user_pwd(username, password)
- else: user_model = self.userRepository.fetch_one_by_email_pwd(email, password) if user_model: current_date = datetime.datetime.now() self.userRepository.update_last_login_by_nid(user_model.nid, current_date) return user_model
这里,我们重点介绍一下上述代码:
初始化参数 user_repository:通过依赖注入对应的数据库访问类的对象;
check_login:访问数据库的关键逻辑处理方法,根据用户是用户名 + 密码方式还是邮箱加密码的方式登录,然后调用对应的数据库处理方法,如果登陆成功,更新时间和最后登录时间,最后将 User 类的实例返回给调用它的服务层 service。(详细见下文数据库处理类的方法)
我们先来看一下对应的数据库处理类中的一个方法:
- 示例代码:
- def fetch_one_by_user_pwd(self, username, password) : ret = None cursor = self.db_conn.connect() sql = """select nid,username,email,last_login,vip,user_type from UserInfo where username=%s and password=%s"""cursor.execute(sql, (username, password)) db_result = cursor.fetchone() self.db_conn.close() if db_result: ret = User(nid = db_result['nid'], username = db_result['username'], email = db_result['email'], last_login = db_result['last_login'], user_type = UserType(nid = db_result['user_type']), vip_type = VipType(nid = db_result['vip'])) return ret
这里我们使用 pymysql 进行数据库操作,以用户名 + 密码登陆为例,如果数据库有对应的用户名和密码,将查询结果放在 User 类中进行初始化,至此,ret 中封装了用户的全部基本信息,将 ret 返回给上面的 check_login 方法,即对应上文中的返回值 user_model,user_model 返回给调用它的服务层 service。
总结:Molde 最终将封装了用户基本信息的 User 类的实例返回给服务层 service。
service 也是一个承上启下的作用,它调用 Moldel 文件对应的数据库业务协调方法,并被对应的 UI 层调用(本例中是 UIadmin)。
目录结构:
同样的,我们只介绍 User 文件夹:它包含 4 个 py 文件:
下面对上述目录做详细代码:
ModelView:
- class UserModelView: def __init__(self, nid, username, email, last_login, user_type_id, user_type_caption, vip_type_id, vip_type_caption) : self.nid = nid self.username = username self.email = email self.last_login = last_login self.user_type = user_type_id self.user_type_caption = user_type_caption self.vip_type = vip_type_id self.vip_type_caption = vip_type_caption
注:对 user_type_id、vip_type_id 增加对应的用户类型和 VIP 级别,即将外键数据对应的 caption 放在外键后面,作为增加的参数。
Request:
- class UserRequest: def __init__(self, username, email, password) : self.username = username self.email = email self.password = password
Response:
- class UserResponse: def __init__(self, status = True, message = '', model_view = None) : self.status = status#是否登陆成功的状态self.message = message#错误信息self.modelView = model_view#登陆成功后的用户数据
- UserService:
- class UserService: def __init__(self, model_user_service) : #通过依赖注入Moldel对应的数据库业务协调方法,此例中对应上文中的user_service self.modelUserService = model_user_service def check_login(self, user_request) : #核心服务层业务处理方法response = UserResponse()#实例化返回类
- try: model = self.modelUserService.check_login(user_request.username, user_request.email, user_request.password)#接收上文中的用户基本信息,是User类的实例
- if not model: raise Exception('用户名或密码错误')
- else: #如果登陆成功,通过UserModelView类格式化返回前端的数据model_view = UserModelView(nid = model['nid'], username = model['usename'], email = model['email'], last_login = model['last_login'], user_type_id = model['user_type'].nid, user_type_caption = model['user_type'].caption, vip_type_id = model['vip_type'].nid, vip_type_caption = model['vip_type'].caption, ) response.modelView = model_view#定义返回UI层的用户信息except Exception as e: response.status = False response.message = str(e)
总结:至此,Service 返回给 Ui 层的数据是是否登陆成功的状态 status、错误信息、已经格式化的用户基本信息。
UI 层主要负责业务处理完成后与前端的交互,它是服务层 Service 的调用者:
示例代码:
- from..Core.HttpRequest import AdminRequestHandler from Service.User.Service import UserService class Foo: #便于前端使用属性获取数据pass class Login(AdminRequestHandler) : def get(self, *args, **kwargs) : user_request = Foo()#获取用户输入的用户名邮箱密码,并封装进user_request对象user_request.name = self.get_argument('name', None) user_request.email = self.get_argument('email', None) user_request.password = self.get_argument('password', None) obj = UserService.check_login(user_request)#获取服务端Service的返回值self.render('Account/Login.html', obj = obj)#传入前端,并渲染def post(self, *args, **kwargs) : pass
总结以上就是基于领域驱动模型的用户管理后台,包含数据库操作文件,数据库业务处理文件,服务端文件,UI 层文件。如果本文对您有参考价值,欢迎帮博主点下文章下方的推荐,谢谢!
来源: http://www.cnblogs.com/wanghzh/p/5847643.html