Programing

Flask에서 데이터베이스에 연결하면 어떤 접근 방식이 더 낫습니까?

crosscheck 2020. 12. 31. 22:51
반응형

Flask에서 데이터베이스에 연결하면 어떤 접근 방식이 더 낫습니까?


방법 1 : http://flask.pocoo.org/docs/tutorial/dbcon/http://flask.pocoo.org/docs/patterns/sqlite3/의 특수 g 개체 사용

import sqlite3
from flask import g

DATABASE = '/path/to/database.db'

def connect_db():
    return sqlite3.connect(DATABASE)

@app.before_request
def before_request():
    g.db = connect_db()

@app.teardown_request
def teardown_request(exception):
    if hasattr(g, 'db'):
        g.db.close()

방법 2 : https://github.com/mitsuhiko/flask/blob/master/examples/flaskr/flaskr.py 에서 Mysterious _app_ctx_stack 사용

from sqlite3 import dbapi2 as sqlite3
from flask import Flask, request, session, g, redirect, url_for, abort, \
     render_template, flash, _app_ctx_stack
def get_db():
    """Opens a new database connection if there is none yet for the
    current application context.
    """
    top = _app_ctx_stack.top
    if not hasattr(top, 'sqlite_db'):
        top.sqlite_db = sqlite3.connect(app.config['DATABASE'])
    return top.sqlite_db


@app.teardown_appcontext
def close_db_connection(exception):
    """Closes the database again at the end of the request."""
    top = _app_ctx_stack.top
    if hasattr(top, 'sqlite_db'):
        top.sqlite_db.close()

어떤 방법이 더 낫습니까? 차이점은 무엇입니까?


둘 사이의 차이점은 방법 1은 g.db필요 여부에 대한 연결을 생성하는 반면 방법 2 get_db는 해당 애플리케이션 컨텍스트에서 처음 호출 할 때만 연결을 생성 한다는 것입니다.

이 설정을 사용하여 둘을 비교하는 경우 :

yourapp = Flask(__name__)

# setup g.db or app_context here
# Add a logging statement (print will do)
# to the get_db or before_request functions
# that simply says "Getting the db connection ..."
# Then access / and /1

@yourapp.route("/")
def index():
    return "No database calls here!"

@yourapp.route("/<int:post_id>")
def show_post(post_id):
    # get a post using g.db or get_db
    return "Went to the DB and got {!r}".format(post)

setup ( )을 /사용하여 눌렀을 때 사용 여부 에 관계 없이 연결 되는 것을 볼 수 있으며 , 경로를 사용 하면 전화를 걸 때만 연결 됩니다 .@app.before_requestg.db_app_contextget_db

공정 g하게 말하면 동일한 지연 연결 (또는 실제 연결 풀에서 연결 획득)을 수행 할 설명자를 추가 할 수도 있습니다 . 그리고에 경우 당신은 (좀 더 마법을 사용할 수 werkzeug.local.LocalProxy정확합니다) 사용자 정의 만들려면 현지 스레드를 같은 역할을하는 g, current_app그리고 request( 다른 사람의 사이에서 ).


첫 번째는 필요하지 않은 경우에도 연결을 확보하는 문제입니다. 두 번째는 써드 파티 프레임 워크의 내부를 가지고 노는 단점이 있으며 읽기도 꽤 어렵습니다.

둘 중 두 번째가 더 나은 선택 일 것입니다. 필요하지 않은 경로에 대한 연결을 획득하지 않을뿐만 아니라 경로의 다른 코드 경로에 연결이 필요하더라도 연결이 필요하지 않은 코드 경로로 이동하면 연결을 획득하지 않습니다. (예를 들어, 일부 양식 유효성 검사가있는 경우 유효성 검사에 통과 한 경우에만 연결이 필요합니다. 유효성 검사가 실패하면 연결이 열리지 않습니다.)이 설정에서 연결을 사용하기 직전에 연결 만 획득합니다.

그러나 내부 문제를 피하고 이러한 모든 이점을 얻을 수 있습니다. 개인적으로 저는 저만의 작은 전역 메서드를 만들었습니다.

import flask
import sqlite3

def request_has_connection():
    return hasattr(flask.g, 'dbconn')

def get_request_connection():
    if not request_has_connection():
        flask.g.dbconn = sqlite3.connect(DATABASE)
        # Do something to make this connection transactional.
        # I'm not familiar enough with SQLite to know what that is.
    return flask.g.dbconn

@app.teardown_request
def close_db_connection(ex):
    if request_has_connection():
        conn = get_request_connection()
        # Rollback
        # Alternatively, you could automatically commit if ex is None
        # and rollback otherwise, but I question the wisdom 
        # of automatically committing.
        conn.close()

Then, throughout the app, always get your connection via get_request_connection, just as you would your get_db function. Straightforward and high efficiency. Basically, the best of both worlds.

Edit:

In retrospect, I really dislike the fact these are global methods, but I think the reason for it is because that's how Flask works: it gives you "globals" that actually point to thread-locals.


I recommend Flask-SQLAlchemy, which extends SQLAlchemy for use in Flask, so it supports many different databases. (Example from Flask-SQLAlchemy documentation)

Setup:

from flask import Flask
from flask.ext.sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db'
db = SQLAlchemy(app)


class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True)
    email = db.Column(db.String(120), unique=True)

    def __init__(self, username, email):
        self.username = username
        self.email = email

    def __repr__(self):
        return '<User %r>' % self.username

Now, you can just import/use the User class to access the User table in your database.

Create new users:

>>> from yourapplication import User
>>> admin = User('admin', 'admin@example.com')
>>> guest = User('guest', 'guest@example.com')

Add the users to the database:

>>> db.session.add(admin)
>>> db.session.add(guest)
>>> db.session.commit()

Query for users already in database:

>>> users = User.query.all()
[<User u'admin'>, <User u'guest'>]
>>> admin = User.query.filter_by(username='admin').first()
<User u'admin'>

I'd go with method one - more readable and less "hackish".

The method 2 is probably designed for flask extensions integration (example and explanation of app-ctx-stack). Although they probably have very similar effect, method one should be used for normal cases.

ReferenceURL : https://stackoverflow.com/questions/16311974/connect-to-a-database-in-flask-which-approach-is-better

반응형