Ограничение Проверки Django ManyToMany
У меня есть множество ссылок и внешний ключ, который связывает три объекта.
[A]>---- - [C]
A может принадлежать многим из B, и наоборот. Однако A может принадлежать только объектам B с тем же родителем C.
Я пытаюсь что-то сделать в методе clean()
модели. Я использую Django Rest Framework, а не ModelForms или что-то в этом роде. Я пока не могу этого понять
Упрощенный Образец Код
class Device(models.Model):
name = models.CharField(max_length=20)
projects = models.ManyToManyField(Project, 'devices')
details = models.CharField(max_length=200)
serial = models.CharField(max_length=20)
address models.GenericIPAddressField(default="0.0.0.0")
port = models.IntegerField(default=3000)
jumpers = models.IntegerField(default=0)
install_date = models.DateField(blank=True, null=True)
class Project(models.Model):
name = models.CharField(max_length=20)
description = models.CharField(max_length=250)
area = models.ForeignKey(Area)
class Area(models.Model):
name = models.CharField(max_length=20)
description = models.CharField(max_length=250)
owner = models.CharField(max_length=20) # microservice doesn't have owner group - field in JWT
Сериализаторы
class AreaSerializer(serializers.ModelSerializer):
class Meta:
model = Area
fields = ('name', 'description', 'owner')
class ProjectSerializer(serializers.ModelSerializer):
class Meta:
model = Project
fields = ('id', 'name', 'description', 'area')
class DeviceSerializer(serializers.ModelSerializer):
class Meta:
model = Device
fields = ('id', 'name', 'projects', 'details', 'serial',
'address', 'port', 'jumpers', 'install_date')
2 ответа:
Я не уверен, где и как вы хотите проверить свои данные. Поэтому я просто публикую метод, который может проверить, может ли проект быть связан с устройством или нет на основе вашей конкретной проверки.
def validate_project(device, project): projects = device.projects.all() areas = set(projects.values_list('area', flat=True)) if len(areas) > 1: raise serializers.ValidationError('projects are not valid') return areas.pop() == project.area_id
Правка:
Вы должны использовать промежуточную модель для хранения отношений между устройством и проектом.
class Membership(models.Model): device = models.ForeignKey(Device, on_delete=models.CASCADE) project = models.ForeignKey(Project, on_delete=models.CASCADE) area = models.ForeignKey(Area, on_delete=models.CASCADE)
Используйте приведенную выше модель членства для хранения отношений "многие ко многим".
В модели вашего устройства используйте это поле для определения отношения "многие ко многим". отношение.
projects = models.ManyToManyField(Project, through='Membership')
Теперь, когда вы связываете устройство и проект, вам придется явно добавить идентификатор области. Перед добавлением теперь вы можете проверить, является ли проект допустимым или нет, основываясь на соответствующей области.
(игнорировать типы полей wonky, cba)
Все сводится к следующему: вам нужна таблица BC, которая хранит отношения между B и C. Таблица A затем выбирала бы только из этих отношений через промежуточную таблицу m2m ABC (или ditch ABC, не мог понять, как нарисовать m2m с помощью онлайн-инструмента). Я думаю, что я перепутал B и C на этой картинке, меняя их местами в зависимости от того, держит ли B или C иностранный ключ.
Пожалуйста поправьте, если я ошибаюсь!