python - Flask WTForms - 基于多个表单字段的自定义验证器

标签 python forms flask sqlalchemy wtforms

我有一个书籍表,其中有可用书籍的数量,我有一个借书表,我可以在其中输入借书和数量。

我正在尝试为我的表单创建自定义验证器函数,如果为借书输入的数量高于图书表中的可用数量,它将在表单中显示错误消息。

这是模型:

class Borrow(db.Model):
    """
    Create a Books table
    """

    __tablename__ = 'borrows'

    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(60), index=True)
    quantity_borrow = db.Column(db.Integer)
    date_borrow = db.Column(db.DATE)
    employees_id = db.Column(db.Integer, db.ForeignKey('employees.id'))
    book_id = db.Column(db.Integer, db.ForeignKey('books.id'))

    def __repr__(self):
        return '<Borrow: {}>'.format(self.name)


class Book(db.Model):
    """
    Create a Books table
    """

    __tablename__ = 'books'

    id = db.Column(db.Integer, primary_key=True)
    book_name = db.Column(db.String(60), index=True,unique=True)
    author = db.Column(db.String(200), index=True)
    quantity = db.Column(db.Integer)
    department_id = db.Column(db.Integer, db.ForeignKey('departments.id'))
    employees_id = db.Column(db.Integer, db.ForeignKey('employees.id'))
    publisher = db.Column(db.String(200))
    no_of_pgs = db.Column(db.Integer)
    pbs_year = db.Column(db.Integer)
    genre_id = db.Column(db.Integer, db.ForeignKey('genres.id'), nullable=False)
    read = db.Column(db.Enum('NO', 'YES'), default='NO')

    borrows = db.relationship('Borrow', backref='book',
                                lazy='dynamic')

这是 View :

    @admin_role.route('/books/add', methods=['GET', 'POST'])
    @login_required
    def add_book():
        """
        Add a book to the database
        """
        check_admin_role()

        add_book = True

        form = BookForm()
        if form.validate_on_submit():
            book = Book(book_name=form.book_name.data,
                        author=form.author.data,
                        quantity=form.quantity.data,
                        department_id=form.department_name.data,
                        employees_id=current_user.id,
                        publisher=form.publisher.data,
                        no_of_pgs=form.no_of_pgs.data,
                        pbs_year=form.pbs_year.data,
                        genre_id=form.genre_name.data,
                        read=form.read.data)
            try:
                # add department to the database
                db.session.add(book)
                db.session.commit()
                flash('You have successfully added a new department.')
            except:
                # in case department name already exists
                flash('Error: Book name already exists.')

            # redirect to departments page
            return redirect(url_for('admin_role.list_books'))

        # load department template
        return render_template('books/book.html', action="Add",
                               add_book=add_book, form=form,
                               title="Add Book", page="books")


    @admin_role.route('/borrows/add', methods=['GET', 'POST'])
    @login_required
    def add_borrow():
        """
        Add a borrow to the database
        """
        check_admin_role()

        add_borrow = True

        form = BorrowForm()

        if form.validate_on_submit():
            borrow = Borrow(name=form.name.data,
                        book_id=form.book_name.data,
                        quantity_borrow=form.quantity_borrow.data,
                        date_borrow=form.date_borrow.data)

            # add department to the database
            db.session.add(borrow)
            db.session.commit()
            flash('You have successfully added a new borrow.')


            # redirect to borrows page
            return redirect(url_for('admin_role.list_borrows'))

        # load department template
        return render_template('borrows/borrow.html', action="Add",
                               add_borrow=add_borrow, form=form,
                               title="Add Borrow", page="borrows")

这是表格

class BookForm(FlaskForm):
    """
    Form for admin_role to add or edit a books
    """
    book_name = StringField('Book Name', validators=[DataRequired()])
    author = StringField('Author', validators=[DataRequired()])
    genre_name = SelectField(coerce=int, validators=[DataRequired()])
    quantity = IntegerField('Quantity', validators=[DataRequired()])
    department_name = SelectField(coerce=int, validators=[DataRequired()])
    publisher = StringField('Publisher', validators=[DataRequired()])
    no_of_pgs = IntegerField('Number of pages', validators=[DataRequired()])
    pbs_year = IntegerField('Publishing Year', validators=[DataRequired()])
    read = SelectField("Read", choices=[(e, e) for e in Book.read.property.columns[0].type.enums])
    submit = SubmitField('Submit')

    def __init__(self):
        super(BookForm, self).__init__()
        self.department_name.choices = [(c.id, c.name) for c in Department.query.all()]
        self.genre_name.choices = [(g.id, g.name) for g in Genre.query.all()]


class BorrowForm(FlaskForm):
    """
    Form for admin_role to add or edit a books
    """
    name = StringField('Borrower Name', validators=[DataRequired()])
    book_name = SelectField(coerce=int, validators=[DataRequired()])
    quantity_borrow = IntegerField('Quantity Borrow', validators=[DataRequired())
    date_borrow = DateField('Borrow Date', validators=[DataRequired()])

    submit = SubmitField('Submit')

    def __init__(self):
        super(BorrowForm, self).__init__()
        self.book_name.choices = [(c.id, c.book_name) for c in Book.query.all()]

最佳答案

在 wtforms 中,您可以通过在该表单类下编写一个方法来验证字段。

在该方法中,validate_前缀调用以其命名的字段。 self 参数将是 BorrowForm 类本身,field 参数将是您使用 validate_ 调用的字段/p>

class BorrowForm(FlaskForm):
    ...

    def validate_quantity_borrow(self, field):
        if field.data > (Book.query.filter_by(id=self.book_name.data).first().quantity - sum(i.quantity_borrow for i in Borrow.query.filter_by(book_id=self.book_name.data).all()):
            raise ValidationError("More than we have")

field 这里是 BorrowFormquantity_borrow 属性。提交后,您需要获取其数据,以便 field.data 为您提供输入的数量。之后,您将通过使用 book_id 作为 self.book_name.data 过滤数据库来选择这本书,这将为您提供 self 作为 BorrowForm 类本身和它的 book_name 属性,然后是该属性的 data,即所选书籍的 ID。

你需要导入你的数据库模型,比如在你的 forms.py 文件中,你还需要导入 ValidationError:

from wtforms.validators import ValidationError

关于python - Flask WTForms - 基于多个表单字段的自定义验证器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61954008/

相关文章:

Python,类型错误 : unhashable type: 'list'

python - 如何使用在线编译器(如ideone、codepad 和compileonline)输入多个输入数据?

python - Scrapy Middleware 忽略 URL 并防止抓取

php - symfony 表单元素选项

python - 在另一个函数中跟踪一个函数的进度

python - Django 总是在管理索引页面中将模型的详细名称大写

javascript - 当用户完成输入或使用 jQuery 离开文本字段时,如何从文本字段中获取值?

javascript - 在提交事件中更新值后未提交隐藏输入

python - Flask 断线子进程 stdout python3

python - 如何正确使用 SQL LIKE 语句从 Flask 应用程序查询数据库