Commit c9a0dbcd authored by Serge S. Koval's avatar Serge S. Koval

Allow overriding base form class

parent f3eb5cf1
...@@ -14,7 +14,6 @@ from mongoengine.connection import get_db ...@@ -14,7 +14,6 @@ from mongoengine.connection import get_db
from bson.objectid import ObjectId from bson.objectid import ObjectId
from flask.ext.admin.actions import action from flask.ext.admin.actions import action
from flask.ext.admin.form import BaseForm
from .filters import FilterConverter, BaseMongoEngineFilter from .filters import FilterConverter, BaseMongoEngineFilter
from .form import get_form, CustomModelConverter from .form import get_form, CustomModelConverter
from .typefmt import DEFAULT_FORMATTERS from .typefmt import DEFAULT_FORMATTERS
...@@ -251,7 +250,7 @@ class ModelView(BaseModelView): ...@@ -251,7 +250,7 @@ class ModelView(BaseModelView):
""" """
form_class = get_form(self.model, form_class = get_form(self.model,
self.model_form_converter(self), self.model_form_converter(self),
base_class=BaseForm, base_class=self.form_base_class,
only=self.form_columns, only=self.form_columns,
exclude=self.form_excluded_columns, exclude=self.form_excluded_columns,
field_args=self.form_args, field_args=self.form_args,
......
...@@ -218,7 +218,7 @@ class ModelView(BaseModelView): ...@@ -218,7 +218,7 @@ class ModelView(BaseModelView):
def scaffold_form(self): def scaffold_form(self):
form_class = get_form(self.model, self.model_form_converter(), form_class = get_form(self.model, self.model_form_converter(),
base_class=form.BaseForm, base_class=self.form_base_class,
only=self.form_columns, only=self.form_columns,
exclude=self.form_excluded_columns, exclude=self.form_excluded_columns,
field_args=self.form_args, field_args=self.form_args,
......
...@@ -513,6 +513,7 @@ class ModelView(BaseModelView): ...@@ -513,6 +513,7 @@ class ModelView(BaseModelView):
""" """
converter = self.model_form_converter(self.session, self) converter = self.model_form_converter(self.session, self)
form_class = form.get_form(self.model, converter, form_class = form.get_form(self.model, converter,
base_class=self.form_base_class,
only=self.form_columns, only=self.form_columns,
exclude=self.form_excluded_columns, exclude=self.form_excluded_columns,
field_args=self.form_args, field_args=self.form_args,
......
...@@ -144,9 +144,6 @@ class FileUploadField(fields.TextField): ...@@ -144,9 +144,6 @@ class FileUploadField(fields.TextField):
:param allowed_extensions: :param allowed_extensions:
List of allowed extensions. If not provided, will allow any file. List of allowed extensions. If not provided, will allow any file.
""" """
if not base_path:
raise ValueError('FileUploadField field requires target path.')
self.base_path = base_path self.base_path = base_path
self.relative_path = relative_path self.relative_path = relative_path
...@@ -210,6 +207,9 @@ class FileUploadField(fields.TextField): ...@@ -210,6 +207,9 @@ class FileUploadField(fields.TextField):
return urljoin(self.relative_path, filename) return urljoin(self.relative_path, filename)
def _get_path(self, filename): def _get_path(self, filename):
if not self.base_path:
raise ValueError('FileUploadField field requires base_path to be set.')
return op.join(self.base_path, filename) return op.join(self.base_path, filename)
def _delete_file(self, filename): def _delete_file(self, filename):
......
...@@ -7,6 +7,7 @@ from jinja2 import contextfunction ...@@ -7,6 +7,7 @@ from jinja2 import contextfunction
from flask.ext.admin.babel import gettext from flask.ext.admin.babel import gettext
from flask.ext.admin.base import BaseView, expose from flask.ext.admin.base import BaseView, expose
from flask.ext.admin.form import BaseForm
from flask.ext.admin.model import filters, typefmt from flask.ext.admin.model import filters, typefmt
from flask.ext.admin.actions import ActionsMixin from flask.ext.admin.actions import ActionsMixin
from flask.ext.admin.helpers import get_form_data, validate_form_on_submit from flask.ext.admin.helpers import get_form_data, validate_form_on_submit
...@@ -247,16 +248,34 @@ class BaseModelView(BaseView, ActionsMixin): ...@@ -247,16 +248,34 @@ class BaseModelView(BaseView, ActionsMixin):
form = None form = None
""" """
Form class. Override if you want to use custom form for your model. Form class. Override if you want to use custom form for your model.
Will completely disable form scaffolding functionality.
For example:: For example::
class MyForm(Form): class MyForm(Form):
pass name = TextField('Name')
class MyModelView(BaseModelView): class MyModelView(BaseModelView):
form = MyForm form = MyForm
""" """
form_base_class = BaseForm
"""
Base form class. Will be used by form scaffolding function when creating model form.
Useful if you want to have custom contructor or override some fields.
Example::
class MyBaseForm(Form):
def do_something(self):
pass
class MyModelView(BaseModelView):
form_base_class = MyBaseForm
"""
form_args = None form_args = None
""" """
Dictionary of form field arguments. Refer to WTForms documentation for Dictionary of form field arguments. Refer to WTForms documentation for
......
...@@ -8,6 +8,7 @@ if not PY2: ...@@ -8,6 +8,7 @@ if not PY2:
from wtforms import fields from wtforms import fields
from flask.ext.admin import form
from flask.ext.admin.contrib.mongoengine import ModelView from flask.ext.admin.contrib.mongoengine import ModelView
from . import setup from . import setup
...@@ -191,3 +192,23 @@ def test_extra_field_order(): ...@@ -191,3 +192,23 @@ def test_extra_field_order():
pos1 = data.find('Extra Field') pos1 = data.find('Extra Field')
pos2 = data.find('Test1') pos2 = data.find('Test1')
ok_(pos2 > pos1) ok_(pos2 > pos1)
def test_custom_form_base():
app, db, admin = setup()
class TestForm(form.BaseForm):
pass
Model1, _ = create_models(db)
view = CustomModelView(
Model1,
form_base_class=TestForm
)
admin.add_view(view)
ok_(hasattr(view._create_form_class, 'test1'))
create_form = view.create_form()
ok_(isinstance(create_form, TestForm))
...@@ -10,6 +10,7 @@ import peewee ...@@ -10,6 +10,7 @@ import peewee
from wtforms import fields from wtforms import fields
from flask.ext.admin import form
from flask.ext.admin._compat import iteritems from flask.ext.admin._compat import iteritems
from flask.ext.admin.contrib.peewee import ModelView from flask.ext.admin.contrib.peewee import ModelView
...@@ -173,3 +174,23 @@ def test_extra_fields(): ...@@ -173,3 +174,23 @@ def test_extra_fields():
pos1 = data.find('Extra Field') pos1 = data.find('Extra Field')
pos2 = data.find('Test1') pos2 = data.find('Test1')
ok_(pos2 < pos1) ok_(pos2 < pos1)
def test_custom_form_base():
app, db, admin = setup()
class TestForm(form.BaseForm):
pass
Model1, _ = create_models(db)
view = CustomModelView(
Model1,
form_base_class=TestForm
)
admin.add_view(view)
ok_(hasattr(view._create_form_class, 'test1'))
create_form = view.create_form()
ok_(isinstance(create_form, TestForm))
...@@ -2,6 +2,7 @@ from nose.tools import eq_, ok_, raises ...@@ -2,6 +2,7 @@ from nose.tools import eq_, ok_, raises
from wtforms import fields from wtforms import fields
from flask.ext.admin import form
from flask.ext.admin._compat import iteritems from flask.ext.admin._compat import iteritems
from flask.ext.admin.contrib.sqla import ModelView from flask.ext.admin.contrib.sqla import ModelView
...@@ -618,4 +619,23 @@ def test_extra_field_order(): ...@@ -618,4 +619,23 @@ def test_extra_field_order():
pos2 = data.find('Test1') pos2 = data.find('Test1')
ok_(pos2 > pos1) ok_(pos2 > pos1)
# TODO: Babel tests # TODO: Babel tests
def test_custom_form_base():
app, db, admin = setup()
class TestForm(form.BaseForm):
pass
Model1, _ = create_models(db)
view = CustomModelView(
Model1, db.session,
form_base_class=TestForm
)
admin.add_view(view)
ok_(hasattr(view._create_form_class, 'test1'))
create_form = view.create_form()
ok_(isinstance(create_form, TestForm))
...@@ -309,3 +309,5 @@ def test_custom_form(): ...@@ -309,3 +309,5 @@ def test_custom_form():
eq_(view._create_form_class, TestForm) eq_(view._create_form_class, TestForm)
eq_(view._edit_form_class, TestForm) eq_(view._edit_form_class, TestForm)
ok_(not hasattr(view._create_form_class, 'col1'))
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment