【问题标题】:Querying on multiple tables using google apps engine (Python)使用谷歌应用程序引擎(Python)查询多个表
【发布时间】:2011-02-28 12:48:42
【问题描述】:

我有三个表,1-Users、2-Softwares、3-UserSoftwares。

如果假设,Users 表有 6 个用户记录(比如 U1、U2、...、U6)和 Softwares 表有 4 个不同的软件(比如 S1、S2、S3、S4),如果用户请求,UserSoftwares 存储引用仅适用于给定的软件。 例如:UserSoftwares(5 条记录)只有两列(userid、softwareid)引用其他列。数据是:

U1 S1

U2 S2

U2 S3

U3 S3

U4 S1

现在我期待以下结果:(如果当前登录用户是 U2):


S1 禁用

S2 启用

S3 启用

S4 禁用

这里,第 1 列是软件 ID 或名称,第 2 列是 status,根据 UserSoftwares 表(模型)只有两个值(启用/禁用)。 注意 status 不是任何模型(表)的字段。 “我的逻辑是: 1. 循环遍历软件模型中的每个软件 2.在UserSoftwares模型中找到当前登录用户ID(U2)的softwareid: 如果找到,则设置 status='Enable' 如果未找到,则设置 status='Disable' 3. 将此状态属性添加到软件对象。 4. 对所有软件重复此过程。 " python 谷歌应用引擎中的查询应该是什么才能达到上述结果?

【问题讨论】:

    标签: python google-app-engine model


    【解决方案1】:

    由于 GAE 的数据存储是关系的,因此您必须在不使用 joins 的情况下为您的 多对多 关系建模。这里有两种方法可以轻松适应您的需求。

    使用链接模型方法的工作示例(更新 #1)

    from google.appengine.ext import db
    
    # Defining models
    
    class User(db.Model):
        name = db.StringProperty()
    
    
    class Software(db.Model):
        name = db.StringProperty()
        description = db.TextProperty()
    
    
    class UserSoftwares(db.Model):
        user = db.ReferenceProperty(User, collection_name='users')
        software = db.ReferenceProperty(Software, collection_name='softwares')
    
    # Creating users
    
    u1 = User(name='John Doe')
    u2 = User(name='Jane Doe')
    
    # Creating softwares    
    sw1 = Software(name='Office 2007')
    sw2 = Software(name='Google Chrome')
    sw3 = Software(name='Notepad ++')
    
    # Batch saving entities
    db.put([u1, u2, sw1, sw2, sw3])
    
    """
    Creating relationship between users and softwares;
    in this example John Doe's softwares are 'Office 2007' and
    'Notepad++' while Jane Doe only uses 'Google Chrome'.
    """
    u1_sw1 = UserSoftwares(user=u1, software=sw1)
    u1_sw3 = UserSoftwares(user=u1, software=sw3)
    u2_sw2 = UserSoftwares(user=u2, software=sw2)
    
    # Batch saving relationships
    db.put([u1_sw1, u1_sw3, u2_sw2])
    
    """
    Selects all softwares.
    """
    
    rs1 = Software.all()
    
    # Print results
    print ("SELECT * FROM Software")
    for sw in rs1:
        print sw.name
    
    """
    Selects a software given it's name.
    """
    
    rs2 = Software.all().filter("name =", "Notepad ++")
    
    # Print result
    print("""SELECT * FROM Software WHERE name = ?""")
    print rs2.get().name
    
    """
    Selects all software used by 'John Smith'.
    """
    
    # Get John Doe's key only, no need to fetch the entire entity
    user_key = db.Query(User, keys_only=True).filter("name =", "John Doe").get()
    
    # Get John Doe's software list
    rs3 = UserSoftwares.all().filter('user', user_key)
    
    # Print results
    print ("John Doe's software:")
    for item in rs3:
        print item.software.name
    
    """
    Selects all users using the software 'Office 2007'
    """
    
    # Get Google Chrome's key
    sw_key = db.Query(Software, keys_only=True).filter("name =", "Google Chrome").get()
    
    # Get Google Chrome's user list
    rs4 = UserSoftwares.all().filter('software', sw_key)
    
    # Print results
    print ("Google Chrome is currently used by:")
    for item in rs4:
        print item.user.name
    

    链接模型方法(推荐)

    您可以通过以这种方式表示每个表来为 多对多 关系建模:

    from google.appengine.ext import db    
    
    class User(db.Model):
        name = db.StringProperty()
    
    
    class Software(db.Model):
        name = db.StringProperty()
        description = db.TextProperty()
    
    
    class UserSoftwares(db.Model):
        user = db.ReferenceProperty(User, collection_name='users')
        software = db.ReferenceProperty(Software, collection_name='softwares')
    

    如您所见,它与关系型的思维方式非常相似。

    键列表方法(备选)

    关系也可以建模为键列表

    class User(db.Model):
        name = db.StringProperty()
        softwares = db.ListProperty(db.Key)
    
    
    class Software(db.Model):
        name = db.StringProperty()
        description = db.TextProperty()
    
        @property
        def users(self):
            return User.all().filter('softwares', self.key())
    

    这种方法更适合少量键,因为它使用 ListProperty,但比上面的 链接模型方法更快

    【讨论】:

    • 感谢您的回复。但我期待获得所有软件(SELECT * FROM software)。现在,如果当前登录用户是“U2”。然后它检查每个软件是否分配给用户'U2',如果从UserSoftwares中找到则status='Enable',否则status='Disable'。注意状态字段不存在于任何模型中。
    • @Nilesh-T 你不需要状态字段来将所有软件分配给特定用户,但我会根据我给你的模型用一些例子来更新我的答案。跨度>
    • 感谢您的帮助。这是一篇带有工作示例的好帖子。
    【解决方案2】:

    如果您正在寻找join - GAE 中没有联接。顺便说一句,很容易进行 2 个简单查询(SoftwaresUserSoftware),并手动计算所有额外数据

    【讨论】:

      【解决方案3】:

      根据Modeling Entity Relationships Datastore Article,您可以对此进行建模,有点像RDBMS 中的传统多对多关系。

      from google.appengine.ext import db
      class User(db.Model):
          name = db.StringProperty()
      
      class Software(db.Model):
          name = db.StringProperty()
      
      class UserSoftware(db.Model):
          user = db.ReferenceProperty(User, required=True, collection_name='softwares')
          software = db.ReferenceProperty(Software, required=True, collection_name='users')
      
      # use the models like so:
      
      alice = User(name='alice')
      alice.put()
      
      s1 = Software(name='s1')
      s1.put()
      
      us = UserSoftware(user=alice,software=s1)
      us.put()
      

      希望这会有所帮助。

      【讨论】:

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