Допустимо ли написание кода модели без ORM в классе модели ORM? - PullRequest
0 голосов
/ 14 марта 2019

Я создаю очень маленький API с использованием Python, и мне было интересно, допустимо ли вообще размещать код API в классе модели при использовании фреймворков, таких как Django или Flask (с ORM, например, Peewee или Pony). Позвольте мне объяснить, что я имею в виду ...

Чтобы проиллюстрировать, что я имею в виду, представьте, что у меня есть пакет со всеми моими моделями, а затем еще один пакет с моим кодом API, который выполняется, когда клиент пингует определенный маршрут, который я определил. Как вы знаете, модели в основном предназначены только для отображения объектов в базу данных. Хотя при определенных обстоятельствах лично по какой-то причине имеет смысл размещать часть кода API в одном из определенных мной классов моделей.

Например, у меня есть модель User, которая отображает пользователя в базу данных. Кроме того, в коде API у меня есть функция для входа пользователя. Эта функция в основном устанавливает куки для входа в систему пользователя, поэтому может иметь смысл поместить их в пакет 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 голосов
/ 14 марта 2019

TL; DR: ваш метод login - который связан только с HTTP-связью - не относится к слою модели, точка.

Самый длинный ответ: добавление логики в модели, конечно,хороший дизайн, но это должна быть логика domain , а не вещи, связанные с пользовательским интерфейсом.Суть (поскольку вы спрашиваете о «передовой практике») состоит в том, чтобы уровень домена (модели) был полностью независимым от пользовательского интерфейса (представления и контроллеры), чтобы вы могли использовать один и тот же уровень домена с различными пользовательскими интерфейсами (помните, что сценарии командной строки являютсяпользовательский интерфейс тоже).

Мне приходилось работать с несколькими плохо спроектированными приложениями / средами, которые смешивали проблемы и фактически требовали с объектами "request" (http request) и "response"под рукой все, что вы хотели сделать, и это был полный кошмар, с которым вам пришлось столкнуться, так что из опыта правило «разделения интересов» не является чем-то, что вы хотите нарушить.

Просто отметьте, что это не означает, чтоСлой пользовательского интерфейса не должен знать о домене - это не имеет смысла, и на самом деле это просто невозможно из технической точки зрения.

0 голосов
/ 14 марта 2019

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 - это функция в моем классе модели User, которая проверяет, правильно ли хэш пароля пользователя:

    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
...