sqlite를 사용하여 PyQt5 및 Sql 클래스를 시작하고 있습니다. sqlite에 확장을로드하고 싶습니다. 이를 위해서는 sqlite에 대해 런타임에 확장 로딩을 활성화해야합니다. 파이썬 모듈 sqlite3 에서는 enable_load_extension을 통해 활성화됩니다 .
C ++에서 sqlite
핸들은 다음과 같이 얻을 수 있습니다 ( https://doc.qt.io/qt-5/qsqldriver.html#handle 에서 가져옴 ) :
QSqlDatabase db = QSqlDatabase::database();
QVariant v = db.driver()->handle();
if (v.isValid() && (qstrcmp(v.typeName(), "sqlite3*") == 0)) {
// v.data() returns a pointer to the handle
sqlite3 *handle = *static_cast<sqlite3 **>(v.data());
if (handle) {
// ...
}
}
파이썬에 상응하는 것은
from PyQt5.QtSql import QSqlDatabase
db = QSqlDatabase.addDatabase('QSQLITE')
db.driver().handle()
-> TypeError: unable to convert a C++ 'sqlite3*' instance to a Python object
참고로 Pyside2에서는 핸들 메서드가 노출되지 않습니다.
이것이 잘못된 방법 인 것 같습니다. PyQt5를 통해 sqlite 확장을로드 할 수있는 방법이 있습니까?
한 가지 가능한 해결책은 ctypes를 사용하여로드되는 라이브러리를 만드는 것입니다.
이 경우 우분투 리눅스에 대한 솔루션을 보여 주지만 비슷한 단계를 다른 OS에도 적용 할 수 있다고 생각합니다.
qsqlite.pro
QT -= gui
QT += sql
TEMPLATE = lib
DEFINES += QSQLITE_LIBRARY
CONFIG += unversioned_libname unversioned_soname
CONFIG += c++11
SOURCES += \
qsqlite.cpp
HEADERS += \
qsqlite_global.h \
qsqlite.h
LIBS += -lsqlite3
qsqlite_global.h
#ifndef QSQLITE_GLOBAL_H
#define QSQLITE_GLOBAL_H
#if defined(_MSC_VER) || defined(WIN64) || defined(_WIN64) || defined(__WIN64__) || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
# define Q_DECL_EXPORT __declspec(dllexport)
# define Q_DECL_IMPORT __declspec(dllimport)
#else
# define Q_DECL_EXPORT __attribute__((visibility("default")))
# define Q_DECL_IMPORT __attribute__((visibility("default")))
#endif
#if defined(QSQLITE_LIBRARY)
# define QSQLITE_EXPORT Q_DECL_EXPORT
#else
# define QSQLITE_EXPORT Q_DECL_IMPORT
#endif
#endif // QSQLITE_GLOBAL_H
qsqlite.h
#ifndef QSQLITE_H
#define QSQLITE_H
#include "qsqlite_global.h"
class QSqlDriver;
extern "C" {
bool QSQLITE_EXPORT enable_extension(QSqlDriver *ptr, bool enabled);
}
#endif // QSQLITE_H
qsqlite.cpp
#include "qsqlite.h"
#include <sqlite3.h>
#include <QSqlDriver>
#include <QVariant>
bool enable_extension(QSqlDriver *driver, bool enabled)
{
if(!driver)
return false;
QVariant v = driver->handle();
if (!v.isValid() || !(qstrcmp(v.typeName(), "sqlite3*")==0))
return false;
if(sqlite3 *db_handle = *static_cast<sqlite3 **>(v.data())){
sqlite3_initialize();
sqlite3_enable_load_extension(db_handle, enabled);
return true;
}
return false;
}
qsqlite/
├── qsqlite.cpp
├── qsqlite_global.h
├── qsqlite.h
└── qsqlite.pro
컴파일하려면 Qt를 사용해야하므로이 경우 python -m pip install aqtinstall
다음 명령을 실행하여 aqtinstall ( )을 사용합니다 .
python -m aqt install 5.15.0 linux desktop --outputdir qt
qt/5.15.0/gcc_64/bin/qmake qsqlite
make
참고 : 라이브러리를 컴파일하려면이를 위해 sqlite3 헤더가 있어야합니다 . libsqlite3-dev
우분투에 설치해야합니다 : sudo apt install -y --no-install-recommends libsqlite3-dev
.
이렇게하면 스크립트 옆에 복사해야하는 libqsqlite.so 라이브러리가 생성됩니다. 예를 들어 다음 코드는 spatialite 모듈 ( sudo apt install -y --no-install-recommends libsqlite3-mod-spatialite
)을 로드합니다 .
main.py
from ctypes import CDLL, c_void_p
import os
from PyQt5.QtSql import QSqlDatabase, QSqlQuery
import sip
CURRENT_DIR = os.path.dirname(os.path.realpath(__file__))
def load_spatialite():
queries = (
"SELECT load_extension('mod_spatialite')",
"SELECT InitSpatialMetadata(1)",
)
q = QSqlQuery()
for query in queries:
if not q.exec_(query):
print(
f"Error: cannot load the Spatialite extension ({q.lastError().text()})"
)
return False
return True
def main():
db = QSqlDatabase.addDatabase("QSQLITE")
db.setDatabaseName("foo.sqlite")
if not db.open():
sys.exit(-1)
lib = CDLL(os.path.join(CURRENT_DIR, "libqsqlite.so"))
lib.enable_extension(c_void_p(sip.unwrapinstance(db.driver()).__int__()), True)
load_spatialite()
query = QSqlQuery()
query.exec_("CREATE TABLE my_line(id INTEGER PRIMARY KEY)")
query.exec_(
"""SELECT AddGeometryColumn("my_line","geom" , 4326, "LINESTRING", 2)"""
)
polygon_wkt = "POLYGON ((11 50,11 51,12 51,12 50,11 50))"
XA = 11
YA = 52
XB = 12
YB = 49
line_wkt = "LINESTRING({0} {1}, {2} {3})".format(XA, YA, XB, YB)
query.prepare("""INSERT INTO my_line VALUES (?,GeomFromText(?, 4326))""")
query.addBindValue(1)
query.addBindValue(line_wkt)
query.exec_()
query.prepare(
"""SELECT astext(st_intersection(geom, GeomFromText(?, 4326))) from my_line WHERE st_intersects(geom, GeomFromText(?, 4326))"""
)
query.addBindValue(polygon_wkt)
query.addBindValue(polygon_wkt)
query.exec_()
while query.next():
for i in range(query.record().count()):
print(query.value(i))
if __name__ == "__main__":
main()
├── main.py
└── libqsqlite.so
산출:
LINESTRING(11.333333 51, 11.666667 50)
동일한 라이브러리를 PySide2에 사용할 수 있습니다.
from ctypes import CDLL, c_void_p
import os
from PySide2.QtSql import QSqlDatabase, QSqlQuery
import shiboken2
CURRENT_DIR = os.path.dirname(os.path.realpath(__file__))
def load_spatialite():
queries = (
"SELECT load_extension('mod_spatialite')",
"SELECT InitSpatialMetadata(1)",
)
q = QSqlQuery()
for query in queries:
if not q.exec_(query):
print(
f"Error: cannot load the Spatialite extension ({q.lastError().text()})"
)
return False
return True
def main():
db = QSqlDatabase.addDatabase("QSQLITE")
db.setDatabaseName("foo.sqlite")
if not db.open():
sys.exit(-1)
lib = CDLL(os.path.join(CURRENT_DIR, "libqsqlite.so"))
lib.enable_extension(c_void_p(shiboken2.getCppPointer(db.driver())[0]))
load_spatialite()
query = QSqlQuery()
query.exec_("CREATE TABLE my_line(id INTEGER PRIMARY KEY)")
query.exec_(
"""SELECT AddGeometryColumn("my_line","geom" , 4326, "LINESTRING", 2)"""
)
polygon_wkt = "POLYGON ((11 50,11 51,12 51,12 50,11 50))"
XA = 11
YA = 52
XB = 12
YB = 49
line_wkt = "LINESTRING({0} {1}, {2} {3})".format(XA, YA, XB, YB)
query.prepare("""INSERT INTO my_line VALUES (?,GeomFromText(?, 4326))""")
query.addBindValue(1)
query.addBindValue(line_wkt)
query.exec_()
query.prepare(
"""SELECT astext(st_intersection(geom, GeomFromText(?, 4326))) from my_line WHERE st_intersects(geom, GeomFromText(?, 4326))"""
)
query.addBindValue(polygon_wkt)
query.addBindValue(polygon_wkt)
query.exec_()
while query.next():
for i in range(query.record().count()):
print(query.value(i))
if __name__ == "__main__":
main()
이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.
침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제
몇 마디 만하겠습니다