在管理中显示之前对数据库中的值进行预处理

发布于 2025-01-07 19:46:54 字数 823 浏览 1 评论 0 原文

我的问题很简单,但我无法解决我的问题:每次在管理中显示该字段时,我都需要处理一个字段,因为它必须以不同的方式保存在数据库中。

例如,我需要用户在管理中输入百分比(例如 50、70 或 100),但这些值将以 0.5、0.7 或 1 的形式保存在数据库中。之后,当用户想要编辑或只是查看时对于这些值,即使它们在数据库中保存为浮点数,也不必对其进行预处理以再次将其显示为百分比(整数)。

我想:

def valid_percentage(value):
    if not 0 <= value <= 1:
        raise ValidationError(u'Must be a value between 0 and 100')

class PercentageField(models.IntegerField):    
    def __init__(self, *args, **kwargs):
        kwargs['validators'] = kwargs.get('validators', []) + [valid_percentage]
        super(PercentageField, self).__init__(*args, **kwargs)

    def to_python(self, value):
        return None if value is None else int(100 * value)

    def get_prep_value(self, value):
        return None if value is None else value/100.0

会做的。但这在保存和显示数据时都是错误的。

My question is very simple, but I can't manage to solve my problem: I need to process a Field every time that this is showed in the admin, because it has to be saved differently in the DB.

For example, I need the user to input percentages in the admin, (say 50, 70 or 100), but those values will be saved in the database as 0.5, 0.7 or 1. After, when the user wants to edit or just see those values, they mus't be preprocessed to show them as percetages (integer numbers) again, even though they were saved as floats in the DB.

I thought something like:

def valid_percentage(value):
    if not 0 <= value <= 1:
        raise ValidationError(u'Must be a value between 0 and 100')

class PercentageField(models.IntegerField):    
    def __init__(self, *args, **kwargs):
        kwargs['validators'] = kwargs.get('validators', []) + [valid_percentage]
        super(PercentageField, self).__init__(*args, **kwargs)

    def to_python(self, value):
        return None if value is None else int(100 * value)

    def get_prep_value(self, value):
        return None if value is None else value/100.0

will do it. But this is saving and showing data all wrong.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

梦幻之岛 2025-01-14 19:46:54

我花了很长时间,得到了一个适用于保存的代码版本,另一个适用于显示的版本。所以这很有趣,但并不是很有用。

实现您想要的正确方法是:

  1. 在模型类定义中使用简单的 DecimalField 或 FloatField

  2. 创建一个 ModelForm 为您的模型

  3. 定义 clean_yourpercentagefield() 在 ModelForm 中将输入值除以 100

  4. 创建并使用自定义小部件类在渲染之前将值乘以 100

django 自定义字段和 modelform 文档

您必须确保用于表示自定义字段的表单字段执行将用户提供的表单输入转换为与 to_python() 兼容的模型字段值所需的任何输入验证和数据清理。这可能需要编写自定义表单字段,和/或在字段上实现 formfield() 方法以返回其 to_python() 返回正确数据类型的表单字段类。

事实上,您还可以采取以下步骤:

  1. 创建一个 PercentageField 类覆盖 formfield()

  2. < p>创建 PercentageFormField ,应由 PercentageField.formfield() 调用

  3. 创建 PercentageFormField 默认使用的 PercentageWidget

如果您打算这样做,您将遇到的错误您建议的方式(这是错误的)是 to_python() 被一遍又一遍地调用几次,基本上使用以下代码:

def to_python(self, value):
    print 'to python', value
    value = None if value is None else int(100 * value)consider this section of the documentation
    print 'converted to python', value
    return value

从模型表单中保存模型将输出类似以下内容:

to python 32.0
converted to python 3200
clean 3200
to python 3200
converted to python 320000

必须使用SubFieldMetaclass如果你坚持要以错误的方式去做。

结论: KISS FTW

感谢 SmileyChris 帮助回答了这个问题,这可能并不完美,但我认为不分享我发现的东西就太糟糕了。

I took it pretty far, got one version of your code that works for saving, another that works for display. So that's quite some fun but not really useful.

A correct to achieve what you want is:

  1. Use a simple DecimalField or FloatField in your Model class definition,

  2. Create a ModelForm for your Model

  3. Define clean_yourpercentagefield() in your ModelForm to divide input value by 100

  4. Make and use a custom widget class to multiply the value by 100 before rendering

As stated by django custom fields and modelform documentation:

you must ensure that the form field used to represent your custom field performs whatever input validation and data cleaning is necessary to convert user-provided form input into a to_python()-compatible model field value. This may require writing a custom form field, and/or implementing the formfield() method on your field to return a form field class whose to_python() returns the correct datatype.

Indeed, you can also take these steps:

  1. Create a PercentageField class overriding formfield()

  2. Create PercentageFormField which should be called by PercentageField.formfield()

  3. Create PercentageWidget which PercentageFormField will use by default

The error you will run into if you intent to do it the way you suggested, which is wrong, is that to_python() is called several times over and over again, basically with this code:

def to_python(self, value):
    print 'to python', value
    value = None if value is None else int(100 * value)consider this section of the documentation
    print 'converted to python', value
    return value

Saving the model from a modelform will output something like:

to python 32.0
converted to python 3200
clean 3200
to python 3200
converted to python 320000

You'd have to use SubFieldMetaclass if you insist in wanting to do it the wrong way.

Conclusion: KISS FTW !

Credits to SmileyChris for helping in this answer, which might not be perfect but i thought it would be too bad to not share what i've found.

在风中等你 2025-01-14 19:46:54

Try get_db_prep_value and then look into DB to see on which step does it fail.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文