2016-11-04 54 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()的数据(一个不变的dict“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,这将最终增长很多。或者这样的抽象不是pythonic的方式,因为“显式比隐式更好”?

PS 我知道从模型的形式,但我不认为他们是我的情况

回答

1

一种方式将过滤器属性与领域在一些地方相关联,例如作为窗体本身上的类属性:

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子句:

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 

添加新的字段和属性筛选上会那么只能转化为创建该字段及其映射到一个属性。

+0

就是这样,先生!事实上,比我想要做的要简单多了。 C#仍然紧盯着我的想法(上帝原谅我思考python中的接口) –