2016-11-04 3 views
1

내 데이터베이스에 대한 모델을 만든 : 그들은 대다 앨범 < 관련있는추상화 SQLAlchemy의 조건 필터링에

class Album(db.Model): 
    id = db.Column(db.Integer, primary_key=True) 
    title = db.Column(db.String(128)) 
    year = db.Column(db.String(4)) 
    tracklist = db.relationship('Track', secondary=tracklist, 
           backref=db.backref('albums', 
           lazy='dynamic'), lazy='dynamic') 

class Track(db.Model): 
    id = db.Column(db.Integer, primary_key=True) 
    title = db.Column(db.String(128)) 

class Artist(db.Model): 
    id = db.Column(db.Integer, primary_key=True) 
    name = db.Column(db.String(128)) 
    releases = db.relationship('Track', secondary=releases, 
           backref=db.backref('artists',   
           lazy='dynamic'), lazy='dynamic') 

-> 트랙 < -> 아티스트

다음으로, 이 양식을 가지고 :

class SearchForm(FlaskForm): 
    search_by_album = StringField('Album', validators=[Optional()]) 
    search_by_artist = StringField('Artist', validators=[Optional()]) 
    search_track = StringField('Track', validators=[Optional()]) 
    year = StringField('Year', validators=[Optional(), Length(max=4)]) 

내 생각은 (필요하지만 적어도 하나) 형태의 원하는 조합을 채우는에서 사용자의 자유를 제공하는 것입니다, 그래서이 기능을 가지고있는 . 접수가 SearchForm() 데이터 (불변 딕셔너리 'FIELD_NAME': '데이터') : 위의 기능에 필터를 추가하는 추상적 방법이 있는지

def construct_query(form): 
    query = db.session.query(*[field.label.text for field in form if field.data and field.name != 'csrf_token']) 
    if form.search_by_album.data: 
     query = query.filter(Album.title == form.search_by_album.data) 
    if form.search_by_artist.data: 
     query = query.filter(Artist.name == form.search_by_artist.data) 
    if form.search_track.data: 
     query = query.filter(Track.title == form.search_track.data) 
    if form.year.data: 
     query = query.filter(Album.year == form.year.data) 
    result = query.all() 
    return result 

내 질문은? 언젠가 내가 테이블에 열을 더 추가하거나 심지어 새로운 테이블을 생성하기로 결정했다면 constrcut_query()에 괴물 ifs를 추가해야합니다. 그러면 엄청나게 커질 것입니다. 또는 "Explicit은 암시 적보다 낫다"때문에 그러한 추상화는 파이썬적인 방식이 아닙니다.

PS 나는 모델의 형태에 대해 알고 있지만, 나는 그들이

답변

1
한 가지 방법은 어떤 장소에서 필드 필터 - 속성을 연결하는 것

, 예를 들어, 내 경우라고 생각하지 않는다 양식 자체에 클래스 속성으로 : 새로운 필드를 추가

def construct_query(form): 
    query = db.session.query(*[field.label.text for field in form if field.data and field.name != 'csrf_token']) 

    for field in form: 
     if field.data: 
      query = query.filter(form.field_to_attr[field] == field.data) 

    # or: 
    # for field, attr in form.field_to_attr.items(): 
    # if field.data: 
    #  query = query.filter(attr == field.data) 

    result = query.all() 
    return result 

및 것 필터링 속성 : 쿼리를 만들 때

class SearchForm(FlaskForm): 

    search_by_album = StringField('Album', validators=[Optional()]) 
    search_by_artist = StringField('Artist', validators=[Optional()]) 
    search_track = StringField('Track', validators=[Optional()]) 
    year = StringField('Year', validators=[Optional(), Length(max=4)]) 

    # map form fields to database fields/attributes 
    field_to_attr = {search_by_album: Album.title, 
        search_by_artist: Artist.name, 
        search_track: Track.title, 
        year: Album.year} 

, 당신은 매우 편안한 방식으로 where 절을 만들 수 필드 생성 및 속성에 대한 매핑으로 변환됩니다.

+0

그게 전부입니다! 사실 훨씬 단순하고 파이소 닉하고 싶었습니다. C# 여전히 꽉 내 마음에 앉아 (신이 파이썬에서 인터페이스를 생각해 주신 것을 용서해주십시오) –