Необработанный запрос Flask / SQL Alchemy вместо метода класса - PullRequest
0 голосов
/ 23 октября 2018

Я признаю, что это странный вопрос, прежде чем я его задам. Мне интересно, возможно ли реплицировать методы класса Flask / SQL Alchemy с использованием необработанного SQL вместо использования самих методов?

Короче говоря, мои товарищи по команде и я занимаемся проектированием базы данныхКонечно, и теперь мы находимся в стадии реализации, где мы кодируем приложение, основанное на нашей схеме схемы БД.Мы хотим, чтобы все было просто, поэтому мы выбрали Flask в Python.Мы следуем Flask Mega Tutorial , который является обучающим уроком о том, как создать базовый сайт, как мы делаем.Мы только что закончили Глава 5: логины пользователей и продолжаем.

В скрипте app/routes.py учебник что-то делает, чтобы получить информацию о пользователе.Вот пример маршрута входа в систему для примера приложения:

from flask_login import current_user, login_user
from app.models import User

# ...

@app.route('/login', methods=['GET', 'POST'])
def login():
    if current_user.is_authenticated:
        return redirect(url_for('index'))
    form = LoginForm()
    if form.validate_on_submit():
        user = User.query.filter_by(username=form.username.data).first()
        if user is None or not user.check_password(form.password.data):
            flash('Invalid username or password')
            return redirect(url_for('login'))
        login_user(user, remember=form.remember_me.data)
        return redirect(url_for('index'))
    return render_template('login.html', title='Sign In', form=form)

Мне интересна строка user = User.query.filter_by(username=form.username.data).first(). По сути, эта строка создает экземпляр класса User, который является моделью базы данных из SQLАлхимия, и получает информацию о пользователе с адреса электронной почты, который они ввели.Вызов этих методов генерирует SQL-оператор, подобный следующему:

SELECT `User`.`userID` AS `User_userID`,
       `User`.user_email AS `User_user_email`,
       `User`.user_first_name AS `User_user_first_name`,
       `User`.user_last_name AS `User_user_last_name`,
       `User`.user_password AS `User_user_password`
FROM `User`
WHERE `User`.user_email = 'test@test.com'
LIMIT 1

А также некоторую информацию о самой переменной user:

>>> print(type(user))
<class 'myapp.models.User'>

>>> pp(user.__dict__)
{'_sa_instance_state': <sqlalchemy.orm.state.InstanceState object at 0x7f5a026a8438>,
 'userID': 1,
 'user_email': 'test@test.com',
 'user_first_name': 'SomeFirstName',
 'user_last_name': 'SomeLastName',
 'user_password': 'somepassword'}

В нашем проекте мы не должныиспользовать сгенерированные операторы SQL, такие как тот, который вызывается при вызове query.filter_by(username=form.username.data).first() в экземпляре класса User;мы должны сами писать сырой SQL, что обычно не имеет смысла, но в нашем случае это так.

Возможно ли это?

1 Ответ

0 голосов
/ 23 октября 2018

Прежде всего: Поговорите со своим профессором или TA .Вы сэкономите время, не делая предположений о чем-то столь важном.Если цель этого класса - подумать над дизайном схемы базы данных, тогда, вероятно, хорошо использовать ORM.Если вам нужно написать собственный SQL, то не используйте ORM для начала с .

Чтобы ответить на технический вопрос: да, вы можете использовать SQLAlchemy исключительно как пул соединений с базой данныхкак инструмент для создания допустимых операторов SQL из объектов Python, а также как полноценный ORM и каждая градация между ними.

Например, используя слой ORM, вы можете указать объекту Queryне генерировать SQL для вас, а вместо этого взять текст.Это описано в руководстве по SQLAlchemy ORM в разделе Использование текстового SQL section :

Литеральные строки можно гибко использовать с Query, указав их использование с помощьюконструкция text(), которая принимается большинством применимых методов

Для вашего примера входа в систему запрос только пароля может выглядеть следующим образом:

user = User.query.from_statement(
    db.text("SELECT * FROM User where user_email=:email LIMIT 1")
).params(email=form.username.data).first()

if user is None or user.check_password(form.password.data):
    # ...

Вы также можете прочитатьна API выражений SQL ( core API библиотеки SQLAlchemy) для построения запросов с использованием кода Python;связь между объектами Python и полученным запросом в значительной степени один на один;Обычно вы сначала создаете модель ваших таблиц, а затем создаете свой SQL-код или можете использовать литералы:

s = select([
    literal_column("User.password", String)
]).where(
    literal_column("User.user_email") == form.username.data
).select_from(table("User")).limit(1)

и выполнять такие объекты с помощью метода Session.execute()

results = db.session.execute(s)

Если вы действительно хотите выстрелить себе в ногу, вы также можете напрямую передать строки db.session.execute():

results = db.session.execute("""
    SELECT user_password FROM User where user_email=:email LIMIT 1
    """, {'email': form.username.data})

Просто знайте, что Session.execute() возвращает ResultProxy() экземпляр , а не экземпляры ORM.

Кроме того, знайте, что Flask-Login не требует использования ORM .Как говорится в проектной документации :

Однако, это не:

  • Не навязывает вам определенную базу данных или другой способ хранения. Вы полностью отвечаете за загрузку пользователя.

Так что вы можете просто создать подкласс UserMixin, который вы создадитекаждый раз, когда вы запрашиваете базу данных, вручную.

class User(flask_login.UserMixin):
    def __init__(self, id):    # add more attributes as needed
        self.id = id

@login_manager.user_loader
def load_user(user_id):
    # perhaps query the database to confirm the user id exists and
    # load more info, but all you basically need is:
    return User(user_id)

# on login, use

user = User(id_of_user_just_logged_in)
login_user(user)

Вот и все.Расширение хочет видеть случаи, когда реализует 4 основных метода , а класс UserMixin предоставляет все из них, и вам нужно только предоставить атрибут id.Как вы проверяете идентификаторы пользователей и обрабатываете вход в систему, зависит от вас.

...