2013-04-24 4 views
1

App Engine에서 SQLAlchemy를 사용하여 Google Cloud SQL에 연결하는 방법에 대해서는 somequestions을 보았습니다. 그러나 로컬 MySQL 데이터베이스와 기존 SQLAlchemy 방언을 사용하여 개발할 수 있는지 확실하지 않습니다. 내 첫 번째 시도에, 나는 응용 프로그램에 0.8.0 SQLAlchemy의 을 추가하고 스키마 정의 :App Engine 개발 서버에서 SQLAlchemy 사용

from sqlalchemy import create_engine, Column, Integer, Table 
from sqlalchemy.ext.declarative import declarative_base 

Base = declarative_base()  

foo_table = Table('foo', Base.metadata, 
    Column('id', Integer, primary_key=True, autoincrement=True), 
) 

을 내가 사용하는 개발 서버에 테이블을 만들려고 할 때 :

url = 'mysql+gaerdbms:///%s?instance=%s' % ('database_name', 'instance_name') 
engine = create_engine(url) 
Base.metadata.create_all(engine) 

. .. 오류가 발생했습니다. DBAPIError: (ImportError) No module named pwd None None은 SQLAlchemy가 개발 서버에 의해 블랙리스트에 올라있는 모듈을 가져 오는 것을 의미합니다.

내가 잘못 했나요? 그렇지 않은 경우 SQLAlchemy를 개발 서버에서 사용하려면 어떻게해야합니까? 또는 첫 번째 질문은 : SQLAlchemy의 gaerdbms dialect를 사용하여 dev 서버를 사용하여 로컬 MySql 데이터베이스에서 개발할 수 있습니까?

편집 :이 오류는 표를 만들 때만 발생합니다. 나는 테이블을 수동으로 생성하고 쿼리를 시도했는데 같은 오류가 발생합니다.

전체 역 추적은 다음과 같습니다

Traceback (most recent call last): 
    File "[...]/google_appengine/lib/webapp2-2.5.2/webapp2.py", line 1535, in __call__ 
    rv = self.handle_exception(request, response, e) 
    File "[...]/google_appengine/lib/webapp2-2.5.2/webapp2.py", line 1529, in __call__ 
    rv = self.router.dispatch(request, response) 
    File "[...]/google_appengine/lib/webapp2-2.5.2/webapp2.py", line 1278, in default_dispatcher 
    return route.handler_adapter(request, response) 
    File "[...]/google_appengine/lib/webapp2-2.5.2/webapp2.py", line 1102, in __call__ 
    return handler.dispatch() 
    File "[...]/google_appengine/lib/webapp2-2.5.2/webapp2.py", line 572, in dispatch 
    return self.handle_exception(e, self.app.debug) 
    File "[...]/google_appengine/lib/webapp2-2.5.2/webapp2.py", line 570, in dispatch 
    return method(*args, **kwargs) 
    File "[...]/webapp/admin.py", line 12, in get 
    db.Base.metadata.create_all(engine) 
    File "[...]/webapp/sqlalchemy/schema.py", line 2784, in create_all 
    tables=tables) 
    File "[...]/webapp/sqlalchemy/engine/base.py", line 1486, in _run_visitor 
    with self._optional_conn_ctx_manager(connection) as conn: 
    File "/usr/lib/python2.7/contextlib.py", line 17, in __enter__ 
    return self.gen.next() 
    File "[...]/webapp/sqlalchemy/engine/base.py", line 1479, in _optional_conn_ctx_manager 
    with self.contextual_connect() as conn: 
    File "[...]/webapp/sqlalchemy/engine/base.py", line 1669, in contextual_connect 
    self.pool.connect(), 
    File "[...]/webapp/sqlalchemy/pool.py", line 272, in connect 
    return _ConnectionFairy(self).checkout() 
    File "[...]/webapp/sqlalchemy/pool.py", line 425, in __init__ 
    rec = self._connection_record = pool._do_get() 
    File "[...]/webapp/sqlalchemy/pool.py", line 855, in _do_get 
    return self._create_connection() 
    File "[...]/webapp/sqlalchemy/pool.py", line 225, in _create_connection 
    return _ConnectionRecord(self) 
    File "[...]/webapp/sqlalchemy/pool.py", line 318, in __init__ 
    self.connection = self.__connect() 
    File "[...]/webapp/sqlalchemy/pool.py", line 368, in __connect 
    connection = self.__pool._creator() 
    File "[...]/webapp/sqlalchemy/engine/strategies.py", line 80, in connect 
    return dialect.connect(*cargs, **cparams) 
    File "[...]/webapp/sqlalchemy/engine/default.py", line 279, in connect 
    return self.dbapi.connect(*cargs, **cparams) 
    File "[...]/google_appengine/google/storage/speckle/python/api/rdbms_googleapi.py", line 183, in __init__ 
    super(GoogleApiConnection, self).__init__(*args, **kwargs) 
    File "[...]/google_appengine/google/storage/speckle/python/api/rdbms.py", line 810, in __init__ 
    self.OpenConnection() 
    File "[...]/google_appengine/google/storage/speckle/python/api/rdbms.py", line 832, in OpenConnection 
    self.SetupClient() 
    File "[...]/google_appengine/google/storage/speckle/python/api/rdbms_googleapi.py", line 193, in SetupClient 
    self._client = RdbmsGoogleApiClient(**kwargs) 
    File "[...]/google_appengine/google/storage/speckle/python/api/rdbms_googleapi.py", line 106, in __init__ 
    rdbms.OAUTH_CREDENTIALS_PATH) 
    File "/usr/lib/python2.7/posixpath.py", line 259, in expanduser 
    import pwd 
    File "[...]/google_appengine/google/appengine/tools/devappserver2/python/sandbox.py", line 822, in load_module 
    raise ImportError('No module named %s' % fullname) 
DBAPIError: (ImportError) No module named pwd None None 

답변

1

내가 해결 방법을 발견했다. 그대로, SQLAlchemy의 gaerdbms dialect는 로컬 데이터베이스에 연결할 수 없습니다. 그러나 아래의 방언으로 할 수 있습니다. this answer에서 지침을 Folow 대신이 방언을 사용 : 개발 서버에서 실행되는 경우

# mysql/gaerdbms.py 
# Copyright (C) 2005-2013 the SQLAlchemy authors and contributors <see AUTHORS file> 
# 
# This module is part of SQLAlchemy and is released under 
# the MIT License: http://www.opensource.org/licenses/mit-license.php 
""" 
.. dialect:: mysql+gaerdbms 
    :name: Google Cloud SQL 
    :dbapi: rdbms 
    :connectstring: mysql+gaerdbms:///<dbname>?instance=<instancename> 
    :url: https://developers.google.com/appengine/docs/python/cloud-sql/developers-guide 

    This dialect is based primarily on the :mod:`.mysql.mysqldb` dialect with minimal 
    changes. 

    .. versionadded:: 0.7.8 


Pooling 
------- 

Google App Engine connections appear to be randomly recycled, 
so the dialect does not pool connections. The :class:`.NullPool` 
implementation is installed within the :class:`.Engine` by 
default. 

""" 

import os 
import re 

from sqlalchemy.dialects.mysql.mysqldb import MySQLDialect_mysqldb 
from sqlalchemy.pool import NullPool 


class MySQLDialect_gaerdbms(MySQLDialect_mysqldb): 

    @classmethod 
    def dbapi(cls): 
     # from django: 
     # http://code.google.com/p/googleappengine/source/ 
     #  browse/trunk/python/google/storage/speckle/ 
     #  python/django/backend/base.py#118 
     # see also [ticket:2649] 
     # see also https://stackoverflow.com/q/14224679/34549 
     if is_production(): 
      # Production mode. 
      from google.storage.speckle.python.api import rdbms_apiproxy 
      return rdbms_apiproxy 
     elif is_remote_mode(): 
      # Development mode with remote database. 
      from google.storage.speckle.python.api import rdbms_googleapi 
      return rdbms_googleapi 
     else: 
      # Development mode with local database. 
      from google.appengine.api import rdbms_mysqldb 
      return rdbms_mysqldb 

    @classmethod 
    def get_pool_class(cls, url): 
     # Cloud SQL connections die at any moment 
     return NullPool 

    def create_connect_args(self, url): 
     opts = url.translate_connect_args() 
     if is_production() or is_remote_mode(): 
      # 'dsn' and 'instance' are because we are skipping 
      # the traditional google.api.rdbms wrapper. 
      # they are not needed in local mode; 'dns' even causes an error. 
      opts['dsn'] = '' 
      opts['instance'] = url.query['instance'] 
     return [], opts 

    def _extract_error_code(self, exception): 
     match = re.compile(r"^(\d+):|^\((\d+),").match(str(exception)) 
     # The rdbms api will wrap then re-raise some types of errors 
     # making this regex return no matches. 
     code = match.group(1) or match.group(2) if match else None 
     if code: 
      return int(code) 

dialect = MySQLDialect_gaerdbms 

def is_production(): 
    return os.getenv('SERVER_SOFTWARE', '').startswith('Google App Engine') 

def is_remote_mode(): 
    return os.getenv('SETTINGS_MODE') == 'prod' 

이 방언은 기본적으로 로컬 데이터베이스를 사용합니다. 개발 중에 Google Cloud SQL에 원격 액세스를 사용하려면 the pattern used by Django 다음의 변수가 환경에 설정되어야합니다.

os.environ['SETTINGS_MODE'] = 'prod'