Django - редактируйте обе стороны отношения «многие ко многим» с помощью общего UpdateView - PullRequest
0 голосов
/ 24 сентября 2018

У меня есть вопрос, возможно ли использовать универсальный класс UpdateView для редактирования «обеих сторон» отношения «многие ко многим».У меня есть следующие классы, определенные в models.py:

class SomeCategory(models.Model):
    code = models.CharField(max_length=5)
    name = models.CharField(max_length=40)    


class SomeClass(models.Model):
    code = models.CharField(max_length=3, unique=True)
    name = models.CharField(max_length=30, unique=False)
    age = models.IntegerField(null=False)
    allowed_categories = models.ManyToManyField(SomeCategory)

Это обе таблицы словарных типов, в которых хранятся наборы данных конфигурации для моего приложения.Чтобы разрешить редактирование словарей, я использую простые UpdateViews:

class SomeClassUpdate(UpdateView):
    model = SomeClass
    template_name = 'admin/edit_class.html'
    fields = ['code', 'name', 'age', 'allowed_categories']
    ordering = ['code']

Это отлично работает, я получаю хороший мульти-выбор и все идеально.Однако я хотел бы иметь возможность редактировать отношения со стороны таблицы SomeCategory, чтобы я мог выбрать, какие элементы SomeClass связаны с определенной категорией SomeCategory:

class SomeCategoryUpdate(UpdateView):
    model = SomeCategory
    template_name = 'admin/edit_category.html'
    fields = ['code', 'name',  ??????? ]
    ordering = ['code']

Я попытался добавить related_name атрибут для модели SomeCategory, но это не сработало.

Есть какие-нибудь идеи, если это можно сделать без использования пользовательской ModelForm?

Ключевые версии библиотеки:

Django==1.11.8
psycopg2==2.7.4

PS: это мой самый первый вопрос, заданный относительно stackoverflow,поэтому, пожалуйста, дайте мне знать, если в моем сообщении отсутствуют какие-либо обязательные элементы.

1 Ответ

0 голосов
/ 15 августа 2019

Ваша проблема в файле models.py.У вас есть два класса, но только один из них упоминает другой.Вы могли бы подумать, что этого должно быть достаточно, поскольку вы все-таки используете ManyToManyField и предположить, что оно автоматически создаст каждое соединение, ведущее в обе стороны ... К сожалению, это не такНа уровне базы данных он действительно создает отдельную промежуточную таблицу со ссылками на объекты в обеих исходных таблицах, но это не означает, что обе они будут автоматически отображаться в Django Admin или аналогичном.

Если вы захотитепопытаться просто создать еще один someclass = models.ManyToManyField(SomeClass) в классе SomeCategory, который потерпит неудачу.Django попытается создать еще одну отдельную промежуточную таблицу от до , для которой будет установлено соединение между двумя основными таблицами.Но поскольку имя промежуточной таблицы зависит от того, где вы определяете соединение ManyToManyField, вторая таблица будет создана с другим именем, и все будет просто логически разрушаться (две таблицы имеют два отдельных способа default дляиметь соединение ManyToMany не имеет смысла).

Решение состоит в том, чтобы добавить ManyToManyField соединение к SomeCategory, одновременно ссылаясь на промежуточную / сквозную таблицу, которая была изначально создана в классе SomeClass.

Несколько замечаний оСоглашения Django / Python / Naming / Programming:

  • Используйте имя таблицы, на которую вы ссылаетесь, как имя поля, содержащего информацию об этом соединении.Это означает, что поле SomeClass со ссылкой на SomeCategory должно иметь имя somecategory вместо allowed_categories.
  • Если соединение одно-ко-многим - использовать единственную форму;если соединение много ко многим - используйте множественное число.Это означает, что в этом случае мы должны использовать множественное число и использовать somecategories вместо somecategory.
  • Django может автоматически приумножать имена, но это плохо, - просто добавляет в конец букву s.Mouse -> Mouses, Category -> Categorys.В таких случаях вам нужно помочь, определив verbose_name_plural в специальном Meta классе.
  • Использование ссылок на другие классы без дополнительных ' s работает, только если класс уже был определенранее в коде.В случае двух классов, ссылающихся друг на друга, это верно только одним способом.Решение состоит в том, чтобы поместить имя упомянутого класса в кавычки, такие как 'SomeCategory' вместо SomeCategory.А так как по умолчанию лучше придерживаться стиля и избегать ненужной траты энергии мозга на «я решу, использовать ли кавычки в зависимости от порядка организации классов; мне придется переделывать эти кавычки thingieкаждый раз, когда я решаю переместить некоторые фрагменты кода: «Я рекомендую просто использовать кавычки каждый раз.Так же, как при обучении управлению автомобилем - лучше научиться всегда использовать сигналы поворота, а не сначала оглядываться вокруг и принимать отдельное решение о том, будет ли кому-то полезна эта информация.

Поэтому решение заключается в том, чтоэто:

class SomeCategory(models.Model):
    code = models.CharField(max_length=5)
    name = models.CharField(max_length=40)
    someclasses = models.ManyToManyField('SomeClass', through='SomeClass.somecategories.through', blank=True)

    class Meta:
        verbose_name_plural = 'SomeCategories'


class SomeClass(models.Model):
    code = models.CharField(max_length=3, unique=True)
    name = models.CharField(max_length=30, unique=False)
    age = models.IntegerField(null=False)
    somecategories = models.ManyToManyField('SomeCategory')

После этого должно быть очевидно, какие окончательные изменения необходимо внести в UpdateView классы.

...