Django ManyToMany验证约束

时间:2018-02-01 03:18:56

标签: django django-models django-rest-framework

我有一个ManyToMany链接,以及一个链接三个对象的外键。

[A]> - < [B]> --- [C]

A可以属于B的许多,反之亦然。但是,A只能属于相同父级 C的B对象。

我试图在模型的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 个答案:

答案 0 :(得分:2)

(忽略不稳定的字段类型,cba) enter image description here

归结为:您需要一个表 BC 来存储 B C 之间的关系。表 A 然后只能通过中间m2m表 ABC (或沟渠ABC,无法通过在线工具绘制m2m)来选择这些关系。我想我在这张照片中混淆了B和C,根据B或C是否持有ForeignKey来交换它们 如果我错了,请更正!

答案 1 :(得分: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')

结帐docs

现在,当您链接设备和项目时,您也将明确添加区域ID。在现在添加之前,您可以根据相关区域检查项目是否有效。