【问题标题】:Flask Admin need HTML5 color picker fieldFlask Admin 需要 HTML5 颜色选择器字段
【发布时间】:2021-07-23 04:15:53
【问题描述】:

我正在使用 Flask-Admin 创建数据库表的视图。我们的一个表格有一个“颜色”列,它是“可编辑”,这意味着如果您点击它,您可以直接编辑文本,它会更新数据库阿贾克斯。这是一个文本字段,我期待像“#3CA4FF”这样的十六进制颜色。

我希望这个“可编辑”颜色列有一个 HTML5 颜色选择器小部件来辅助颜色选择(即<input type="color">)。

这是我的 Python 代码:

  1. SQLAlchemy 表模型类
  2. 自定义 ColorField wtforms 字段
  3. Flask-Admin 模型视图类

以下可以很好地将我的自定义 ColorField 添加到“编辑”表单,但我真正想要的是使用 column_editable_list 选项对其进行编辑。

from flask_admin.contrib.sqla import ModelView
from wtforms.widgets.html5 import ColorInput
from wtforms.widgets import TextInput
from wtforms import StringField
from wtforms.fields import TextAreaField

from app import db


class UnitType(db.Model):
    """Create a SQLAlchemy model for the our manufactured units"""

    __tablename__ = "unit_types"

    id = db.Column(INTEGER, primary_key=True)
    unit = db.Column(TEXT, unique=True, nullable=False)
    color = db.Column(TEXT, nullable=True)


class ColorField(TextAreaField):
    """Create special ColorField for the color picker"""

    # Set the widget for this custom field
    widget = ColorInput()


class UnitModelView(ModelView):
    """The Flask-Admin view for the UnitModel model class"""
    
    # List of columns to display in the view
    column_list = (
        "unit",
        "color",
    )

    # List of columns that are immediately "editable"
    # without clicking "edit" first (super-nice feature)
    column_editable_list = (
        "unit",
        # If I uncomment the following, I get an error...
        # "color",
    )

    # Specify my own custom color picker form field type
    form_overrides = {
        'color': ColorField
    }

    # form_args = {
    #     'color': {
    #         'type': "color",
    #     },
    # }

    # form_widget_args = {
    #     'color': {
    #         'type': "color",
    #     },
    # }

当我将“颜色”字段添加到 column_editable_list 时,我收到以下错误:

Exception: Unsupported field type: <class 'app.admin.admin.ColorField'>

我不确定接下来要尝试什么...

【问题讨论】:

  • 可能是烧瓶管理员的问题。

标签: python flask flask-sqlalchemy color-picker flask-admin


【解决方案1】:

经过多次反复试验,我至少想出了如何添加一个自定义的 select2 下拉菜单,该菜单将实际选择的颜色显示在十六进制颜色值的左侧。

首先创建一个自定义小部件,这样我们就不会收到以下错误:

Exception: Unsupported field type: <class 'flask_admin.model.fields.AjaxSelectField'>

这是自定义小部件:

from flask_admin.contrib.sqla.ajax import QueryAjaxModelLoader
from flask_admin.model.widgets import XEditableWidget
from wtforms.widgets import html_params
from flask_admin.helpers import get_url
from flask_admin.babel import gettext
from flask_admin._backwards import Markup
from jinja2 import escape


class CustomWidget(XEditableWidget):
    """WTForms widget that provides in-line editing for the list view"""

    def get_kwargs(self, field, kwargs):
        """Return extra kwargs based on the field type"""

        if field.type == "ColorField":
            # A select2 list of pre-defined colors, formatted to display the actual color
            kwargs["data-role"] = "x-editable-color"
            kwargs["data-type"] = "select2"
        else:
            super().get_kwargs(field, kwargs)

        return kwargs

然后在您的模型视图中覆盖 get_list_form() 方法,以使用您的 CustomWidget。

from flask_admin.contrib.sqla import ModelView


class MyModelView(ModelView):
    """
    Customized model view for Flask-Admin page (for database tables)
    https://flask-admin.readthedocs.io/en/latest/introduction/#
    """

    # Custom templates to include custom JavaScript and override the {% block tail %}
    list_template = 'admin/list_custom.html'

    can_create = True
    can_edit = True

    def get_list_form(self):
        """Override this function and supply my own CustomWidget with AJAX 
        for lazy-loading dropdown options"""

        if self.form_args:
            # get only validators, other form_args can break FieldList wrapper
            validators = dict(
                (key, {'validators': value["validators"]})
                for key, value in iteritems(self.form_args)
                if value.get("validators")
            )
        else:
            validators = None

        # Here's where I supply my custom widget!
        return self.scaffold_list_form(validators=validators, widget=CustomWidget())

这是我的list_custom.html 模板,用于用我自己的flask_admin_form.js 脚本覆盖{% block tail %},用于我的自定义小部件。

{% extends 'admin/model/list.html' %}

{% block tail %}
    {% if filter_groups %}
      <div id="filter-groups-data" style="display:none;">{{ filter_groups|tojson|safe }}</div>
      <div id="active-filters-data" style="display:none;">{{ active_filters|tojson|safe }}</div>
    {% endif %}

    <script src="{{ admin_static.url(filename='vendor/bootstrap-daterangepicker/daterangepicker.js', v='1.3.22') }}"></script>
    {% if editable_columns %}
      <script src="{{ admin_static.url(filename='vendor/x-editable/js/bootstrap3-editable.min.js', v='1.5.1.1') }}"></script>
    {% endif %}

    <!-- Custom JavaScript -->
    <script src="{{ url_for('static', filename='js/flask_admin_form.js') }}"></script>

    <script src="{{ admin_static.url(filename='admin/js/filters.js', v='1.0.0') }}"></script>

    {{ actionlib.script(_gettext('Please select at least one record.'),
                        actions,
                        actions_confirmation) }}
{% endblock %}

最后,在flask_admin_form.js(我替换默认的filename='admin/js/form.js')中,我为x-editable-color(我的自定义角色)添加了以下案例。为简洁起见,我没有在此处包含整个 JavaScript 文件。可以在源码中找到here

注意我添加到$el.editable( 选项中的select2

...
      switch (name) {
        case "select2-ajax":
          processAjaxWidget($el, name);
          return true;

        case "x-editable":
          $el.editable({
            params: overrideXeditableParams,
            combodate: {
              // prevent minutes from showing in 5 minute increments
              minuteStep: 1,
              maxYear: 2030,
            },
          });
          return true;

        case "x-editable-color":
          // Nice pastel colors
          var colorsource = [
            {value: "#f7f7f7", text: "#f7f7f7"},
            {value: "#292b2c", text: "#292b2c"},
            {value: "#87CEEB", text: "#87CEEB"},
            {value: "#32CD32", text: "#32CD32"},
            {value: "#BA55D3", text: "#BA55D3"},
            {value: "#F08080", text: "#F08080"},
            {value: "#4682B4", text: "#4682B4"},
            {value: "#9ACD32", text: "#9ACD32"},
            {value: "#40E0D0", text: "#40E0D0"},
            {value: "#FF69B4", text: "#FF69B4"},
            {value: "#F0E68C", text: "#F0E68C"},
            {value: "#D2B48C", text: "#D2B48C"},
            {value: "#8FBC8B", text: "#8FBC8B"},
            {value: "#6495ED", text: "#6495ED"},
            {value: "#DDA0DD", text: "#DDA0DD"},
            {value: "#5F9EA0", text: "#5F9EA0"},
            {value: "#FFDAB9", text: "#FFDAB9"},
            {value: "#FFA07A", text: "#FFA07A"},
            {value: "#fce38a", text: "#fce38a"},
            {value: "#eaffd0", text: "#eaffd0"},
            {value: "#95e1d3", text: "#95e1d3"},
          ]

          var optsSelect2 = {
            placeholder: $el.attr("data-value"),
            minimumInputLength: $el.attr("data-minimum-input-length"),
            allowClear: $el.attr("data-allow-blank") == "1",
            multiple: $el.attr("data-multiple") == "1",
            // Display the actual color next to the hex value of the color
            formatResult: function (item) { return "<span style='padding-left: 20px; border-left: 20px solid " + item.text + "'>" + item.text + "</span>"; },
            formatSelection: function (item){ return item.text; },
          };
          
          $el.editable({
            // Source data for list of colors, as array of objects
            source: colorsource,
            params: overrideXeditableParams,
            // select2-specific options
            select2: optsSelect2,
          });

          return true;
...

【讨论】:

    猜你喜欢
    • 2017-02-13
    • 2018-10-13
    • 1970-01-01
    • 2013-05-18
    • 2012-01-23
    • 1970-01-01
    • 2011-10-12
    • 2020-08-14
    • 1970-01-01
    相关资源
    最近更新 更多