SQLAlchemy के साथ SQL दृश्य को परिभाषित करने के लिए "पायथोनिक" तरीका है (मेरा मतलब है, कोई "शुद्ध SQL" क्वेरी)?
जवाबों:
अद्यतन: यहां SQLAlchemy उपयोग नुस्खा भी देखें
जहाँ तक मुझे पता है बॉक्स से बाहर (केवल पढ़ने के लिए गैर-भौतिकीकृत) दृश्य बनाना समर्थित नहीं है। लेकिन SQLAlchemy 0.7 में इस कार्यक्षमता जोड़ने सीधा है (उदाहरण के मैं दे दी है के लिए इसी तरह यहाँ )। आपको बस एक कंपाइलर एक्सटेंशन लिखना है CreateView
। इस एक्सटेंशन के साथ, फिर आप लिख सकते हैं (यह मानते हुए कि t
एक स्तंभ के साथ एक टेबल ऑब्जेक्ट है id
)
createview = CreateView('viewname', t.select().where(t.c.id>5))
engine.execute(createview)
v = Table('viewname', metadata, autoload=True)
for r in engine.execute(v.select()):
print r
यहाँ एक काम कर उदाहरण है:
from sqlalchemy import Table
from sqlalchemy.ext.compiler import compiles
from sqlalchemy.sql.expression import Executable, ClauseElement
class CreateView(Executable, ClauseElement):
def __init__(self, name, select):
self.name = name
self.select = select
@compiles(CreateView)
def visit_create_view(element, compiler, **kw):
return "CREATE VIEW %s AS %s" % (
element.name,
compiler.process(element.select, literal_binds=True)
)
# test data
from sqlalchemy import MetaData, Column, Integer
from sqlalchemy.engine import create_engine
engine = create_engine('sqlite://')
metadata = MetaData(engine)
t = Table('t',
metadata,
Column('id', Integer, primary_key=True),
Column('number', Integer))
t.create()
engine.execute(t.insert().values(id=1, number=3))
engine.execute(t.insert().values(id=9, number=-3))
# create view
createview = CreateView('viewname', t.select().where(t.c.id>5))
engine.execute(createview)
# reflect view and print result
v = Table('viewname', metadata, autoload=True)
for r in engine.execute(v.select()):
print r
यदि आप चाहें, तो आप एक बोली के लिए विशेषज्ञ भी कर सकते हैं, जैसे
@compiles(CreateView, 'sqlite')
def visit_create_view(element, compiler, **kw):
return "CREATE VIEW IF NOT EXISTS %s AS %s" % (
element.name,
compiler.process(element.select, literal_binds=True)
)
orm.mapper(ViewName, v, primary_key=pk, properties=prop)
जहां pk
और जहां prop
आपकी प्राथमिक कुंजी (या चाबियाँ) और गुण क्रमशः हैं। Docs.sqlalchemy.org/en/latest/orm/… देखें ।
v = Table('viewname', metadata, Column('my_id_column', Integer, primary_key=True), autoload=True)
स्टेफ़न का उत्तर एक अच्छा है और अधिकांश आधारों को शामिल करता है, लेकिन जो मुझे असंतुष्ट छोड़ गया था, वह SQLAlchemy (ORM, स्वत: छोड़ने आदि) के साथ एकीकरण की कमी थी। इंटरनेट के सभी कोनों से एक साथ प्रयोग करने और ज्ञान प्राप्त करने के घंटों के बाद मैं निम्नलिखित के साथ आया:
import sqlalchemy_views
from sqlalchemy import Table
from sqlalchemy.ext.compiler import compiles
from sqlalchemy.sql.ddl import DropTable
class View(Table):
is_view = True
class CreateView(sqlalchemy_views.CreateView):
def __init__(self, view):
super().__init__(view.__view__, view.__definition__)
@compiles(DropTable, "postgresql")
def _compile_drop_table(element, compiler, **kwargs):
if hasattr(element.element, 'is_view') and element.element.is_view:
return compiler.visit_drop_view(element)
# cascade seems necessary in case SQLA tries to drop
# the table a view depends on, before dropping the view
return compiler.visit_drop_table(element) + ' CASCADE'
ध्यान दें कि मैं sqlalchemy_views
पैकेज का उपयोग कर रहा हूं , बस चीजों को सरल बनाने के लिए।
एक दृश्य को परिभाषित करना (जैसे आपके टेबल मॉडल की तरह विश्व स्तर पर):
from sqlalchemy import MetaData, text, Text, Column
class SampleView:
__view__ = View(
'sample_view', MetaData(),
Column('bar', Text, primary_key=True),
)
__definition__ = text('''select 'foo' as bar''')
# keeping track of your defined views makes things easier
views = [SampleView]
विचारों को मैप करना (ORM कार्यक्षमता सक्षम करें):
अपने एप्लिकेशन को लोड करते समय, किसी भी प्रश्न से पहले और डीबी सेट करने के बाद करें।
for view in views:
if not hasattr(view, '_sa_class_manager'):
orm.mapper(view, view.__view__)
विचार बनाना:
डेटाबेस को इनिशियलाइज़ करते समय करें, जैसे create_all () कॉल के बाद।
from sqlalchemy import orm
for view in views:
db.engine.execute(CreateView(view))
किसी दृश्य को कैसे क्वेरी करें:
results = db.session.query(SomeModel, SampleView).join(
SampleView,
SomeModel.id == SampleView.some_model_id
).all()
यह वही होगा जो आप उम्मीद करते हैं (ऑब्जेक्ट्स की एक सूची जो प्रत्येक में एक SomeModel ऑब्जेक्ट और एक नमूना दृश्य वस्तु है)।
एक दृश्य छोड़ने:
SampleView.__view__.drop(db.engine)
यह भी एक drop_all () कॉल के दौरान स्वचालित रूप से हटा दिया जाएगा।
यह स्पष्ट रूप से एक बहुत ही आसान उपाय है, लेकिन मेरी नजर में यह सबसे अच्छा है और इस समय वहां से सबसे साफ है। मैंने पिछले कुछ दिनों में इसका परीक्षण किया है और कोई समस्या नहीं हुई है। मुझे यकीन नहीं है कि रिश्तों में कैसे जोड़ना है (वहाँ समस्याओं में भाग गया) लेकिन यह वास्तव में आवश्यक नहीं है, जैसा कि क्वेरी में ऊपर दिखाया गया है।
यदि किसी के पास कोई इनपुट है, तो कोई भी अप्रत्याशित समस्या पाता है, या चीजों को करने का एक बेहतर तरीका जानता है, कृपया एक टिप्पणी छोड़ दें या मुझे बताएं।
यह SQLAlchemy 1.2.6 और पायथन 3.6 पर परीक्षण किया गया था।
super(CreateView, self).__init__
और होनेclass SampleView(object)
Base = declarative_base(metadata=db.MetaData()) class ViewSample(Base): __tablename__ = 'view_sample'
मैंने अभी भी __definition__
संपत्ति को शामिल किया और मूल पोस्ट में सुझाए अनुसार इसे बनाने के लिए CreateView को बुलाया। अंत में, मुझे ड्रॉप सजाए गए तरीके को संशोधित करना पड़ा: if element.element.name.startswith('view_'): return compiler.visit_drop_view(element)
क्योंकि मुझे संपत्ति को एम्बेडेड तालिका में जोड़ने का कोई तरीका नहीं मिला।
इन दिनों उस के लिए एक PyPI पैकेज है: SQLAlchemy Views ।
यह PyPI पृष्ठ से है:
>>> from sqlalchemy import Table, MetaData
>>> from sqlalchemy.sql import text
>>> from sqlalchemy_views import CreateView, DropView
>>> view = Table('my_view', metadata)
>>> definition = text("SELECT * FROM my_table")
>>> create_view = CreateView(view, definition, or_replace=True)
>>> print(str(create_view.compile()).strip())
CREATE OR REPLACE VIEW my_view AS SELECT * FROM my_table
हालाँकि, आपने कोई "शुद्ध SQL" क्वेरी नहीं मांगी है , इसलिए आप संभवतः definition
SQLAlchemy क्वेरी ऑब्जेक्ट के साथ बनाया जाना चाहते हैं ।
सौभाग्य से, text()
ऊपर दिए गए उदाहरण में यह स्पष्ट है कि definition
पैरामीटर CreateView
एक ऐसी क्वेरी ऑब्जेक्ट है। तो कुछ इस तरह काम करना चाहिए:
>>> from sqlalchemy import Table, Column, Integer, String, MetaData, ForeignKey
>>> from sqlalchemy.sql import select
>>> from sqlalchemy_views import CreateView, DropView
>>> metadata = MetaData()
>>> users = Table('users', metadata,
... Column('id', Integer, primary_key=True),
... Column('name', String),
... Column('fullname', String),
... )
>>> addresses = Table('addresses', metadata,
... Column('id', Integer, primary_key=True),
... Column('user_id', None, ForeignKey('users.id')),
... Column('email_address', String, nullable=False)
... )
यहाँ दिलचस्प सा है:
>>> view = Table('my_view', metadata)
>>> definition = select([users, addresses]).where(
... users.c.id == addresses.c.user_id
... )
>>> create_view = CreateView(view, definition, or_replace=True)
>>> print(str(create_view.compile()).strip())
CREATE OR REPLACE VIEW my_view AS SELECT users.id, users.name,
users.fullname, addresses.id, addresses.user_id, addresses.email_address
FROM users, addresses
WHERE users.id = addresses.user_id
SQLAlchemy-utils ने केवल 0.33.6 में यह कार्यक्षमता जोड़ी (pypi में उपलब्ध)। इसमें दृश्य, भौतिक विचार हैं, और यह ORM के साथ एकीकृत है। यह अभी तक प्रलेखित नहीं है, लेकिन मैं विचारों + ओआरएम का सफलतापूर्वक उपयोग कर रहा हूं।
आप ओआरएम का उपयोग करके दोनों नियमित और भौतिक विचारों के लिए एक उदाहरण के रूप में उनके परीक्षण का उपयोग कर सकते हैं ।
एक दृश्य बनाने के लिए, एक बार पैकेज स्थापित करने के बाद, ऊपर दिए गए कोड को अपने दृश्य के आधार के रूप में परीक्षण से उपयोग करें:
class ArticleView(Base):
__table__ = create_view(
name='article_view',
selectable=sa.select(
[
Article.id,
Article.name,
User.id.label('author_id'),
User.name.label('author_name')
],
from_obj=(
Article.__table__
.join(User, Article.author_id == User.id)
)
),
metadata=Base.metadata
)
कहाँ Base
है declarative_base
, sa
है SQLAlchemy
पैकेज है, और create_view
से एक समारोह है sqlalchemy_utils.view
।
मुझे एक छोटा और आसान जवाब नहीं मिला।
मुझे दृश्य की अतिरिक्त कार्यक्षमता की आवश्यकता नहीं है (यदि कोई है), तो मैं बस एक दृश्य को अन्य तालिका परिभाषाओं के रूप में एक साधारण तालिका के रूप में मानता हूं।
इसलिए मूल रूप से मेरे पास a.py
जहां सभी तालिकाओं और विचारों को परिभाषित करता है, एसक्यूएल से संबंधित सामान, और main.py
जहां मैं उन कक्षाओं को आयात करता हूं a.py
और उनका उपयोग करता हूं।
यहाँ मैं क्या जोड़ रहा हूँ a.py
और काम करता है:
class A_View_From_Your_DataBase(Base):
__tablename__ = 'View_Name'
keyword = Column(String(100), nullable=False, primary_key=True)
विशेष रूप से, आपको primary_key
संपत्ति जोड़ने की आवश्यकता है, भले ही दृश्य में कोई प्राथमिक कुंजी न हो।
शुद्ध SQL के बिना SQL देखें? आप एक परिभाषित दृश्य को लागू करने के लिए एक वर्ग या फ़ंक्शन बना सकते हैं।
function get_view(con):
return Table.query.filter(Table.name==con.name).first()
v = Table('viewname', metadata, autoload=True) class ViewName(object): def __init__(self, name): self.name = name mapper(ViewName, v)
ऊपर की तरह संभव है? क्योंकि मैं सत्र के साथ View का उपयोग करूंगा।