Создание модели ManyToMany с обязательным полем
Есть модельки Городов и Туров. Тур может проходить по нескольким городам, в городе может проходить несколько туров. Логично - Many To Many. Но городу никто не запрещает существовать без тура, а вот тур 100% должен проходить как миниму по одному городу. Т.е. при создании города я могу не указывать туры, а вот при создании тура я обязан указать город.
class Tour(UUIDMixin, NameMixin, Model):
description = TextField(_('description'))
cities = ManyToManyField(
'City',
verbose_name = _('cities'),
through = 'TourCity'
)
def __str__(self) -> None:
return self.name
class Meta:
db_table = '"tours_data"."tour"'
ordering = ['name']
verbose_name = _('tour')
verbose_name_plural = _('tours')
unique_together = (('name', 'description', 'cities'),)
class City(UUIDMixin, NameMixin, Model):
country = CharField(
_('country'),
null=False,
blank=False,
max_length=COUNTRY_MAX_LEN
)
def __str__(self) -> None:
return f'{self.name}, {self.country}'
class Meta:
db_table = '"tours_data"."city"'
ordering = ['name']
verbose_name = _('city')
verbose_name_plural = _('cities')
unique_together = (('name', 'country'),)
class TourCity(UUIDMixin, Model):
tour = ForeignKey(Tour, verbose_name=_('tour'), on_delete=CASCADE)
city = ForeignKey(City, verbose_name=_('city'), on_delete=CASCADE, null=False, blank=False)
class Meta:
db_table = '"tours_data"."tour_city"'
unique_together = (('tour', 'city'),)
verbose_name = _('relationship tour city')
verbose_name_plural = _('relationships tour city')
Однако я все еще могу создать тур и не добавить в него ни одного города. Как это можно исправить?
Для проверки помогают инлайны.
Поле min_num
просто не даст создать запись в таблице если не удет заполнен хотя бы один инлайн. Он проверяет не то что инлайн просто добавлен, но и что в нем хранится значение.
Есть еще max_num
- но она не для моего случая, может кому понадобится.
Итак, в admin.py
делаем инлайн:
class TourCityInline(admin.TabularInline):
model = TourCity
min_num = 1
Который в последствии применяем ко всем нужным классам в админ-панели:
@admin.register(Tour)
class TourAdmin(admin.ModelAdmin):
model = Tour
inlines = (TourCityInline,)