Как мне сделать несколько объединений и агрегацию с Django ORM? - PullRequest
2 голосов
/ 05 февраля 2011

Джанго / Python / ORM нуб здесь!Я с трудом нахожу мысли о том, как работают объединения в ORM.

Вот мои модели:

class Courts(models.Model):
    id = models.AutoField(primary_key=True)
    location_name = models.CharField(max_length=100)
    number = models.IntegerField()
    def __unicode__(self):
        return "%s %s %s" % (self.id, self.location_name, self.number)

class Matches(models.Model):
    id = models.AutoField(primary_key=True)
    date = models.DateTimeField()
    court = models.ForeignKey(Courts)
    def __unicode__(self):
        return "%s %s" % (self.id, self.date)

class Participants(models.Model):
    id = models.AutoField(primary_key=True)
    match = models.ForeignKey(Matches)
    userid = models.ForeignKey(User)
    games_won = models.IntegerField()
    def __unicode__(self):
        return "%s %s %s" % (self.id, self.games_won, self.userid)

Первый шаг - это получить все «участия».в вывод, подобный следующему:

[match_id] [date]       [userid]  [games_won]  [court_location_name]  [court_number]
1          01-01-2011   mike      6            Queen                  5
1          01-01-2011   chris     4            Queen                  5
2          01-02-2011   bob       3            Queen                  6
2          01-02-2011   joe       4            Queen                  6
3          01-03-2011   jessie    5            Queen                  2
3          01-03-2011   john      5            Queen                  2

Какой сценарий ORM я бы написал, чтобы получить это?Мне трудно понять, как работает простое объединение с ORM, а тем более объединение трех таблиц.

Далее я хочу объединить данные, чтобы они в конечном итоге выглядели так:

[match_id] [date]       [player1] [player2]  [p1wins] [p2wins] [game_winner] [court_location_name]  [court_number]
1          01-01-2011   mike      chris      6        4        mike          Queen                  5
2          01-02-2011   bob       joe        3        4        joe           Queen                  6
3          01-03-2011   jessie    john       5        5        draw          Queen                  2  

Изменит ли это сценарий ORM (в представлении), который я написал бы?Это то, что мне нужно включить в представление или в шаблон?

ОБНОВЛЕНИЕ:

Итак, я думаю, я могу использовать select_related () .Итак, я попробовал Players.objects.select_related () и получаю этот оператор SQL

SELECT "squash_participants"."id", "squash_participants"."match_id", "squash_participants"."userid_id", "squash_participants"."games_won", "squash_matches"."id", "squash_matches"."date", "squash_matches"."court_id", "squash_courts"."id", "squash_courts"."location_name", "squash_courts"."number", "auth_user"."id", "auth_user"."username", "auth_user"."first_name", "auth_user"."last_name", "auth_user"."email", "auth_user"."password", "auth_user"."is_staff", "auth_user"."is_active", "auth_user"."is_superuser", "auth_user"."last_login", "auth_user"."date_joined" FROM "squash_participants" INNER JOIN "squash_matches" ON ("squash_participants"."match_id" = "squash_matches"."id") INNER JOIN "squash_courts" ON ("squash_matches"."court_id" = "squash_courts"."id") INNER JOIN "auth_user" ON ("squash_participants"."userid_id" = "auth_user"."id"

Это больше похоже на то, чего я пытаюсь достичь.Теперь я не могу понять, как получить из этого данные в шаблон.

UPDATE2:

Мой взгляд выглядит так:

def index(request):
    matches_list = Participants.objects.all()
    return render_to_response('squash/base_matches.html', {'matches_list': matches_list}, context_instance = 
RequestContext(request))
    return HttpResponse(output)

И мойшаблон выглядит следующим образом:

{% for matches in matches_list %}
    <tr>
        <td>{{ matches.id }}</td> 
        <td>{{ matches.date|date:"d-m-Y" }}</td>
        <td>{{ matches.date|date:"G:i" }}</td>
    </tr>
    {% endfor %}

Он правильно отображает все Participants.id s, но, к примеру, не будет содержать идентификаторы матчей, даты или суды.

1 Ответ

5 голосов
/ 05 февраля 2011

У вас там есть пара "вещей":

  1. Определение первичных полей "id" не является необходимым и поэтому сбивает с толку, Django генерирует их автоматически
  2. Хорошей практикой является именование ваших моделей с использованием единственного числа (т. Е. Сопоставление вместо совпадений и т. Д.) - таким образом вы разрешаете Django обеспечить правильную обработку единственного и множественного числа . Это также логично, поскольку объект класса Match представляет одно совпадение, а не их число, а для нескольких совпадений используется менеджер моделей: Match.objects
  3. Ваша модель "Участники" фактически является промежуточной таблицей ManyToMany, которую вы можете явно объявить в модели "Соответствия", например ЗДЕСЬ

Теперь, что касается вашего вопроса JOIN, я поддерживаю подход S. Lott, который я когда-то читал где-то на StackOverflow - вы не должны думать о JOINs в Django, потому что это не то, как Django ORM («O» означает «объект») - и сопоставление SQL с объектами не является простым делом) работает. Вам следует сосредоточиться на выполнении своей работы и прибегать к использованию JOINs only в обоснованных случаях, например при проблемах с производительностью.

Наконец, ответ на ваш вопрос:

Participants.objects.all()

: -)

Вы можете добиться лучшей производительности, используя select_related () , также вы можете применить порядок, если необходимо, используя order_by () .

Что касается агрегации, другие могут прийти с однострочным решением, которого я не вижу в данный момент, но сейчас вы можете добавить это к модели "Matches":

players = models.ManyToManyField(User, through='Participants')

тогда вы можете просто выбрать совпадения самым простым способом:

Matches.objects.all()

и тогда у каждого элемента возвращаемого набора будет свойство «Players».

UPDATE:

Чтобы передать данные в шаблон, вам просто нужно добавить их в контекст рендеринга шаблона:

http://docs.djangoproject.com/en/1.2/ref/templates/api/#rendering-a-context

Это можно упростить с помощью render_to_response функции быстрого доступа.

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