Значение поля Web2py зависит от другого поля — (проверка при определении модели)

#python #web2py #data-access-layer

#python #web2py #уровень доступа к данным

Вопрос:

Пожалуйста, рассмотрите следующую таблицу:

 db.define_table('bio_data',
            Field('name', 'string'),
            Field('total_mark', 'integer', requires=IS_EMPTY_OR(IS_INT_IN_RANGE(0, 1e100))),
            Field('marks_obtained', 'integer')
            )
 

Теперь поле ‘marks_obtained’ не может иметь значение больше, чем ‘total_marks’.

Я попробовал следующее

 db.bio_data.marks_obtained.requires = IS_EMPTY_OR(
IS_INT_IN_RANGE(0, db.bio_data.total_mark))
 

Но это не работает. Я получаю следующую ошибку:

 TypeError: int() argument must be a string or a number, not 'Field'
 

Любая помощь приветствуется.

Комментарии:

1. найдите способ получить целочисленное значение Field .

2. Да, это вопрос здесь, как я могу получить значение вместо поля. Я попробовал следующее, но все равно получаю ошибку: Field('marks_obtained', 'integer', requires=lambda row: IS_EMPTY_OR(IS_INT_IN_RANGE(0, db.bio_data(row.id).total_mark))) И прошу вас, пожалуйста, не снижать голос, не понимая всей проблемы или знаний.

3. можете ли вы ввести dir(db.bio_data.total_mark) и посмотреть, что он возвращает? Вы только что пробовали int(db.bio_data.total_mark)

4. int(db.bio_data.total_mark) это дает ту же ошибку, так как этот запрос db.bio_data.total_mark возвращает поле вместо целого числа.

Ответ №1:

У меня была такая же проблема, и я только что нашел для нее элегантное решение. Во-первых, вы должны заметить, что перед любой проверкой значения полей передаются в модель, поэтому в модели вы можете манипулировать ими с помощью request.vars . После этого все остальное просто: просто создайте свой собственный валидатор, извлеките значения полей и используйте их по своему усмотрению. Пример будет лучше:

Предположим, у вас есть таблица с двумя полями:

     dbOBJECT.define_table("example",
                          Field("high_number",
                                "integer",
                                label= T('High number'),
                                requires=[IS_NOT_EMPTY(T(stringBuilder.emptyField))]),
                          Field("other_number",
                                "integer",
                                label= T('Lower number'),
                                requires=IS_NOT_EMPTY(T(stringBuilder.emptyField))))
 

И вам нужно, чтобы второе число было меньше первого. Для объяснения давайте создадим пользовательский валидатор. Это можно сделать тем же db.py файл

     class VALIDATE_NUMBERS(object):
        def __init__(self, error_message="Error, this value can't be greather than the above one"):
            self.error_message = error_message

        def __call__(self, value):
            error = None
            high_number=request.vars['high_number']

            if high_number < value:
                error = self.error_message
            return (value, error)
 

Ну, еще одна вещь, которую нужно сделать, это включить эту проверку в модель:

     dbOBJECT.define_table("example",
                          Field("high_number",
                                "integer",
                                label= T('High number'),
                                requires=[IS_NOT_EMPTY(T(stringBuilder.emptyField))]),
                          Field("other_number",
                                "integer",
                                label= T('Lower number'),
                                requires=IS_NOT_EMPTY [(T(stringBuilder.emptyField)), VALIDATE_NUMBERS()]))
 

Волшебство сделано!!! Наслаждайтесь…

Ответ №2:

Вы можете легко сделать это с помощью onvalidation функции обратного вызова. Прочитайте эту форму и валидаторы — onvalidation

Второе решение — вам нужно объединить «Валидаторы с зависимостями» и IS_EXPR валидатор. Читать:

  1. Валидаторы с зависимостями
  2. IS_EXPR

Добавьте валидатор в контроллер примерно следующим образом, я не тестировал это, но вы получите представление об этом.

 is_total_less = int(request.vars.marks_obtained) < int(request.vars.total_mark)

db.bio_data.marks_obtained.requires = IS_EMPTY_OR(
IS_EXPR('%s' % is_total_less,
        error_message='Marks Obtained should be smaller than Totak Marks'))
 

Убедитесь, что request.vars оно доступно.

Комментарии:

1. Я смог сделать это с помощью onvalidation обратного вызова. Для уровня модели я попробую то же самое и обновлю. Спасибо за обновление.