【问题标题】:Inserting new records with one-to-many relationship in sqlalchemy在sqlalchemy中插入具有一对多关系的新记录
【发布时间】:2013-05-02 06:00:32
【问题描述】:

我正在关注 declaring models 上关于一对多关系的 flask-sqlalchemy 教程。示例代码如下:

class Person(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(50))
    addresses = db.relationship('Address', backref='person',
                                lazy='dynamic')

class Address(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    email = db.Column(db.String(50))
    person_id = db.Column(db.Integer, db.ForeignKey('person.id'))

现在我想知道如何使用这种模型将新记录插入数据库。我假设我需要一个构造函数 init,但我很难理解它应该如何实现和使用。我这里的主要问题是 Person 依赖于 Address 并且 Address 对 Person 有 ForeignKey,所以它应该提前知道 Person。

请帮助我了解它应该如何执行。

提前谢谢你。

【问题讨论】:

    标签: python sqlalchemy foreign-keys relationship flask-sqlalchemy


    【解决方案1】:

    您不需要编写构造函数,您可以将Person 实例上的addresses 属性视为一个列表:

    a = Address(email='foo@bar.com')
    p = Person(name='foo')
    p.addresses.append(a)
    

    或者您可以将地址列表传递给Person 构造函数

    a = Address(email='foo@bar.com')
    p = Person(name='foo', addresses=[a])
    

    在任何一种情况下,您都可以像这样访问Person 实例上的地址:

    db.session.add(p)
    db.session.add(a)
    db.session.commit()
    print(p.addresses.count()) # 1
    print(p.addresses[0]) # <Address object at 0x10c098ed0>
    print(p.addresses.filter_by(email='foo@bar.com').count()) # 1
    

    【讨论】:

    • 太棒了!现在,如果数据库中已经存在一个人,并且我们已经为他们添加了一个新地址 (p.addresses.append(a)),那么我们是否需要在 db.session.commit 之前添加db.session.add 人、地址、两者,或者两者都不是叮?
    • 您必须从数据库中查询现有数据,例如p = db.session.query(Person).filter(Person.name == 'Name of existing Person').first(),然后执行相同的p.addresses.append(a)。您不必将它添加到会话中,因为它直接来自会话。但在所有更改完成后我仍然会db.session.commit()
    • 这会创建一个新的Address 记录。如果我想用email='foo@bar.com' 分配Address 记录的id(主键)怎么办。我想将已经创建的地址分配给人员,但我不想先查询地址。
    【解决方案2】:

    研究这个模型时最重要的是要理解这个模型具有一对多关系的事实,即一个人有多个地址,在我们的例子中,我们会将这些地址存储在一个列表中。

    因此,带有 init 的 Person 类将如下所示。

    class Person(db.Model):
        id = db.Column(db.Integer, primary_key=True)
        name = db.Column(db.String(50))
        addresses = db.relationship('Address', backref='person',
                                lazy='dynamic')
    
        def __init__(self,id,name,addresses = tuple()):
            self.id = id
            self.name = name
            self.addresses = addresses
    

    所以这个 Person 类将需要一个 id、一个名称和一个包含 Address 类型对象的列表。我将默认值保留为空列表。

    希望对您有所帮助。 :)

    【讨论】:

    • 可变的默认参数是common gotcha,您可能需要更改示例以反映这一点:)
    • @DazWorrall 我编辑了答案以改变它。
    【解决方案3】:

    我在这里和其他地方收集了信息,并找到了 3 种方法。在此模型示例中(与问题相同):

    class Person(db.Model):
        id = db.Column(db.Integer, primary_key=True)
        name = db.Column(db.String(50))
        addresses = db.relationship('Address', backref='person',
                                    lazy='dynamic')
    
    class Address(db.Model):
        id = db.Column(db.Integer, primary_key=True)
        email = db.Column(db.String(50))
        person_id = db.Column(db.Integer, db.ForeignKey('person.id'))
    

    1.

    a = Address(email='foo@bar.com')
    p = Person(name='foo', addresses=[a])
    

    2.

    p = Person(name='foo')
    a = Address(email='foo@bar.com', person_id=p.id)
    

    3.

    a = Address(email='foo@bar.com')
    p = Person(name='foo')
    p.addresses.append(a)
    

    【讨论】:

      【解决方案4】:

      除了所有之前的答案,与uselist=False 建立一对一关系,例如:

      class Person(db.Model):
          id = db.Column(db.Integer, primary_key=True)
          name = db.Column(db.String(50))
          address = db.relationship('Address', backref='person',
                                      lazy=True, uselist=False)
      
      class Address(db.Model):
          id = db.Column(db.Integer, primary_key=True)
          email = db.Column(db.String(50))
          person_id = db.Column(db.Integer, db.ForeignKey('person.id'))
      

      只有下一种方法有助于插入记录:

      p = Person(name='foo')
      a = Address(email='foo@bar.com', person=p)  # Adding created person directly to Address's backref
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-09-16
        • 1970-01-01
        • 2012-11-23
        • 2013-08-18
        • 1970-01-01
        • 2015-03-29
        • 2021-07-12
        相关资源
        最近更新 更多