Ограничение Проверки 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 7

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 иностранный ключ.
Пожалуйста поправьте, если я ошибаюсь!