【问题标题】:Resolve circular import issue解决循环导入问题
【发布时间】:2019-05-10 22:01:39
【问题描述】:

我正在创建一个使用 Flask 和 MongoEngine 连接到 MongoDB 的应用程序。 我的文件夹结构如下所示:

app/
    __init__.py
    mod_users/
        __init__.py
        constants.py
        forms.py
        models.py 
        views.py
    mod_games/
        __init__.py
        constants.py
        forms.py
        models.py 
        views.py

假设我的用户和游戏模型如下所示:

mod_users/models.py

class User(db.Document):
    email = db.EmailField()
    username = db.StringField()
    password = db.StringField()

mod_games/models.py

from app.mod_users.models import User

class Game(db.Document):
    title = db.StringField()
    creator = db.ReferenceField(User, reverse_delete_rule=db.CASCADE)
    likes_count = db.IntField()

现在,我的问题是我希望用户拥有他喜欢的游戏的列表。但是我不能使用引用字段,因为我必须导入 Game,这会创建循环导入。

这行不通:

from app.mod_games.models import Game

class User(db.Document):
    email = db.EmailField()
    username = db.StringField()
    password = db.StringField()
    liked_games = db.ListField(
        db.ReferenceField(Game, reverse_delete_rule=db.PULL)
    )

我想过在每个游戏中存储一个喜欢它的用户列表,然后在 Game 中添加一个静态方法来检索 给定用户的喜欢游戏列表,但这似乎不是解决此问题的干净有效的方法。

【问题讨论】:

    标签: python mongodb flask mongoengine


    【解决方案1】:

    虽然您有答案 - MongoEngine 确实可以满足这一点,因为您可以将类的字符串名称传递给参考字段,例如:

    class User(db.Document):
        email = db.EmailField()
        username = db.StringField()
        password = db.StringField()
        liked_games = db.ListField(
            db.ReferenceField('Game', reverse_delete_rule=db.PULL)
        )
    

    【讨论】:

    • 它需要在某个地方导入是的 - 但不一定在 models.py 中。但是,如果您让所有 ReferenceFields 都使用模型名称作为字符串,那么您将不会有任何循环引用...
    • 但是我可以在哪里导入我的所有模型以便 mod_x/models.py 可以访问它?
    • 这取决于你如何组织你的应用程序 - 你可以使用 app/__init__.py 或任何你设置 mongodb 连接的地方。
    • @Ross 您能否提供完整的示例来展示模块是如何组织的以及如何完成导入?
    【解决方案2】:

    要通过关联类建模的 M:N 关系

    游戏和用户之间存在关系,其中一个游戏可以被任意数量的用户点赞,而一个用户可以喜欢任意数量的游戏。

    这是典型的M:N关系,需要通过关联类来建模(以类建模规则为准)。

    类应该有:

    • 对用户的引用
    • 游戏参考
    • 此特定关系的任何附加属性,例如用户给这款游戏打了多少颗星。

    元组 User - Game 必须是唯一的。

    在定义这种类型的类时,您从 User 和 Game 模块导入。

    用户和游戏不得导入此关联类(否则会再次陷入循环引用问题)

    【讨论】:

      【解决方案3】:

      就像mentioned before 一样,您可以将模型的字符串名称传递给参考字段。这是您应该避免循环导入的第一件事:

      class User(db.Document):
          company = db.ReferenceField('Company')
      

      但是,当您有一个使用某种模型的方法时,比如说,聚合一些数据,上面的这种方式没有帮助 - 您仍然可能会遇到循环导入问题。要解决此问题,请尝试 get_document 函数。请参见下面的示例。

      from mongoengine.base.common import get_document as get_model
      
      class User(db.Document):
          # fields definition omitted
      
          def get_games(self):
              Game = get_model('Game')
              games = Game.objects.filter(user=self.pk)
              # some code here
      

      【讨论】:

        猜你喜欢
        • 2014-12-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-03-12
        • 1970-01-01
        • 2020-11-01
        • 2020-05-18
        相关资源
        最近更新 更多