Ведение базы данных JOIN в Django - PullRequest
0 голосов
/ 04 июля 2011

Я хочу сделать эквивалентный запрос как SELECT user_name, item_name FROM users, items WHERE users.favor_item_id = items.item_id, который должен вернуть пары user_name и item_name.В базе данных один пользователь может иметь несколько избранных элементов.

Мне просто любопытно, что является эквивалентным запросом Django для этого запроса SQL ??

Моя первая мысль - перечислить все, fav_item_id) пара из USERS, а затем искать item_name с идентификатором item_id.Но похоже, что он будет искать таблицу ITEM N раз (N - это количество пар), которая имеет сложность O (NlogM) (M - это число элементов в ITEM), хотя при использовании вышеуказанного SQL-запроса сложность равна O(N).

Есть ли более эффективный способ сделать это в django (или любой системе ORM)?

Ответы [ 2 ]

2 голосов
/ 04 июля 2011

(или любая система 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 голос
/ 04 июля 2011

Предполагая модель:

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_table и db_column в модели.

PS Эта конкретная схема не особенно хороша.ИМХО, User и Item должны иметь отношение «многие ко многим»:

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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...