【问题标题】:Update many-to-many relationships using Flask, SQLAlchemy and WTForms?使用 Flask、SQLAlchemy 和 WTForms 更新多对多关系?
【发布时间】:2014-09-26 21:31:40
【问题描述】:

我想使用代表这些模型的 Flask、SQLAlchemy 和 WTForms 为多对多关系创建一个表单:

personaddress = db.Table('personaddress',
    db.Column('person', db.Integer, db.ForeignKey('person.id')),
    db.Column('address', db.Integer, db.ForeignKey('address.id'))
)

class Person(db.Model):
    __tablename__ = "person"
    id = db.Column(Integer, primary_key=True)
    name = db.Column(String, nullable=False)
    addresses = db.relationship('Address', secondary=personaddress, backref=db.backref('person', lazy='dynamic'))

class Address(db.Model):
    __tablename__ = "address"
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String, nullable=False)

要求

现在我想创建一个包含表单的单个页面,以实现以下目标:

  • 添加/编辑/删除人员
  • 添加/编辑/删除地址
  • 添加/编辑/删除人员与地址之间的关系

重要要求:使用 QuerySelectField,我可以选择一个人的现有地址。但我想以相同的形式添加新地址。

我已经使用model_form 对主要模型和子表单使用FormField 作为连接表,但我只是不知道如何更新包括外键关系在内的所有内容。该页面应该为所有显示的表单和子表单提供一个提交按钮。

问题

  1. 上述要求通常如何在 Flask 中实现?
  2. Django 可以通过其管理界面更轻松地处理这种多对多场景吗?

【问题讨论】:

  • 按照 Flask-SQLAlchemy 示例了解如何建立正确的多对多关系 (pythonhosted.org/Flask-SQLAlchemy/…),因为目前您还没有定义任何关系。然后使用 wtforms/flask-wtf 创建一个从 query_factory 馈送的 QuerySelectField 以将您想要的对象 (stackoverflow.com/questions/17887519/…) 从您的对象中拉到您的表单中。
  • 我添加了关系,但是单独使用 QuerySelectField 并不能满足要求。
  • 您可以尝试使用 PonyORM 而不是 sqlalchemy 来执行此操作。这是他们的编辑器,因此您可以获得所需的所有正确输出PonyOrm
  • @boadescriptor,你能分享你使用的代码吗?

标签: python flask sqlalchemy flask-wtforms


【解决方案1】:

我之前也遇到过类似的事情。我尝试使用model_form来解决它,但它并没有完全解决动态添加新条目的问题,并且在处理关系时我很难使用它。

在 WTForms 中使用 QuerySelectField 只会帮助您填充例如。一个带有 id 的

通过使用某种多选功能,可以在前端添加dynamically add 新选项,您可以以相同的形式发送其他地址。如果数据库中不存在新地址,端点将负责创建它们。

WTForm 表单将是:

from app import db

class PersonAddressForm(Form):
    id = HiddenField('id')
    name = StringField('Name')
    addresses = QuerySelectField('Addresses', 
            query_factory=lambda: db.session.query(Address), 
            get_pk=lambda a: a.id, get_label=lambda a: a.name)

    # Custom validate
    def validate(self):
        # ... custom validation
        return True

路线类似于:

# ... this will be used to create and update a user
@route('create/<userid>', methods=["GET"])
def get_user_form(userid):
    # ... Get the Person
    user = Person()
    if userid:
        # ... if userid supplied, use existing Person object
        user = Person.query.get(userid)

    # ... Populate the form
    person_form = PersonAddressForm(obj=user)

    # ... return form
    return render_template('somepage.html', form=person_form)

@route('create/<userid>', methods=["POST"])
def post_person_form(userid):
    person_form = PersonAddressForm(request.form)

    if person_form.validate():
        # ... Get db object
        person = db.session.query(Person).get(form.id)

        # ... Add changes to the object from the form
        person_form.populate_obj(obj=person_address)

        # ... Get addresses
        addresses = form.addresses.raw_data

        # ... loop over and add to person
        for address in addresses:
            # Add or create an address
            actual_address = db.session.query(Address).get(address.id)

            # ... check if address is existing
            if not actual_address:
                # ... if address not existing, create new one
                actual_address = Address(address.name)
                db.session.add(actual_address)

            # ... Append new or created address to person
            person.addresses.append(actual_address)

        # ... save changes to the db
        db.session.commit()

        # ... Update/Create complete
        return redirect(url_for('get_users'))

    else:
        # ... form not valid, notify user
        # ...

这将处理编辑/创建用户和创建地址。以及创建之间的关系。要使其也支持删除地址,请更改

person.addresses.append(actual_address)

person.addresses = list_of_actual_addresses

并在人员模型中进行更改 (cascade='delete-orphan')

addresses = db.relationship('Address', secondary=personaddress, cascade='delete-orphan' backref=db.backref('person', lazy='dynamic'))

这将使表单每次更新整个地址关系,级联将删除孤立地址。因此,每次提交表单时都会更新一个人的整个地址列表。

在模板中处理 WTForms 时,如果您还没有使用宏,我强烈建议您使用。您必须在某种程度上重写它,但请检查this

希望对你有帮助

【讨论】:

  • 你传入的person_address是什么populate_obj
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-10
  • 2016-12-03
  • 2020-06-10
  • 2012-04-10
  • 1970-01-01
  • 2018-07-13
相关资源
最近更新 更多