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

Merge branch 'master' of github.com:mrjoes/flask-admin

parents 2e823c72 d12a6e12
Flask-Admin includes some bundled software to ease installation.
Select2
=======
Distributed under `APLv2 <http://www.apache.org/licenses/LICENSE-2.0>`_.
Twitter Bootstrap
=================
Distributed under `APLv2 <http://www.apache.org/licenses/LICENSE-2.0>`_.
......@@ -33,7 +33,7 @@ Flask-Admin is extensively documented, you can find `documentation here <http://
3rd Party Stuff
---------------
Flask-Admin is built with help of `Twitter Bootstrap <http://twitter.github.com/bootstrap/>`_ and `Chosen <http://harvesthq.github.com/chosen/>`_.
Flask-Admin is built with help of `Twitter Bootstrap <http://twitter.github.com/bootstrap/>`_ and `Select2 <https://github.com/ivaynberg/select2>`_.
Kudos
-----
......
......@@ -17,6 +17,8 @@ import sys, os
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
sys.path.insert(0, os.path.abspath('..'))
import flask_admin
from flask_admin import __version__
# -- General configuration -----------------------------------------------------
......@@ -48,9 +50,9 @@ copyright = u'2012, Serge S. Koval'
# built documents.
#
# The short X.Y version.
version = '0.0.1'
version = __version__
# The full version, including alpha/beta/rc tags.
release = '0.0.1'
release = version
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
......
__version__ = '1.0.2'
from .base import expose, Admin, BaseView, AdminIndexView
......@@ -96,8 +96,18 @@ def contribute_inline(model, form_class, inline_models):
elif isinstance(p, BaseModel):
info = InlineFormAdmin(p)
else:
model = getattr(p, 'model', None)
if model is None:
raise Exception('Unknown inline model admin: %s' % repr(p))
attrs = dict()
for attr in dir(p):
if not attr.startswith('_') and attr != model:
attrs[attr] = getattr(p, attr)
info = InlineFormAdmin(model, **attrs)
# Find property from target model to current model
reverse_field = None
......
......@@ -70,23 +70,23 @@ class ModelView(BaseModelView):
Accept enumerable with one of the values:
1. Child model class
1. Child model class::
class MyModelView(ModelView):
inline_models = (Post,)
2. Child model class and additional options
2. Child model class and additional options::
class MyModelView(ModelView):
inline_models = [(Post, dict(form_columns=['title']))]
3. Django-like ``InlineFormAdmin`` class instance
3. Django-like ``InlineFormAdmin`` class instance::
class MyInlineForm(InlineFormAdmin):
forum_columns = ('title', 'date')
class MyInlineModelForm(InlineFormAdmin):
form_columns = ('title', 'date')
class MyModelView(ModelView):
inline_models = (MyInlineForm,)
inline_models = (MyInlineModelForm(MyInlineModel),)
"""
def __init__(self, model, name=None,
......@@ -340,7 +340,7 @@ class ModelView(BaseModelView):
count += 1
flash(ngettext('Model was successfully deleted.',
'%(count)s models were sucessfully deleted.',
'%(count)s models were successfully deleted.',
count,
count=count))
except Exception, ex:
......
......@@ -64,13 +64,13 @@ class AdminModelConverter(ModelConverterBase):
return override(**kwargs)
# Contribute model-related parameters
kwargs.update({
'allow_blank': local_column.nullable,
'query_factory': lambda: self.session.query(remote_model)
})
if 'allow_blank' not in kwargs:
kwargs['allow_blank'] = local_column.nullable,
if 'query_factory' not in kwargs:
kwargs['query_factory'] = lambda: self.session.query(remote_model)
if prop.direction.name == 'MANYTOONE':
return QuerySelectField(widget=form.ChosenSelectWidget(),
return QuerySelectField(widget=form.Select2Widget(),
**kwargs)
elif prop.direction.name == 'ONETOMANY':
# Skip backrefs
......@@ -78,11 +78,11 @@ class AdminModelConverter(ModelConverterBase):
return None
return QuerySelectMultipleField(
widget=form.ChosenSelectWidget(multiple=True),
widget=form.Select2Widget(multiple=True),
**kwargs)
elif prop.direction.name == 'MANYTOMANY':
return QuerySelectMultipleField(
widget=form.ChosenSelectWidget(multiple=True),
widget=form.Select2Widget(multiple=True),
**kwargs)
else:
# Ignore pk/fk
......@@ -348,8 +348,18 @@ def contribute_inline(session, model, form_class, inline_models):
elif hasattr(p, '_sa_class_manager'):
info = InlineFormAdmin(p)
else:
model = getattr(p, 'model', None)
if model is None:
raise Exception('Unknown inline model admin: %s' % repr(p))
attrs = dict()
for attr in dir(p):
if not attr.startswith('_') and attr != 'model':
attrs[attr] = getattr(p, attr)
info = InlineFormAdmin(model, **attrs)
# Find property from target model to current model
target_mapper = info.model._sa_class_manager.mapper
......
......@@ -138,34 +138,34 @@ class ModelView(BaseModelView):
giving SQLAlchemy chance to manually cleanup any dependencies (many-to-many
relationships, etc).
If set to True, will run DELETE statement which is somewhat faster, but
might leave corrupted data if you forget to configure DELETE CASCADE
for your model.
If set to `True`, will run `DELETE` statement which is somewhat faster,
but might leave corrupted data if you forget to configure `DELETE
CASCADE` for your model.
"""
inline_models = None
"""
Inline related-model editing for models with parent to child relation.
Inline related-model editing for models with parent-child relations.
Accept enumerable with one of the values:
Accepts enumerable with one of the following possible values:
1. Child model class
1. Child model class::
class MyModelView(ModelView):
inline_models = (Post,)
2. Child model class and additional options
2. Child model class and additional options::
class MyModelView(ModelView):
inline_models = [(Post, dict(form_columns=['title']))]
3. Django-like ``InlineFormAdmin`` class instance
3. Django-like ``InlineFormAdmin`` class instance::
class MyInlineForm(InlineFormAdmin):
forum_columns = ('title', 'date')
class MyInlineModelForm(InlineFormAdmin):
form_columns = ('title', 'date')
class MyModelView(ModelView):
inline_models = (MyInlineForm,)
inline_models = (MyInlineModelForm(MyInlineModel),)
"""
def __init__(self, model, session,
......@@ -657,7 +657,7 @@ class ModelView(BaseModelView):
self.session.commit()
flash(ngettext('Model was successfully deleted.',
'%(count)s models were sucessfully deleted.',
'%(count)s models were successfully deleted.',
count,
count=count))
except Exception, ex:
......
......@@ -83,28 +83,30 @@ class TimeField(fields.Field):
raise ValueError(gettext('Invalid time format'))
class ChosenSelectWidget(widgets.Select):
class Select2Widget(widgets.Select):
"""
`Chosen <http://harvesthq.github.com/chosen/>`_ styled select widget.
`Select2 <https://github.com/ivaynberg/select2>`_ styled select widget.
You must include chosen.js and form.js for styling to work.
You must include select2.js, form.js and select2 stylesheet for it to
work.
"""
def __call__(self, field, **kwargs):
if field.allow_blank and not self.multiple:
kwargs['data-role'] = u'chosenblank'
kwargs['data-role'] = u'select2blank'
else:
kwargs['data-role'] = u'chosen'
kwargs['data-role'] = u'select2'
return super(ChosenSelectWidget, self).__call__(field, **kwargs)
return super(Select2Widget, self).__call__(field, **kwargs)
class ChosenSelectField(fields.SelectField):
class Select2Field(fields.SelectField):
"""
`Chosen <http://harvesthq.github.com/chosen/>`_ styled select field.
`Select2 <https://github.com/ivaynberg/select2>`_ styled select widget.
You must include chosen.js and form.js for styling to work.
You must include select2.js, form.js and select2 stylesheet for it to
work.
"""
widget = ChosenSelectWidget
widget = Select2Widget
class DatePickerWidget(widgets.TextInput):
......
......@@ -20,6 +20,8 @@ class InlineFormAdmin(object):
class MyUserInfoForm(InlineFormAdmin):
form_columns = ('name', 'email')
"""
_defaults = ['form_columns', 'excluded_form_columns', 'form_args']
def __init__(self, model, **kwargs):
"""
Constructor
......@@ -31,13 +33,11 @@ class InlineFormAdmin(object):
"""
self.model = model
defaults = dict(form_columns=None,
excluded_form_columns=None,
form_args=None)
defaults.update(kwargs)
for k in self._defaults:
if not hasattr(self, k):
setattr(self, k, None)
for k, v in defaults.iteritems():
for k, v in kwargs.iteritems():
setattr(self, k, v)
......
This diff is collapsed.
This diff is collapsed.
......@@ -41,7 +41,7 @@ var AdminFilters = function(element, filters_element, operations, options, types
$select.append($('<option/>').attr('value', this[0]).text(this[1]));
});
$select.chosen();
$select.select2();
var optId = op[0][0];
......@@ -58,7 +58,7 @@ var AdminFilters = function(element, filters_element, operations, options, types
.appendTo($el);
});
$field.chosen();
$field.select2();
} else
{
$field = $('<input type="text" class="filter-val" />')
......
......@@ -2,11 +2,11 @@
var AdminForm = function() {
this.applyStyle = function(el, name) {
switch (name) {
case 'chosen':
$(el).chosen();
case 'select2':
$(el).select2({width: 'resolve'});
break;
case 'chosenblank':
$(el).chosen({allow_single_deselect: true});
case 'select2blank':
$(el).select2({allowClear: true, width: 'resolve'});
break;
case 'datepicker':
$(el).datepicker();
......@@ -49,8 +49,8 @@
};
this.applyGlobalStyles = function(parent) {
$('[data-role=chosen]', parent).chosen();
$('[data-role=chosenblank]', parent).chosen({allow_single_deselect: true});
$('[data-role=select2]', parent).select2({width: 'resolve'});
$('[data-role=select2blank]', parent).select2({allowClear: true, width: 'resolve'});
$('[data-role=datepicker]', parent).datepicker();
$('[data-role=datetimepicker]', parent).datepicker({displayTime: true});
};
......
Copyright 2012 Igor Vaynberg
Version: @@ver@@ Timestamp: @@timestamp@@
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this work except in
compliance with the License. You may obtain a copy of the License in the LICENSE file, or at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and limitations under the License.
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
......@@ -74,7 +74,7 @@
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" type="text/javascript"></script>
<script src="{{ url_for('admin.static', filename='bootstrap/js/bootstrap.min.js') }}" type="text/javascript"></script>
<script src="{{ url_for('admin.static', filename='chosen/chosen.jquery.min.js') }}" type="text/javascript"></script>
<script src="{{ url_for('admin.static', filename='select2/select2.min.js') }}" type="text/javascript"></script>
{% block tail %}
{% endblock %}
......
......@@ -2,7 +2,7 @@
{% import 'admin/lib.html' as lib with context %}
{% block head %}
<link href="{{ url_for('admin.static', filename='chosen/chosen.css') }}" rel="stylesheet">
<link href="{{ url_for('admin.static', filename='select2/select2.css') }}" rel="stylesheet">
<link href="{{ url_for('admin.static', filename='css/datepicker.css') }}" rel="stylesheet">
{% endblock %}
......
......@@ -2,7 +2,7 @@
{% import 'admin/lib.html' as lib with context %}
{% block head %}
<link href="{{ url_for('admin.static', filename='chosen/chosen.css') }}" rel="stylesheet">
<link href="{{ url_for('admin.static', filename='select2/select2.css') }}" rel="stylesheet">
<link href="{{ url_for('admin.static', filename='css/datepicker.css') }}" rel="stylesheet">
{% endblock %}
......
......@@ -3,7 +3,7 @@
{% import 'admin/actions.html' as actionlib with context %}
{% block head %}
<link href="{{ url_for('admin.static', filename='chosen/chosen.css') }}" rel="stylesheet">
<link href="{{ url_for('admin.static', filename='select2/select2.css') }}" rel="stylesheet">
<link href="{{ url_for('admin.static', filename='css/datepicker.css') }}" rel="stylesheet">
{% endblock %}
......@@ -73,14 +73,14 @@
{% set filter = admin_view._filters[flt[0]] %}
<a href="#" class="btn remove-filter" title="{{ _gettext('Remove Filter') }}">
<span class="close-icon">&times;</span>&nbsp;{{ filters[flt[0]] }}
</a><select class="filter-op" data-role="chosen">
</a><select class="filter-op" data-role="select2">
{% for op in admin_view._filter_dict[filter.name] %}
<option value="{{ op[0] }}"{% if flt[0] == op[0] %} selected="selected"{% endif %}>{{ op[1] }}</option>
{% endfor %}
</select>
{%- set data = filter_data.get(flt[0]) -%}
{%- if data -%}
<select name="flt{{ i }}_{{ flt[0] }}" class="filter-val" data-role="chosen">
<select name="flt{{ i }}_{{ flt[0] }}" class="filter-val" data-role="select2">
{%- for d in data %}
<option value="{{ d[0] }}"{% if flt[1] == d[0] %} selected{% endif %}>{{ d[1] }}</option>
{%- endfor %}
......
# Fix for older setuptools
import multiprocessing, logging, os
import flask_admin
from setuptools import setup, find_packages
......@@ -17,7 +19,7 @@ def desc():
setup(
name='Flask-Admin',
version='1.0.2',
version=flask_admin.__version__,
url='https://github.com/mrjoes/flask-admin/',
license='BSD',
author='Serge S. Koval',
......
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