Спасибо, что никто не помог! Решил вопрос сам. Моя первая django-победа.
Решил в лоб, путём прямого union sql объединения 2х моделей и переопределения нескольких функций DjangoMpttAdmin, который в свою очередь наследовал admin.ModelAdmin.
Напоминаю, краткую предысторию
models.py
class Catalog(MPTTModel):
name = models.CharField(max_length=255, default='/', verbose_name=u'Имя')
parent = TreeForeignKey('self', null=True, blank=True, verbose_name=u'Родитель', related_name='child')
class Product(models.Model):
parent = models.ForeignKey(Catalog, blank=True, verbose_name=u'Папка', related_name='+')
title = models.CharField(max_length=255, db_index=True, verbose_name=u'Имя')
slug = models.SlugField(default = product_slug, max_length = 60, null = True, blank =True)
В итоге admin.py получил сл.вид:
from django_mptt_admin.admin import DjangoMpttAdmin
from django_mptt_admin import util
from django.core.urlresolvers import reverse
from django.contrib.admin.util import quote
class CatalogAdmin ( DjangoMpttAdmin ) :
def get_admin_url(self, name, type=None, args=None):
opts = self.model._meta
if type:
url_name = 'admin:%s_%s_%s' % (opts.app_label, type, name)
else:
url_name = 'admin:%s_%s_%s' % (opts.app_label, opts.module_name, name)
return reverse(url_name,args=args,current_app=self.admin_site.name)
def get_tree_data(self, qs, max_level):
pk_attname = self.model._meta.pk.attname
def handle_create_node(instance, node_info):
pk = quote(getattr(instance, pk_attname))
import logging
logging.debug(str(instance.type))
node_info.update(
url=self.get_admin_url('change', instance.type,(quote(pk),)),
move_url=self.get_admin_url('move', instance.type,(quote(pk),))
)
return util.get_tree_from_queryset(qs, handle_create_node, max_level)
def tree_json_view(self, request):
node_id = request.GET.get('node')
if node_id:
node = self.model.objects.get(id=node_id)
max_level = node.level + 1
else:
max_level = self.tree_load_on_demand
qs=Catalog.objects.raw('''select id, parent_id, name, lft, rght, tree_id, level, 'catalog' as type from offers_catalog
UNION
select id, parent_id, title, lft, rght, tree_id, level, 'product' from offers_product order by tree_id, lft''')
tree_data = self.get_tree_data(qs, max_level)
return util.JsonResponse(tree_data)
admin.site.register(Catalog, CatalogAdmin)
В конце то самое объединение таблиц через raw() с order by внутри т.к. RawQuerySet не имеет метода .order_by(). Единственное моё ноу-хау - последняя колонка, определяющая название модели каждой строки. Иначе дерево будет думать, что весь результат запроса - одна модель. Чтобы ссылки в дереве ссылались на нужную модель было решено передать в get_admin_url то самое название модели из sql-запроса.
Никто не знает, как запретить узлу иметь детей? Чтобы товар никода не смог стать родителем папки?