LINUX.ORG.RU

Django, проблема с пониманием orm.

 , , ,


0

2

Добрый день! Не так давно опять сел осваивать Django, столкнулся с orm и немного... Задумался. Есть простенькая модель

from django.conf import settings
from django.db import models


class Message(models.Model):
    message_num = models.IntegerField()
    owner = models.ForeignKey(settings.AUTH_USER_MODEL)
    name = models.CharField(max_length=50)
    creation_time = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return ''.join([
            str(self.id),
            ' ',
            str(self.message_num),
            ' ',
            self.name
        ])


class MessageVersion(models.Model):
    message_id = models.ForeignKey(Message)
    version_num = models.PositiveIntegerField()
    text = models.TextField()
    creation_time = models.DateTimeField(auto_now_add=True)
Хочется извлечь из MessageVersion последние версии для каждого Message. На SQL все решается банально
select res1.*, res2.* from homepage_messageversion res1
    join (
        select message_id_id, max(version_num) as version_num
        from homepage_messageversion
        group by message_id_id
    ) res2
    on (res1.message_id_id = res2.message_id_id)
    and (res1.version_num = res2.version_num);
Но как это превратить в запрос orm? И именно с join, а не where in?

ИМХО, либо RAW'ом, либо никак. Собственно, RAW как раз для таких (нестандартных /с точки зрения ОРМа/) селектов и сделан.

И еще: «message_id = models.ForeignKey(Message)» очень рискованное определение, поскольку джанга в своих моделях <forign_field_name>_id резервирует под ID внешнего ключа автоматически, и вовсе не рассчитывает что это имя будет использовано в качестве имени самого ключа.

То есть если ты напишешь, что

message = models.ForeignKey(Message)
то в твоей модели атрибут message_id будет определен автоматически, и в нем будет ID внешнего ключа. И все приложения джанги рассчитывают именно на это.

k0valenk0_igor ★★★ ()
Последнее исправление: k0valenk0_igor (всего исправлений: 1)
Ответ на: комментарий от k0valenk0_igor

Спасибо... Видимо меня ждет java+play+hibernate(HQL). Такие простые запросы делать через raw sql как то... Не кошерно.

matroskin ()
Ответ на: комментарий от matroskin

Ну, гарантированно кошерно получится на связке Flask+SQLAlchemy. Эта связка то, что ты хочешь, сделает «легко и непринужденно». Просто джанга... ну словом, не следует у джанги просить то, на что она не рассчитана.

k0valenk0_igor ★★★ ()
Последнее исправление: k0valenk0_igor (всего исправлений: 1)

Но как это превратить в запрос orm?

Взять нормальный orm, например алхимию. Нормальные шаблоны тоже не помешают.

bj ()

Но как это превратить в запрос orm? И именно с join, а не where in?

С таким «join» с подзапросом уж лучше б был where in...

In [1]: from qweqwe.models import *

In [2]: from django.db import connection

In [3]: Message.objects.values('id').annotate(version_num=models.Max('messageversion__version_num'))
Out[3]: [{'id': 1, 'version_num': 1}]

In [4]: print(connection.queries[-1]['sql'])
QUERY = 'SELECT "qweqwe_message"."id", MAX("qweqwe_messageversion"."version_num") AS "version_num" FROM "qweqwe_message" LEFT OUTER JOIN "qweqwe_messageversion" ON ( "qweqwe_message"."id" = "qweqwe_messageversion"."message_id_id" ) GROUP BY "qweqwe_message"."id" LIMIT 21' - PARAMS = ()
ei-grad ★★★★★ ()
Ответ на: комментарий от bj

При отсутствии рук и головы не поможет ни один orm. ORM в SQLAlchemy это полный треш, а уж если Django ORM не смог освоить, то алхимия противопоказана.

ei-grad ★★★★★ ()
Ответ на: комментарий от ei-grad

ORM в SQLAlchemy это полный треш

После вводных туторов можно пользоваться гораздо эффективнее чем джанговским. По крайней мере вопросы про джойны точно не возникают.

bj ()
Ответ на: комментарий от bj

А аргументировать хоть как-то?.. Уж что-что а джанговские доки с туториалами гораздо подробнее и понятнее. При работе с алхимией мне постоянно в ее код лезть приходится. Ты хоть бы попробовал сначала посмотреть как будет выглядеть решение задачи из топика на SQLa ORM. Вопросы у него, понимаешь, не возникают после прочтения туториалов.

ei-grad ★★★★★ ()
Ответ на: комментарий от matroskin

Такие простые запросы делать через raw sql как то... Не кошерно.

Во многих случаях использовать ORM не оправдано.

Siado ★★★★★ ()

сделать так, чтоб последняя версия доставалась легко и непринуждённо, а не через попу. в 95% случаев тебе нужна именно последняя версия, если ты её будешь доставать подобными запросами, производительность может(и скорее всего это и сделает) просесть.

vtVitus ★★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.