Django ManyToMany Validation Limit

I have a ManyToMany link and a foreign key that links three objects.

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

A can belong to many of B and vice versa. However, A can only belong to B-objects with the same parent C.

I am trying to do something in the clean() method of a model. I am using the Django Rest Framework and no ModelForms or anything like that. I still could not figure it out.

Simplified Code Example

 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 

serializers

 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') 
+7
django django-models django-rest-framework
source share
2 answers

I am not sure where and how you want to check your data. So I'm just sending a method that can check if the project can be connected to the device or not based on your specific check.

 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 

EDIT:

You must use an intermediate model to store the relationship between the device and the project.

 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) 

Use the above membership model to maintain many of the many relationships.

In your device model, this field is used to determine the relationship of many to many.

projects = models.ManyToManyField(Project, through='Membership')

select docs

Now that you are connecting the device and the project, you will also explicitly add the area identifier. Before adding, you can now check if the project is valid or not based on the related area.

+1
source share

(ignore field types, cba) enter image description here

What’s the matter: we need a table BC , which stores the relationship between B and C. Table A will only select from these relationships through the intermediate table m2m ABC (or ditch ABC, it was not possible to figure out how to draw m2m using the online tool). I think I mixed up B and C in this picture, change them depending on whether B or C contains ForeignKey.
Please correct if I am wrong!

+2
source share

All Articles