【问题标题】:Django comma-separated field does not work well with admin siteDjango 逗号分隔字段不适用于管理站点
【发布时间】:2020-05-06 14:47:17
【问题描述】:

我在documentation(Django 3.0)之后编写了一个如下所示的自定义字段。 该字段允许存储逗号分隔的字符串列表。

我的问题是from_db_value 在管理站点中填充表单字段时也会被调用。

例如,假设数据库中的值为alpha,beta,代表Python列表['alpha', 'beta']。如果我想更改模型实例,表单将填充字符串['alpha', 'beta']。 这不会很糟糕,但是当我保存模型实例(不触及该字段)时,新值变为["['alpha'", " 'beta']"]!换句话说,表单域的输入然后被解释为一个逗号分隔的列表。

为了拥有一个可用的管理站点,处理这个问题的正确方法是什么?

class CommaSepField(models.CharField):
    description = "A comma-separated list of strings"

    def __init__(self, separator=",", *args, **kwargs):
        self.separator = separator
        super().__init__(*args, **kwargs)

    def deconstruct(self):
        name, path, args, kwargs = super().deconstruct()
        # Only include kwarg if it's not the default
        if self.separator != ",":
            kwargs['separator'] = self.separator
        return name, path, args, kwargs

    def from_db_value(self, value, expression, connection):
        print('here', value)
        if value is None:
            return value
        return value.split(self.separator)

    def to_python(self, value):
        if value is None:
            return None
        elif isinstance(value, list):
            return value
        else:
            return value.split(self.separator)

    def get_prep_value(self, value):
        if value is None:
            return None
        else:
            return self.separator.join(value)

【问题讨论】:

    标签: python django django-forms django-admin


    【解决方案1】:

    有两种选择。

    1. 根据this answer 创建自定义模型表单,并将字段的initial 设置为数据库中的值(例如alpha,beta)而不是Python 表示形式(例如['alpha', 'beta'])。

    2. 检查to_python 值字符串是否已经是列表文字的表示。如果是,那么直接使用它,而不是再次拆分。

    class CommaSepField(models.CharField):
        description = "A comma-separated list of strings"
    
        def __init__(self, separator=",", *args, **kwargs):
            self.separator = separator
            super().__init__(*args, **kwargs)
    
        def deconstruct(self):
            name, path, args, kwargs = super().deconstruct()
            # Only include kwarg if it's not the default
            if self.separator != ",":
                kwargs['separator'] = self.separator
            return name, path, args, kwargs
    
        def from_db_value(self, value, expression, connection):
            return self.to_python(value)
    
        def to_python(self, value):
            if value is None:
                return None
            elif isinstance(value, list):
                return value
            else:
                literal = _eval_from_string_if_literal_type(value, list)
                value = self.get_prep_value(literal) if literal is not None else value
                return value.split(self.separator)
    
        def get_prep_value(self, value):
            if value is None:
                return None
            else:
                return self.separator.join(value)
    
    
    def _eval_from_string_if_literal_type(string, literal_type):
        """Try to get a literal value from a string
    
        This is useful for the Django admin form, where you would receive as input the string
        representation of a literal, such as a dict or list.
        """
        if isinstance(string, str):
            try:
                result = ast.literal_eval(string)
                if isinstance(result, literal_type):
                    return result
            except (ValueError, SyntaxError):
                pass
    
        return None
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-11-22
      • 1970-01-01
      • 1970-01-01
      • 2018-05-07
      • 2013-10-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多