Search code examples
pythonmongoengineflask-admin

How to specify label_attr for a model in a Flask-Admin ModelView using MongoEngine?


I think I have a pretty common use case and am surprised at how much trouble it's giving me.

I want to use a key-value pair for a ReferenceField in the Flask-Admin edit form generated by the following two classes:

class Communique(db.Document):
    users = db.ListField(db.ReferenceField(User), default=[])

class User(db.Document):
    email = db.StringField(max_length=255, required=True)

    def __unicode__(self):
        return '%s' % self.id

I want the select to be constructed out of the ObjectId and the an email field in my model.

By mapping the __unicode__ attribute to the id field I get nice things on the mongoengine side like using the entire object in queries:

UserInformation.objects(user=current_user)

This has the unfortunate effect of causing the Flask-Admin form to display the mongo ObjectId in the edit form like so:

enter image description here

The docs say I have to provide the label_attr to the ModelSelectMultipleField created by Flask-Admin. I've done so by overriding the get_form method on my ModelView:

def get_form(self):
     form = super(ModelView, self).get_form()
     form.users = ModelSelectMultipleField(model=User,  
         label_attr='email',                                          
         widget=form.users.__dict__['kwargs']['widget'])
     return form

I'm reusing the the widget used by the original form.users (which may be wrong). It works fine when editing an existing item, BUT throws an exception when creating a new one (perhaps because I'm reusing the widget).

All of this seems like way more work than should be needed to simply provide a label_attr to my SelectField. Fixing up the listing view was a simple matter of adding an entry to the column_formatters dictionary. Is there no simple way to specify the label_attr when creating my ModelView class?

I know I could make this problem go away by returning the email property in the __unicode__ attribute, but I feel like I shouldn't have to do that! Am I missing something?


Solution

  • Oy, now I see how to do it, though it's not that obvious from the docs. form_args is a dictionary with items keyed to the form models. All I needed to do was...

    form_args = dict(users=dict(label_attr='email'))
    

    Which does seem about the right amount of effort (considering Flask-Admin isn't some sort of java framework).