Общие отношения «многие ко многим» в django admin - PullRequest
5 голосов
/ 18 апреля 2011

У меня есть несколько похожих моделей в Django:

class Material(models.Model):
    title = models.CharField(max_length=255)
    class Meta:
        abstract = True

class News(Material):
    state = models.PositiveSmallIntegerField(choices=NEWS_STATE_CHOICES)

class Article(Material):
    genre = models.ForeignKey(Genre, verbose_name='genre')

И модель Тема , которая относится к News и Article как ManyToMany.

Мне бы хотелосьиспользовать общие отношения «многие ко многим», как в этом случае .Но вопрос в том, как использовать стандартный виджет ManyToMany в django admin.Или другой удобный аналог.

UPD : Если бы я не использовал дженерики, я написал бы

class News(Material): 
    topic = models.ManyToMany(Topic) 

class Article(Material):
    topic = models.ManyToMany(Topic)

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

Ответы [ 2 ]

7 голосов
/ 18 апреля 2011

РЕДАКТИРОВАТЬ: Проверьте это http://charlesleifer.com/blog/connecting-anything-to-anything-with-django/

GenericForeignKey, к сожалению, не так хорошо, как ForeignKey.Существует открытый (и принятый) тикет с патчем для предоставления им виджета: http://code.djangoproject.com/ticket/9976

В комплект поставки входит управление объектами с помощью встроенного GenericForeignKey.

Предполагается, чтоВаше общее родство достигается с помощью

from django.contrib.contenttypes import generic
from django.contrib.contenttypes.models import ContentType
from django.db import models

class News(models.Model):
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    content_object = generic.GenericForeignKey('content_type', 'object_id')
    ...

и

class Topic(models.Model):
    ...
    news = generic.GenericRelation('News')   # if separate app: 'newsapp.News'

Если вы хотите редактировать новости по теме, вы можете определить встроенного администратора для новостей:

from django.contrib.contenttypes.generic import GenericTabularInline

class NewsInline(GenericTabularInline):
    model = News

и добавьте его в заголовки администратора темы:

class TopicAdmin(models.ModelAdmin):
    inlines = (NewsInline, )

Тем не менее, из предоставленной информации я не вижу, что не так с вашими отношениями в ManyToMany.Кажется, он выражает то, что вам нужно.

Может быть, вы определяете поле ManyToMany в теме, а не в новостях и статьях?Определите их в новостях и статьях.

РЕДАКТИРОВАТЬ: Спасибо за разъяснения.Настройка вашей модели будет такой же, как в сообщении Arie (т. Е. Наоборот), и вы будете редактировать inline.Если вы просто хотите выбрать существующую тему изнутри News / Article / etc.Например, я не знаю ничего из коробки для GenericRelation (который обычно просто служит помощником обратного просмотра).Вы можете

a) Переопределить форму администратора и добавить ModelMultipleChoiceField с набором запросов в соответствии с GenericRelation

b) Переопределить save () для настройки отношений.

Довольномного работы.Я лично придерживался нескольких таблиц m2m и не собирал все в одну.Если вы боитесь, что база данных выполнит несколько поисков при запросе всех новостей, статей и т. Д. Одной или нескольких тем, то имейте в виду, что универсальное решение всегда будет иметь настройку, аналогичную требованиям GenericForeignKey, то есть дополнительные столбцы длямодель и идентификатор.Это может привести к гораздо большему количеству запросов (например, к content_type для каждого результата).

2 голосов
/ 18 апреля 2011

Разве это не должно сработать, если вы просто переверните пример Дэнни и определите родовое отношение на стороне Topic -Модели?

См. Пример в документации django: http://docs.djangoproject.com/en/dev/ref/contrib/admin/#using-generic-relations-as-an-inline

Адаптировано к этому вопросу:

class Topic(models.Model):
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    content_object = generic.GenericForeignKey("content_type", "object_id")

Возможно, имеет смысл дополнительно определить обратное отношение для каждой связанной модели.

class News(models.Model):
    topics = generic.GenericRelation(Topic)

А теперьВы можете создать TopicInline и прикрепить Темы к новостям, статьям, что угодно ...

class TopicInline(generic.GenericTabularInline):
    model = Topic

class ArticleAdmin(admin.ModelAdmin):
    inlines = [
        TopicInline,
    ]

class NewsAdmin(admin.ModelAdmin):
    inlines = [
        TopicInline,
    ]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...