Извлечение унаследованных модельных объектов в Django - PullRequest
9 голосов
/ 03 марта 2011

У меня есть приложение django со следующей моделью:

Объект A - это простой объект, выходящий из модели с несколькими полями, и, скажем, конкретный объект является полем charс именем "ИМЯ" и целочисленное поле с именем "ЗАКАЗ" . A является абстрактным, что означает, что в базе данных нет A объектов, но вместо этого ...

Объекты B и C являются специализациями A , что означает, что они наследуются от A и добавляют некоторые другие поля.

Теперь предположим, что мне нужны все объекты, чье поле ИМЯ начинается с буквы "Z" , упорядоченной по полю ORDER , но яВам нужны все поля, специфичные для B и C для этих объектов.Теперь я вижу 2 подхода:

a) Выполнять запросы по отдельности для B и C объектов и извлекать два списка, объединять их, заказывать вручную и работать с этим.

b) Запрос A объектов на имена, начинающиеся с "Z" , упорядоченные по "ORDER" и с результатом запроса B и C объекты для получения всех оставшихся данных.

Оба подхода звучат крайне неэффективно, в первом я должен заказать их сам, во втором я должензапрашивать базу данных несколько раз.

Есть ли магический способ, по которому мне не хватает выбрать все объекты B и C , упорядоченные одним способом?Или, по крайней мере, более эффективный способ сделать это, чем оба упомянутых?

Заранее спасибо!

Бруно

Ответы [ 4 ]

6 голосов
/ 03 марта 2011

Если A может быть конкретным, вы можете сделать все это в одном запросе, используя select_related.

from django.db import connection
q = A.objects.filter(NAME__istartswith='z').order_by('ORDER').select_related('b', 'c')
for obj in q:
   obj = obj.b or obj.c or obj
   print repr(obj), obj.__dict__ # (to prove the subclass-specific attributes exist)
print "query count:", len(connection.queries)
1 голос
/ 08 августа 2013

На этот вопрос ответили здесь .

Используйте InheritanceManager из проекта django-model-utils .

0 голосов
/ 03 марта 2011

Пока вы заказываете оба запроса на B и C, объединить их довольно просто, не прибегая к дорогостоящему курсу:

# first define a couple of helper functions 

def next_or(iterable, other):
    try:
        return iterable.next(), None
    except StopIteration:
        return None, other

def merge(x,y,func=lambda a,b: a<=b):
    ''' merges a pair of sorted iterables '''
    xs = iter(x)
    ys = iter(y)
    a,r = next_or(xs,ys)
    b,r = next_or(ys,xs)
    while r is None:
        if func(a,b):
            yield a
            a,r = next_or(xs,ys)
        else:
            yield b
            b,r = next_or(ys,xs)
    else:
        if a is not None:
            yield a
        else:
            yield b
    for o in r:
        yield o

# now get your objects & then merge them

b_qs = B.objects.filter(NAME__startswith='Z').order_by('ORDER')
c_qs = C.objects.filter(NAME__startswith='Z').order_by('ORDER')

for obj in merge(b_qs,c_qs,lambda a,b: a.ORDER <= b.ORDER):
    print repr(obj), obj.__dict__

Преимущество этого метода в том, что он работает с абстрактным базовым классом.

0 голосов
/ 03 марта 2011

Запросы с использованием вашего метода "b" позволят вам "ввести" все оставшиеся данные, не запрашивая ваши модели B и C по отдельности. Вы можете использовать отношение "точка строчная название модели".

http://docs.djangoproject.com/en/dev/topics/db/models/#multi-table-inheritance

for object in A.objects.filter(NAME__istartswith='z').order_by('ORDER'):
    if object.b:
        // do something
        pass
    elif object.c:
        // do something
        pass

Возможно, вам придется попробовать, кроме исключений типа DidNotExist. Я немного подзабыл с моим Джанго. Удачи.

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