Sqlalchemy ORM을위한 프레임 워크 공유, 통합하기 쉬운 팩.
Django Orm과 Eloquent Orm에서 크게 영감을 받았습니다
Fastapi와 같은 기존 프로젝트에 쉽게 통합 :
from sqlalchemy_mixins import BaseMixin
class User ( Base , BaseMixin ):
pass PIP를 사용하십시오
pip install SqlalchemyMixin
다음은 믹스 인이 할 수있는 일에 대한 빠른 데모입니다.
bob = User . create ( name = 'Bob' )
post1 = Post . create ( body = 'Post 1' , user = bob , rating = 3 )
post2 = Post . create ( body = 'long-long-long-long-long body' , rating = 2 ,
user = User . create ( name = 'Bill' ),
comments = [ Comment . create ( body = 'cool!' , user = bob )])
# filter using operators like 'in' and 'contains' and relations like 'user'
# will output this beauty: <Post #1 body:'Post1' user:'Bill'>
print ( Post . where ( rating__in = [ 2 , 3 , 4 ], user___name__like = '%Bi%' ). all ())
# joinedload post and user
print ( Comment . with_joined ( 'user' , 'post' , 'post.comments' ). first ())
# subqueryload posts and their comments
print ( User . with_subquery ( 'posts' , 'posts.comments' ). first ())
# sort by rating DESC, user name ASC
print ( Post . sort ( '-rating' , 'user___name' ). all ())
# created_at, updated_at timestamps added automatically
print ( "Created Bob at " , bob . created_at )
# serialize to dict, with relationships import sqlalchemy as sa
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy_mixins import BaseMixin
app = Flask ( __name__ )
app . config [ 'SQLALCHEMY_DATABASE_URI' ] = 'sqlite://'
db = SQLAlchemy ( app )
######### Models #########
class BaseModel ( db . Model , BaseMixin ):
__abstract__ = True
pass
class User ( BaseModel ):
name = sa . Column ( sa . String )
######## Initialize ########
BaseModel . set_session ( db . session )
######## Create test entity ########
db . create_all ()
user = User . create ( name = 'bob' )
print ( user ) 이 라이브러리는 SQLALCHEMY의 autocommit 플래그에 의존합니다. 세션을 초기화 할 때는 true로 설정해야합니다.
session = scoped_session ( sessionmaker ( bind = engine , autocommit = True ))
BaseModel . set_session ( session ) 또는 Flask-SQLAlchemy 와 함께
db = SQLAlchemy ( app , session_options = { 'autocommit' : True })주요 기능입니다
ActiveRecordMixin 이 제공합니다
SQLALCHEMY의 데이터 맵퍼 패턴은 시원하지만 활성 레코드 패턴은 가장 쉽고 건조합니다.
글쎄, 우리는 데이터 맵퍼 위에 그것을 구현했습니다! 우리가 필요한 것은 앱을 부트 스트랩하는 동안 ORM 클래스에 세션을 주입하는 것입니다.
BaseModel . set_session ( session )
# now we have access to BaseOrmModel.session property우리 모두는 sqlalchemy를 좋아하지만 Crud를하는 것은 약간 까다 롭습니다.
예를 들어, 객체를 만드는 3 줄의 코드가 필요합니다.
bob = User ( name = 'Bobby' , age = 1 )
session . add ( bob )
session . flush ()글쎄, 모델에서 세션에 액세스 할 때 우리는 그냥 쓸 수 있습니다.
bob = User . create ( name = 'Bobby' , age = 1 )그것이 Django Orm과 Peewee에서 수행 한 방법입니다
업데이트 및 삭제 방법도 제공됩니다
bob . update ( name = 'Bob' , age = 21 )
bob . delete ()그리고 Django와 Eloquent에서와 마찬가지로 ID로 물체를 신속하게 검색 할 수 있습니다.
User . get ( 1 ) # instead of session.query(User).get(1)그러한 ID가 존재하지 않으면 실패합니다
User . get_or_abort ( 123987 ) # will raise sqlalchemy_mixins.ModelNotFoundErrorFlask-Sqlalchemy, Peewee 및 Django Orm에서와 같이 일부 클래스를 신속하게 쿼리 할 수 있습니다.
User . query # instead of session.query(User)또한 첫 번째 또는 모든 개체를 신속하게 검색 할 수 있습니다.
User . first () # instead of session.query(User).first()
User . all () # instead of session.query(User).all() EagerLoadMixin 에서 제공합니다
SQLALCHEMY의 열렬한 로딩을 사용하는 경우, 특히 우리가 동일한 쿼리의 모든 게시물에 대한 모든 게시물 및 댓글을로드 할 때 특히 편리하지 않을 수 있습니다.
글쎄, 이제 열망하고 싶은 ORM 관계를 쉽게 설정할 수 있습니다.
User . with_ ({
'posts' : {
'comments' : {
'user' : JOINED
}
}
}). all ()또는 문자열 대신 클래스 속성을 쓸 수 있습니다.
User . with_ ({
User . posts : {
Post . comments : {
Comment . user : JOINED
}
}
}). all ()때때로 우리는 별도의 쿼리로 관계를로드하고 싶습니다. 예를 들어, 우리는 이와 같은 페이지의 게시물을로드하고 각 게시물에 대해 사용자와 모든 주석 (및 댓글 저자)을 갖기를 원합니다.
쿼리 속도를 높이려면 별도의 쿼리로 주석을로드하지만이 별도의 쿼리에서는 사용자 가입합니다.
from sqlalchemy_mixins import JOINED , SUBQUERY
Post . with_ ({
'user' : JOINED , # joinedload user
'comments' : ( SUBQUERY , { # load comments in separate query
'user' : JOINED # but, in this separate query, join user
})
}). all ()여기에서는 게시물이 첫 번째 쿼리에로드되고 사용자와의 주석은 두 번째 쿼리입니다. 관계 로딩 기술을 설명하려면 sqlalchemy 문서를 참조하십시오.
간단한 경우에, 몇 가지 관계를 바탕으로 합류하거나 하위 쿼리를 원할 때, 우리는 당신에게 더 쉬운 구문을 가지고 있습니다.
Comment . with_joined ( 'user' , 'post' , 'post.comments' ). first ()
User . with_subquery ( 'posts' , 'posts.comments' ). all ()이 sqlalchemy 기능으로 인해
post.comments와 같은 DOT와의 관계를 분할 할 수 있습니다.
SmartQueryMixin 에서 제공합니다
우리는 Django와 같은 필드 조회 및 자동 관계 조인을 구현합니다.
그것은 문자열에 정의 된 속성으로 동적으로 필터링하고 정렬 할 수 있음을 의미합니다!
따라서 Post.user 관계가있는 Post 모델을 User 모델과 정의하면 쓸 수 있습니다.
Post . where ( rating__gt = 2 , user___name__like = '%Bi%' ). all () # post rating > 2 and post user name like ...
Post . sort ( '-rating' , 'user___name' ). all () # sort by rating DESC, user name ASC ( ___ 관계 및 속성 분할, __ 속성 및 연산자 분할)
더 많은 유연성이 필요한 경우 저수준
filter_exprMethodsession.query(Post).filter(*Post.filter_expr(rating__gt=2, body='text'))사용할 수 있습니다. 예제를 참조하십시오.그것은 sqlalchemy의
filter_by와 같지만rating__gt와 같은 마법의 연산자도 허용합니다.참고 :
filter_expr메소드는 매우 낮은 수준이며 마법의 장고 같은 결합을 수행하지 않습니다.smart_query사용하십시오.
필터링/정렬에 사용되는 모든 관계는 백 리프뿐만 아니라 명시 적으로 설정 해야합니다.
이 예에서는
Post.user관계가User.posts정의 된 경우에도Post클래스에서 정의되어야합니다.따라서 입력 할 수 없습니다
class User ( BaseModel ): # ... user = sa . orm . relationship ( 'User' , backref = 'posts' )
Post.user관계 정의를 건너 뜁니다. 어쨌든 정의해야합니다.class Post ( BaseModel ): # ... user = sa . orm . relationship ( 'User' ) # define it anyway
코드를 건조화하고 비즈니스 로직을 배출하기 위해 SQLALCHEMY의 하이브리드 속성 및 Hybrid_Methods를 사용할 수 있습니다. 필터링/정렬에 사용하는 것은 간단합니다 (예제 및 테스트 참조).
글쎄, SmartQueryMixin 필터링/정렬을 위해 자동 조인을 수행함에 따라 SQLALCHEMY에게 이미 그 관계에 합류했다고 말하는 의미가 있습니다.
따라서 관계는 필터링/정렬에 사용 된 경우 자동으로 결합되도록 설정됩니다.
우리가 글을 쓰면
comments = Comment . where ( post___public = True , post___user___name__like = 'Bi%' ). all ()그러면 중고 관계에 액세스하면 추가 쿼리가 실행되지 않습니다.
comments [ 0 ]. post
comments [ 0 ]. post . user SmartQueryMixin 에서 제공합니다
실제 세계에서는 한 번에 일부 관계를 필터링하고 정렬하며 열망하는 것을 원합니다. 필터링 및 정렬에서 User.posts 하게 사용하는 경우 동일하게 사용하면 두 번 결합해서는 안됩니다 .
그렇기 때문에 필터, 정렬 및 열망하는 하중을 하나의 현명한 방법으로 결합한 이유입니다.
Comment . smart_query (
filters = {
'post___public' : True ,
'user__isnull' : False
},
sort_attrs = [ 'user___name' , '-created_at' ],
schema = {
'post' : {
'user' : JOINED
}
}). all ()개발자로서 우리는 편리하게 물건을 디버깅해야합니다. 우리가 REPL로 플레이 할 때, 우리는 이것을 볼 수 있습니다
>>> session.query(Post).all()
[<myapp.models.Post object at 0x04287A50>, <myapp.models.Post object at 0x04287A90>]
글쎄, 우리의 믹스 인을 사용하면 포스트 ID를 사용하여 더 읽기 쉬운 출력을 가질 수 있습니다.
>>> session.query(Post).all()
[<Post #11>, <Post #12>]
더욱이 Post 모델에서 우리는보고 싶은 다른 것을 정의 할 수 있습니다.
class User ( BaseModel ):
__repr_attrs__ = [ 'name' ]
# ...
class Post ( BaseModel ):
__repr_attrs__ = [ 'user' , 'body' ] # body is just column, user is relationship
# ...이제 우리는 가지고 있습니다
>>> session.query(Post).all()
[<Post #11 user:<User #1 'Bill'> body:'post 11'>,
<Post #12 user:<User #2 'Bob'> body:'post 12'>]
최대 __repr__ 길이를 사용자 정의 할 수 있습니다.
class Post(BaseModel):
# ...
__repr_max_length__ = 25
# ...
>>> long_post
<Post #2 body:'Post 2 long-long body' user:<User #1 'Bob'>>
DateMixin 에서 제공합니다
생성 및 업데이트 된 타임 스탬프를 볼 수 있습니다.
bob = User ( name = "Bob" )
session . add ( bob )
session . flush ()
print ( "Created Bob: " , bob . created_at )
# Created Bob: 2019-03-04 03:53:53.606765
print ( "Pre-update Bob: " , bob . updated_at )
# Pre-update Bob: 2019-03-04 03:53:53.606769
time . sleep ( 2 )
bob . name = "Robert"
session . commit ()
print ( "Updated Bob: " , bob . updated_at )
# Updated Bob: 2019-03-04 03:53:58.613044