Это не магия полей ManyToMany;это универсальный из django ORM с отношениями внешнего ключа (включая ManyToMany).
Например, если у вас есть
class Musician(models.Model):
name = models.CharField(max_length=128)
band = models.ForeignKey("Band")
class Band(models.Model):
name = models.CharField(max_length=128)
genre = models.CharField(max_length=50)
Вы можете сделать что-то вроде Musician.objects.filter(band__name='The Beatles')
Запрос можно увидетьс django-debug-toolbar или из оболочки django с:
from django.db import connection
connection.queries
и будет составлен из сложного оператора JOIN.SQL-запрос, созданный ORM, будет выглядеть примерно так:
SELECT "appname_musician"."id", "appname_musician"."name", "appname_musician"."band_id"
FROM "appname_musician"
INNER JOIN "appname_band" ON ("appname_musician"."band_id" = "appname_band"."id")
WHERE "appname_band"."name" = "The Beatles";
РЕДАКТИРОВАТЬ: Если вы сделали Band.objects.filter(musician__name = 'Ringo Starr')
, ORM переведет его в:
SELECT "appname_band"."id", "appname_band"."name", "appname_band"."genre"
FROM "appname_band"
INNER JOIN "appname_musician" ON ("appname_musician"."band_id" = "appname_band"."id")
WHERE "appname_musician"."name" = "Ringo Starr";
ORMзнает отношения и может преобразовать ваш запрос ORM в соответствующий SQL.Неважно, что у группы нет музыкального объекта;вы смогли дать django четкую просьбу: я хочу, чтобы все объекты группы были связаны с музыкантом с именем «Ringo Starr».
Я думаю, что вы, возможно, зациклены на мысли об инкапсуляции объектов (Например, в группе нет музыканта, как вы можете фильтровать на его основе?Это не черная магия, поскольку запрос фильтра ясен и недвусмысленен - и принимает в качестве аргументов не члены объекта Band;но команды для фильтрации.Например, вы можете сделать Band.objects(name__icontains = "The")
, даже если в Band нет объекта name__icontains
.ORM преобразует ваш запрос в SQL, который легко выполнить быстро.
EDIT2: Ваш последний пример:
class Musician(models.Model):
name = models.CharField(max_length=128)
initial_band = models.ForeignKey("Band", related_name = 'initial_band_members')
final_band = models.ForeignKey("Band", related_name = 'final_band_members')
class Band(models.Model):
name = models.CharField(max_length=128)
genre = models.CharField(max_length=50)
try: ## create some objects
cream,_ = Band.objects.get_or_create(name="Cream", genre="Classic Rock")
derek, _ = Band.objects.get_or_create(name="Derek and the Dominos", genre="Classic Rock")
beatles, _ = Band.objects.get_or_create(name="The Beatles", genre="Classic Rock")
wings, _ = Band.objects.get_or_create(name="Wings", genre="Classic Rock")
Musician.objects.get_or_create(name="Eric Clapton", initial_band=cream, final_band=derek)
Musician.objects.get_or_create(name="Paul McCartney", initial_band=beatles, final_band=wings)
Musician.objects.get_or_create(name="John Lennon", initial_band=beatles, final_band=beatles)
except:
pass
Тогда запросы типа Band.objects.filter(musician__name='Paul McCartney')
не работают (FieldError
), но запросы типа Band.objects.filter(initial_band_members__name='Paul McCartney')
будут возвращать найденные Битлз со следующим SQL (используя sqlite в качестве базы данных; команда зависит от серверной части БД):
SELECT "testing_band"."id", "testing_band"."name", "testing_band"."genre"
FROM "testing_band"
INNER JOIN "testing_musician" ON ("testing_band"."id" = "testing_musician"."final_band_id")
WHERE "testing_musician"."name" = Paul McCartney '