是否可以在ORM模型类中编写非ORM模型代码?

时间:2019-03-14 01:35:43

标签: python django django-models

我正在使用Python构建一个非常小的API,并且想知道在使用诸如Django或Flask(带有Peewee或Pony之类的ORM)之类的框架时,将API代码放置在模型类中通常是否可以接受。让我解释一下我的意思...

为说明我的意思,假设我有一个包含所有模型的程序包,然后是另一个包含我的API代码的程序包,当客户端ping我定义的特定路由时执行该程序包。如您所知,这些模型基本上仅用于将对象映射到数据库。尽管在某些情况下,出于某些原因,将某些API代码放在我定义的模型类之一中更有意义。

例如,我有一个将用户映射到数据库的用户模型。另外,在API代码中,我有一个用于登录用户的功能。此功能基本上将cookie设置为登录用户,因此将其放置在API包中可能有意义。但是,我觉得如果将此函数用作方法并将其放置在用户模型中,则它在语义上更有意义,并且可能更易于理解。

class UserModel(Peewee or Pony or Django.model...):
    def login(self):
        """" Login code goes here. Set cookies, login the user, etc. """
        add_cookies(self.username)
        return jsonify({"logged_in": True})  # Flask example...

user = UserModel()
user.login()

但是,这样做的一个警告是,模型代码和API代码不再分离,现在彼此之间非常依赖。

因此,我想我的“客观”问题是关于这些问题的可接受性。使模型(数据库和ORM之类的东西)和API路由保持解耦比将它们组合在一起更好的做法吗?每种方法都有哪些优缺点?最常见和推荐的做法是什么?

先谢谢了。

2 个答案:

答案 0 :(得分:0)

TL; DR:可以在模型类中放置一个函数,但是如果您想进行安全登录,则需要使用Flask-Login之类的东西在令牌中传递登录信息(我不确定等效扩展名是django)。

在类中放置一个函数很好,但是这对于登录来说并不是很安全,所以我建议遵循一个教程来实现安全的登录扩展。

例如,在我的一个项目中,登录页面的视图功能为:

@user.route('/login', methods=['GET', 'POST'])
def login():
    form = LoginForm(next=request.args.get('next'))

    if form.validate_on_submit():
        u = User.find_by_identity(request.form.get('identity'))

        if u and u.authenticated(password=request.form.get('password')):
            if login_user(u, remember=True) and u.is_active():
                # Handle optionally redirecting to the next URL safely.
                next_url = request.form.get('next')
                if next_url:
                    return redirect(safe_next_url(next_url))
                return redirect(url_for('user.settings'))
        else:
            flash('Identity or password is incorrect.', 'error')

return render_template('user/login.html', form=form)

请注意,u.authenticated是我的用户模型类中的一个函数,用于检查用户密码哈希是否正确:

    def authenticated(self, with_password=True, password=''):

    #Ensure a user is authenticated, and optionally check their password.
    if with_password:
        return check_password_hash(self.password, password)

    return True

答案 1 :(得分:0)

TL; DR:您的login方法(仅与HTTP相关的内容)不属于模型层,即周期。

最长的答案:向模型中添加逻辑当然是一个好的设计,但这必须是 domain 逻辑,而不是与UI相关的东西。重点(因为您询问“好的做法”)是使域层(模型)完全独立于UI(视图和控制器),因此您可以将同一域层用于不同的UI(请记住,命令行脚本是UI)。

我不得不处理许多设计不当的应用程序/框架,这些应用程序/框架混合了各种顾虑,并且实际上是必需,无论您想做什么,手头都有一个“请求”(http请求)和“响应”对象而且这些都是一场完整的噩梦,因此从经验上讲,“关注点分离”规则并不是您想要打破的。

请注意,这并不意味着UI层不应该了解域-这是没有意义的,并且实际上从技术POV来说是不可能的。