Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DocumentForm metaclass creates connection too early #64

Open
foxx opened this issue Apr 20, 2014 · 1 comment
Open

DocumentForm metaclass creates connection too early #64

foxx opened this issue Apr 20, 2014 · 1 comment

Comments

@foxx
Copy link

foxx commented Apr 20, 2014

DocumentFormMetaclass attempts to create a connection too quickly when a class is defined, with at least formfield_generator needing an open connection in order to continue (as seen in the below traceback).

This does not work well because a mongoengine connections might not yet be available at the time the forms.py is imported. For example when running unit tests, the app modules are imported first, and then setup_databases() is called which applies NAME patches to define what the test database name should be. However this breaks when using this library because the DocumentForm requires a connection before we even know what the connection name should be.

The quick fix is to lazy import each form class (i.e. within a method/function local, rather than a module global) but this is quite hacky.

Alternatively you could patch DocumentForm to return a lazy class loader, which doesn't create the new form type until the point where __init__.py is called. This would prevent the class meta being called at import. However anything which relies on introspection of DocumentForm will naturally break when using this approach.

An ideal patch would be to stop mongodbforms from requiring a connection inside formfield_generator, but it would seem this isn't a trivial thing to fix.

Any thoughts?

  File "/home/foxx/code/simplicitymedialtd/smsje-repo/smsje/libs/useful2/testproject/forms.py", line 47, in <module>
    class MessageCreateForm(PartialFormMixin, ReadOnlyFormFieldsMixin, DocumentForm):
  File "/home/foxx/.virtualenvs/smsje/local/lib/python2.7/site-packages/mongodbforms/documents.py", line 281, in __new__
    opts.exclude, opts.widgets, formfield_callback, formfield_generator)
  File "/home/foxx/.virtualenvs/smsje/local/lib/python2.7/site-packages/mongodbforms/documents.py", line 229, in fields_for_document
    formfield = field_generator.generate(f, **kwargs)            
  File "/home/foxx/.virtualenvs/smsje/local/lib/python2.7/site-packages/mongodbforms/fieldgenerator.py", line 401, in generate
    return super(MongoDefaultFormFieldGenerator, self).generate(field, **kwargs)
  File "/home/foxx/.virtualenvs/smsje/local/lib/python2.7/site-packages/mongodbforms/fieldgenerator.py", line 83, in generate
    return getattr(self, attr_name)(field, **kwargs)
  File "/home/foxx/.virtualenvs/smsje/local/lib/python2.7/site-packages/mongodbforms/fieldgenerator.py", line 308, in generate_referencefield
    'queryset': field.document_type.objects.clone(),
  File "/home/foxx/.virtualenvs/smsje/local/lib/python2.7/site-packages/mongoengine/queryset/manager.py", line 37, in __get__
    queryset = queryset_class(owner, owner._get_collection())
  File "/home/foxx/.virtualenvs/smsje/local/lib/python2.7/site-packages/mongoengine/document.py", line 148, in _get_collection
    db = cls._get_db()
  File "/home/foxx/.virtualenvs/smsje/local/lib/python2.7/site-packages/mongoengine/document.py", line 142, in _get_db
    return get_db(cls._meta.get("db_alias", DEFAULT_CONNECTION_NAME))
  File "/home/foxx/.virtualenvs/smsje/local/lib/python2.7/site-packages/mongoengine/connection.py", line 134, in get_db
    conn = get_connection(alias)
  File "/home/foxx/.virtualenvs/smsje/local/lib/python2.7/site-packages/mongoengine/connection.py", line 93, in get_connection
    raise ConnectionError(msg)
mongoengine.connection.ConnectionError: Connection with alias "default-mongo" has not been defined
@foxx
Copy link
Author

foxx commented Apr 20, 2014

Tried to get this working using the following patterns;

  • Lazy form class, hold loading real metaclass until an attribute is requested on the class/instance, but I was unable to find a working MRO combination that didn't cause type errors.
  • Lazy mongoengine connection, hold connecting until an attribute is requested, this didn't work because the formfield generator seems to query mongo in the metaclass
  • Delayed metaclass loader, overload new on base metaclass for DocumentForm, but again MROs were a problem

Each of these patterns failed, to fix it would probably require moving the formfield generators out of new and into init, but this could break introspection. Alternatively unless the formfield generator absolutely requires a database connection (though I'm struggling to think of a reason why it would), you could just remove the pre-req for a db connection.

I don't know enough about the internals of this library to make a solid suggestion, but the concept of connecting to a database during class creation rather than instantiation is certainly flawed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant