简体   繁体   English

Flask SQLAlchemy:多对多关系错误

[英]Flask SQLAlchemy: many to many relationship error

I am trying to set up many-to-many relationship in SQLAlchemy but I am getting the error:我正在尝试在 SQLAlchemy 中建立多对多关系,但出现错误:

from shopapp import db
db.create_all()

sqlalchemy.exc.NoReferencedTableError: Foreign key associated with column 'shoppinglists_products.shoppinglist_id_v2' could not find table 'shoppinglist' with which to generate a foreign key to target column 'id'

My code:我的代码:

from sqlalchemy import ForeignKey
from shopapp import db


shoppinglists_products = db.Table("shoppinglists_products",
                                  db.Column("shoppinglist_id", db.Integer, ForeignKey("shoppinglist.id")),
                                  db.Column("product_id", db.Integer, ForeignKey("product.id")))

class ShoppingList(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(20), unique=True, nullable=False)
    products = db.relationship('Product', back_populates="shoppinglists", secondary="shoppinglists_products")


class Product(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(20), unique=True, nullable=False)

Where is the problem?问题出在哪里?

It seems like Flask-SQLAlchemy has problem finding the table for foreign key reference .似乎 Flask-SQLAlchemy 在查找外键引用表时遇到问题。 Based on your code, here are the two ways you can fix this:根据您的代码,您可以通过以下两种方法解决此问题:

1) Fix shoppinglists_products table: 1) 修复shoppinglists_products表:

Flask-SQLAlchemy often converts the CamelCased model names into a syntax similar to this: camel_cased . Flask-SQLAlchemy 经常将CamelCased模型名称转换成类似于这样的语法: camel_cased In your case, ShoppingList will be referred to as shopping_list .在您的情况下, ShoppingList将被称为shopping_list Therefore, changing the ForeignKey("shoppinglist.id") to ForeignKey("shopping_list.id") will do the trick.因此,将ForeignKey("shoppinglist.id")更改为ForeignKey("shopping_list.id")就可以了。

shoppinglists_products = db.Table("shoppinglists_products",
             db.Column("shoppinglist_id", db.Integer, ForeignKey("shopping_list.id")), # <-- fixed
                                  

2) Change the model names: 2)更改模型名称:

If you'd like, you could go ahead and change the model name from ShoppingList to Shopping and later refer to this as shopping .如果您愿意,您可以继续将模型名称从ShoppingList更改为Shopping ,稍后将其称为shopping This would prevent any confusion from rendering further.这将防止任何混淆进一步渲染。 Usually, developers don't quite often go for a class name which is combined of two words, especially for the ORM cases.通常,开发人员不会经常使用由两个单词组合而成的类名,尤其是对于 ORM 案例。 This is because various frameworks has different ways of interpreting the class names to create tables.这是因为各种框架有不同的方式来解释类名来创建表。

Expanding on @P0intMaN's answer - explicitly providing the SQL Alchemy table name with __tablename__ = "ShoppingList" (for example) lets you use your preferred case style and prevents SQLAlchemy from 'helping' you by changing the name of something kind of important without telling you.扩展@P0intMaN 的答案 - 显式提供带有 __tablename__ = "ShoppingList" 的 SQL Alchemy 表名(例如)让您可以使用您喜欢的案例样式,并防止 SQLAlchemy 通过更改某种重要的名称而不告诉您来“帮助”您.

class ShoppingList(db.Model):
    __tablename__ = "ShoppingList"
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(20), unique=True, nullable=False)
    products = db.relationship('Product', back_populates="shoppinglists", secondary="shoppinglists_products")

In many/most Flask tutorials and books, simplistic table names (eg posts, comments, users) are used, which elide this issue.在许多/大多数 Flask 教程和书籍中,使用了简单的表名(例如帖子、评论、用户),从而避免了这个问题。 Thus a trap awaits for those of us who insist on meaningful CamelCased class names.因此,对于我们这些坚持有意义的 CamelCased 类名的人来说,一个陷阱等待着我们。 This is mentioned somewhat casually in the documentation here: https://flask-sqlalchemy.palletsprojects.com/en/2.x/models/此处的文档中有些随意地提到了这一点: https ://flask-sqlalchemy.palletsprojects.com/en/2.x/models/

Some parts that are required in SQLAlchemy are optional in Flask-SQLAlchemy. SQLAlchemy 中需要的一些部分在 Flask-SQLAlchemy 中是可选的。 For instance the table name is automatically set for you unless overridden.例如,除非被覆盖,否则会自动为您设置表名。 It's derived from the class name converted to lowercase and with “CamelCase” converted to “camel_case”.它派生自转换为小写的类名,并将“CamelCase”转换为“camel_case”。 To override the table name, set the tablename class attribute.要覆盖表名,请设置tablename类属性。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM