在django中执行数据库JOIN

时间:2011-07-04 02:51:16

标签: python sql database django orm

我想做与SELECT user_name, item_name FROM users, items WHERE users.favor_item_id = items.item_id等效的查询,即返回user_name和item_name对。在数据库中,一个用户可以拥有多个受欢迎的项目。

我只是好奇这个SQL查询的等效Django查询是什么?

我的第一个想法是列出USERS中的所有(user,favor_item_id)对,然后查找id为item_id的item_name。但似乎它会搜索ITEM表N次(N是对数),其复杂度为O(NlogM)(M是ITEM中的项目数),而使用上面的SQL查询,复杂度为O (N)。

在django(或任何ORM系统)中有更有效的方法吗?

2 个答案:

答案 0 :(得分:2)

  

(或任何ORM系统)?

真的?这是你在sqlalchemy中的表现方式

假设合理的映射类(这里,使用声明):

Base = sqlalchemy.ext.declarative.declarative_base()

class Item(Base):
    __tablename__ = 'items'
    id = Column('item_id', Integer, primary_key=True)
    name = Column('item_name', String)

class User(Base):
    __tablename__ = 'users'
    name = Column('user_name', String(50), primary_key=True)
    favor_item_id = Column(Integer, ForeignKey(Item.id))

    favor_item = relationship(Item, backref="favored_by")

查询非常简单

>>> print sqlalchemy.orm.Query((User.name, Item.name)).join(Item.favored_by)
SELECT users.user_name AS users_user_name, items.item_name AS items_item_name 
FROM items JOIN users ON items.item_id = users.favor_item_id

答案 1 :(得分:1)

假设模型:

class User(models.Model):
    name = models.CharField(max_length=32)
    favorite = models.ForeignKey(Item)

class Item(models.Model):
    name = models.CharField(max_length=32)

等效的Django将是:

usersFavorites = User.objects.all().values_list("name", "favorite__name")

这不使用您提供的字段的确切名称。为此,您只需在模型中添加适当的db_tabledb_column字段。

P.S。这种特殊的模式并不是特别好。恕我直言,UserItem应该有多对多的关系:

class User(models.Model):
    name = models.CharField(max_length=32)
    favorites = models.ManyToManyField(Item, related_name="users")

class Item(models.Model):
    name = models.CharField(max_length=32)

除非某个项目只能有一个用户,否则ForeignKey应位于Item

然后你可以迭代一个双循环:

for user in User.objects.all().select_related("favorites"):
    for favorite in user.favorites:
        # use `user` and `favorite` in some way.

由于select_related()调用,查询在第一个for循环中一举完成。