【问题标题】:One-to-many relationship with wtforms_alchemy.ModelFieldList does not update children与 wtforms_alchemy.ModelFieldList 的一对多关系不更新子级
【发布时间】:2018-04-25 03:45:55
【问题描述】:

下面是一个填充空父对象并创建其子对象的表单。必须手动调用 ModelFormField,这是一个小麻烦。它工作得很好。但是,当我使用表单进行 update 时,只有对象被更新——子对象是新创建的。

在这个框架中向孩子传播更新的正确方法是什么?实际上,我想使用下面的两个打印语句来打印相同的内容。如果表单数据有孩子的额外(缺失)数据,如果表单会创建(删除)孩子,我将特别感激。

from multidict import MultiDict
from sqlalchemy import Column, ForeignKey, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine

from wtforms_alchemy import ModelFieldList, ModelForm, ModelFormField

Base = declarative_base()

class Child(Base):
  __tablename__ = "child"
  id = Column(Integer, primary_key=True)
  name = Column(String)
  parent_id = Column(Integer, ForeignKey("parent.id"))

class Parent(Base):
  __tablename__ = "parent"
  id = Column(Integer, primary_key=True)
  name = Column(String)
  children = relationship(Child)

class ChildForm(ModelForm):
  class Meta:
    model = Child

class ParentForm(ModelForm):
  class Meta:
    model = Parent
  children = ModelFieldList(ModelFormField(ChildForm))  # annoyed!

engine = create_engine("sqlite://")
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()

# Form data
formdata = MultiDict({"name": "Foo", "children-0-name": "hotdog"})

# Create initial object
question = Parent()
form = ParentForm(formdata, obj=question)
form.populate_obj(question)
if not form.validate():
  raise RuntimeError(form.errors)
session.add(question)
session.commit()

# prints: "(1, 1)"
print((question.id, question.children[0].id))


# Retrieve object and update with same data
question_get = session.query(Parent).get(question.id)
form = ParentForm(formdata, obj=question_get)
form.populate_obj(question_get)
if not form.validate():
  raise RuntimeError(form.errors)
session.add(question_get)
session.commit()

# prints: "(1, 2)", want it to print the same as above
print((question_get.id, question_get.children[0].id))

【问题讨论】:

    标签: sqlalchemy wtforms


    【解决方案1】:

    在深入研究代码时,似乎需要更新对象 ID。因此,必须在更新时使用包含 id 并传递 id 的表单。

    --- orig.py 2018-05-01 20:51:09.000000000 -0700
    +++ fixed.py    2018-05-01 20:56:16.000000000 -0700
    @@ -4,6 +4,7 @@
     from sqlalchemy.orm import relationship
     from sqlalchemy.orm import sessionmaker
     from sqlalchemy import create_engine
    +from wtforms import IntegerField
    
     from wtforms_alchemy import ModelFieldList, ModelForm, ModelFormField
    
    @@ -24,6 +25,7 @@
     class ChildForm(ModelForm):
       class Meta:
         model = Child
    +  id = IntegerField()  # Optional field used in update operations.
    
     class ParentForm(ModelForm):
       class Meta:
    @@ -53,7 +55,11 @@
    
     # Retrieve object and update with same data
     question_get = session.query(Parent).get(question.id)
    -form = ParentForm(formdata, obj=question_get)
    +child_id = question_get.children[0].id
    +formdata_update = MultiDict({"name": "Foo",
    +                             "children-0-id": child_id,
    +                             "children-0-name": "pizza"})
    +form = ParentForm(formdata_update, obj=question_get)
     form.populate_obj(question_get)
     if not form.validate():
       raise RuntimeError(form.errors)
    

    【讨论】:

      【解决方案2】:

      不错的侦查。不过这看起来还是比较麻烦的。您随后是否找到了一种更简单的方法来更新具有一对多关系的表单? WTForms 应该可以节省开发人员的时间。但这似乎比不使用 WTForms 的开销更大。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-23
        • 1970-01-01
        相关资源
        最近更新 更多