0

I have a sqlalchemy model that I am searching with flask-whooshalchemy. I was looking to include the output of a method in the search fields but can't figure out how it's done or if it's even possible. The flask-whooshalchemy documentation is a little limited.

I'm currently trying something like this:

class Trade(db.Model):
    __searchable__ = [
        'species', 'nature', 'ability', 'move1', 'move2', 'move3', 'move4', 'ivSpread']

    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
    dex_no = db.Column(db.Integer)
    species = db.Column(db.String(30))
    male = db.Column(db.Boolean)
    female = db.Column(db.Boolean)
    nature = db.Column(db.String(30))
    ability = db.Column(db.String(30))
    iv_hp = db.Column(db.Integer)
    iv_atk = db.Column(db.Integer)
    iv_def = db.Column(db.Integer)
    iv_spa = db.Column(db.Integer)
    iv_spd = db.Column(db.Integer)
    iv_spe = db.Column(db.Integer)
    move1 = db.Column(db.String(30))
    move2 = db.Column(db.String(30))
    move3 = db.Column(db.String(30))
    move4 = db.Column(db.String(30))

    def ivSpread(self):
        ivs = [
            self.iv_hp,
            self.iv_atk,
            self.iv_def,
            self.iv_spa,
            self.iv_spd,
            self.iv_spe
        ]
        return "/".join(ivs)

    def __repr__(self):
        return '<Post %r: %r>' % (self.owner.nickname, self.species)

Let me know if I can provide any more information. Suggestions of alternate modules to use is fine too, I'm sure there could be something more powerful than flask-whooshalchemy out there. It hasn't been pushed to in 2 years after all.

e: Using the above as is and with the @property suggestion provided by Mark Hildreth below, I get the following traceback.

whoosh.fields.UnknownFieldError
UnknownFieldError: No field named 'ivSpread' in <Schema: ['ability', 'gender', 'id', 'move1', 'move2', 'move3', 'move4', 'nature', 'species']>

Traceback (most recent call last):
  File "c:\Python27\lib\site-packages\flask\app.py", line 1701, in __call__
    return self.wsgi_app(environ, start_response)
  File "c:\Python27\lib\site-packages\flask\app.py", line 1689, in wsgi_app
    response = self.make_response(self.handle_exception(e))
  File "c:\Python27\lib\site-packages\flask\app.py", line 1687, in wsgi_app
    response = self.full_dispatch_request()
  File "c:\Python27\lib\site-packages\flask\app.py", line 1360, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "c:\Python27\lib\site-packages\flask\app.py", line 1358, in full_dispatch_request
    rv = self.dispatch_request()
  File "c:\Python27\lib\site-packages\flask\app.py", line 1344, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "c:\Users\Shane\Documents\Coding\python\flask\trade_lister\app\views.py", line 172, in new_trade
    db.session.commit()
  File "c:\Python27\lib\site-packages\sqlalchemy\orm\scoping.py", line 114, in do
    return getattr(self.registry(), name)(*args, **kwargs)
  File "c:\Python27\lib\site-packages\sqlalchemy\orm\session.py", line 703, in commit
    self.transaction.commit()
  File "c:\Python27\lib\site-packages\sqlalchemy\orm\session.py", line 367, in commit
    self.session.dispatch.after_commit(self.session)
  File "c:\Python27\lib\site-packages\sqlalchemy\event.py", line 319, in __call__
    fn(*args, **kw)
  File "c:\Python27\lib\site-packages\flask_sqlalchemy\__init__.py", line 170, in session_signal_after_commit
    models_committed.send(session.app, changes=d.values())
  File "c:\Python27\lib\site-packages\blinker\base.py", line 267, in send
    for receiver in self.receivers_for(sender)]
  File "c:\Python27\lib\site-packages\flask_whooshalchemy.py", line 256, in _after_flush
    writer.update_document(**attrs)
  File "c:\Python27\lib\site-packages\whoosh\writing.py", line 477, in update_document
    self.add_document(**fields)
  File "c:\Python27\lib\site-packages\whoosh\writing.py", line 730, in add_document
    self._check_fields(schema, fieldnames)
  File "c:\Python27\lib\site-packages\whoosh\writing.py", line 718, in _check_fields
    % (name, schema))
UnknownFieldError: No field named 'ivSpread' in <Schema: ['ability', 'gender', 'id', 'move1', 'move2', 'move3', 'move4', 'nature', 'species']>
sharktamer
  • 126
  • 9

1 Answers1

1

I don't know nearly enough about Woosh or Flask-Wooshalchemy, so this might be wrong, but I imagine you might be able to do something like this...

class Trade(db.Model):
    #...

    @property
    def ivSpread(self):
        #...

This uses a property to make the method call look like an attribute, so instead of doing... t = Trade(...) print t.ivSpread()

...you would do...

t = Trade(...)
print t.ivSpread

This would be necessary because Flask-WooshAlchemy seems to be assuming that the searchable item is an attribute, and at this point it's just pulling the method without calling it.

If you need to have ivSpread stay a method, you can use a wrapper:

class Trade(db.Model):
    #...

    def ivSpread(self):
        #...

    @property
    def ivSpreadProp(self):
        return self.ivSpread()

Then you would need to make ivSpreadProp searchable rathe rthan ivSpread.

Edit:

Looks like what you are trying to do is not currently possible. See here:

searchable = set(model.__searchable__)
for field in model.__table__.columns:
    if field.primary_key:
        schema[field.name] = whoosh.fields.ID(stored=True, unique=True)
        primary = field.name

    if field.name in searchable and isinstance(field.type,
            (sqlalchemy.types.Text, sqlalchemy.types.String,
                sqlalchemy.types.Unicode)):

        schema[field.name] = whoosh.fields.TEXT(
                analyzer=StemmingAnalyzer())

Flask-WhooshAlchemy assumes that items in the __searchable__ attribute are going to be columns defined by your model using SQLAlchemy. Flask-WhooshAlchemy would need to allow you to achieve your goal cleanly.

Mark Hildreth
  • 42,023
  • 11
  • 120
  • 109
  • Unfortunately not. Thanks for the suggestion though. I've included the traceback in the original question now. – sharktamer Jan 06 '14 at 21:28
  • I've updated my answer. Unfortunately, the answer appears to be "it's not really easily possible". Flask-WhooshAlchemy does not appear to support this. You could recommend this as a feature request to the Flask-WhooshAlchemy maintainer (or try to add it yourself!). – Mark Hildreth Jan 06 '14 at 22:03
  • I think I'm better off switching to something like flask-whooshee, seeing if it supports it and then requesting it there. Like I said, flask-whooshalchemy hasn't been maintained in two years. I would have used flask-whooshee in the beginning if I had known. Looks like I should close this? – sharktamer Jan 06 '14 at 22:05