Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/342.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python Django模型字段的最大值和最小值,取决于已经引入的值_Python_Django_Django Models - Fatal编程技术网

Python Django模型字段的最大值和最小值,取决于已经引入的值

Python Django模型字段的最大值和最小值,取决于已经引入的值,python,django,django-models,Python,Django,Django Models,我想在Django中创建一个模型,在这个模型中,我可以为给定的字段引入整数值,限制取决于已经为该字段引入的值。具体来说,我希望引入的值在范围内(最小值=1 |最大值=该字段的最大值+1) 代码应该与models.py文件中的类似: from django.db import models from django.core.validators import MaxValueValidator, MinValueValidator class MyModel(models.Model):

我想在Django中创建一个模型,在这个模型中,我可以为给定的字段引入整数值,限制取决于已经为该字段引入的值。具体来说,我希望引入的值在范围内(最小值=1 |最大值=该字段的最大值+1) 代码应该与models.py文件中的类似:

from django.db import models
from django.core.validators import MaxValueValidator, MinValueValidator

class MyModel(models.Model):
    max_myfield = MyModel.objects.filter(myfield=self.myfield).aggregate(Max('myfield'))["myfield_max"]
    myfield = models.IntegerField(validators=[MinValueValidator=1, MaxValueValidator=max_myfield + 1])
问题是max_myfield使用的是MyModel本身,这会引发一个NameError,因为它尚未定义

此外,如果表中没有记录,则最大值也应为1,就像最小值一样

编辑: 我想把问题简化为以下几点:
如果我想定义一个带有字段的模型,那么在Django应用程序的models.py文件中我应该怎么做?验证器在某种程度上取决于模型字段的值。

我刚刚在以下文档中注意到了一些技巧:

类MaxValueValidator(限制值,消息=无)

如果值大于limit_值,则引发代码为“max_value”的ValidationError,limit_值可能是可调用的

您不希望每个记录的最大值都相同,因此可以传入一个查询数据库以查找当前最大值并添加1的方法。为了避免在声明类之前引用该类,您可以将该方法从类中拉出,或者将调用包装在lambda表达式中。我选择把它拔出来

尝试将您的
models.py
更改为如下所示:

from django.core.validators import MinValueValidator, MaxValueValidator
from django.db import models
from django.db.models import Max


def get_max_myfield() -> int:
    max_found = MyModel.objects.aggregate(Max('myfield'))["myfield__max"]
    if max_found is None:
        return 1
    return max_found + 1


class MyModel(models.Model):
    myfield = models.IntegerField(validators=[
        MinValueValidator(1),
        MaxValueValidator(get_max_myfield)])
下面是一个示例中的相同模型代码,它允许您在一个文件中运行完整的Django应用程序并对其进行实验。前三次调用
clean_fields()
正确验证,第四次调用抱怨
myfield
太大

# Tested with Django 3.1 and Python 3.8.
import logging
import sys

import django
from django.apps import apps
from django.apps.config import AppConfig
from django.conf import settings
from django.core.exceptions import ValidationError
from django.db import connections, models, DEFAULT_DB_ALIAS
from django.db.models import Max
from django.db.models.base import ModelBase
from django.core.validators import MaxValueValidator, MinValueValidator

NAME = 'udjango'
DB_FILE = NAME + '.db'


def main():
    setup()
    logger = logging.getLogger(__name__)

    def get_max_myfield() -> int:
        max_found = MyModel.objects.aggregate(Max('myfield'))["myfield__max"]
        if max_found is None:
            return 1
        return max_found + 1

    class MyModel(models.Model):
        myfield = models.IntegerField(validators=[
            MinValueValidator(1),
            MaxValueValidator(get_max_myfield)])

    syncdb(MyModel)
    
    m1 = MyModel(myfield=1)
    m1.clean_fields()
    m1.save()

    m2a = MyModel(myfield=2)
    m2a.clean_fields()
    m2a.save()

    m2b = MyModel(myfield=2)
    m2b.clean_fields()
    m2b.save()

    m101 = MyModel(myfield=101)
    try:
        m101.clean_fields()
        assert False, "Should have raised ValidationError."
    except ValidationError:
        logger.info("Raised validation error, as expected.")

    logger.info('Max allowed is %d.', get_max_myfield())


def setup():
    with open(DB_FILE, 'w'):
        pass  # wipe the database
    settings.configure(
        DEBUG=True,
        DATABASES={
            DEFAULT_DB_ALIAS: {
                'ENGINE': 'django.db.backends.sqlite3',
                'NAME': DB_FILE}},
        LOGGING={'version': 1,
                 'disable_existing_loggers': False,
                 'formatters': {
                    'debug': {
                        'format': '%(asctime)s[%(levelname)s]'
                                  '%(name)s.%(funcName)s(): %(message)s',
                        'datefmt': '%Y-%m-%d %H:%M:%S'}},
                 'handlers': {
                    'console': {
                        'level': 'DEBUG',
                        'class': 'logging.StreamHandler',
                        'formatter': 'debug'}},
                 'root': {
                    'handlers': ['console'],
                    'level': 'INFO'},
                 'loggers': {
                    "django.db": {"level": "DEBUG"}}})
    app_config = AppConfig(NAME, sys.modules['__main__'])
    apps.populate([app_config])
    django.setup()
    original_new_func = ModelBase.__new__

    @staticmethod
    def patched_new(cls, name, bases, attrs):
        if 'Meta' not in attrs:
            class Meta:
                app_label = NAME
            attrs['Meta'] = Meta
        return original_new_func(cls, name, bases, attrs)
    ModelBase.__new__ = patched_new


def syncdb(model):
    """ Standard syncdb expects models to be in reliable locations.

    Based on https://github.com/django/django/blob/1.9.3
    /django/core/management/commands/migrate.py#L285
    """
    connection = connections[DEFAULT_DB_ALIAS]
    with connection.schema_editor() as editor:
        editor.create_model(model)


main()

谢谢你的回答。我想我理解这个解决方案(我是django的初学者)。我现在的问题是:在常规应用程序中,函数和类应该拉到哪里?在我的例子中,我认为它们都应该放在“models.py”文件中,但是在那种情况下。。。由于函数正在调用MyModel,但尚未定义,它是否会出现错误?此外,如果a将函数和类放入“models.py”文件中,则会出现错误:TypeError:Field“myfield”需要一个数字,但即使在
get\u max\u myfield()之后定义了
MyModel
类,也会出现错误
函数已定义,在调用函数之前定义类。至少在这个单文件版本中,这可以让事情顺利进行。我不知道你为什么会得到
TypeError
,@Lokicor。我建议使用新的模型文件和
TypeError
的stack trace.BTW、@Lokicor为您的问题添加一个更新,如果您将代码从我的脚本直接复制到您的脚本中创建前三条记录,是否会引发错误?如果调用模型的方式与我不同,则可能会出现不相关的错误。我在我的答案中添加了一个单独的
models.py
文件@Lokicor。试着在你的项目中使用它。您从我的脚本中描述的输出是我期望它产生的结果,因此请查看我的脚本和您的代码之间的差异。尝试更改我的代码,使其看起来更像您的代码,然后查看输出是如何更改的。祝你好运