Просмотр исходного кода

Fixes #2301: Fix model validation on assignment of ManyToMany fields via API patch

Jeremy Stretch 7 лет назад
Родитель
Сommit
1bdfcd1dbe
2 измененных файлов с 12 добавлено и 5 удалено
  1. 5 0
      netbox/extras/tests/test_api.py
  2. 7 5
      netbox/utilities/api.py

+ 5 - 0
netbox/extras/tests/test_api.py

@@ -438,9 +438,13 @@ class ConfigContextTest(HttpStatusMixin, APITestCase):
 
 
     def test_update_configcontext(self):
     def test_update_configcontext(self):
 
 
+        region1 = Region.objects.create(name='Test Region 1', slug='test-region-1')
+        region2 = Region.objects.create(name='Test Region 2', slug='test-region-2')
+
         data = {
         data = {
             'name': 'Test Config Context X',
             'name': 'Test Config Context X',
             'weight': 999,
             'weight': 999,
+            'regions': [region1.pk, region2.pk],
             'data': {'foo': 'XXX'}
             'data': {'foo': 'XXX'}
         }
         }
 
 
@@ -452,6 +456,7 @@ class ConfigContextTest(HttpStatusMixin, APITestCase):
         configcontext1 = ConfigContext.objects.get(pk=response.data['id'])
         configcontext1 = ConfigContext.objects.get(pk=response.data['id'])
         self.assertEqual(configcontext1.name, data['name'])
         self.assertEqual(configcontext1.name, data['name'])
         self.assertEqual(configcontext1.weight, data['weight'])
         self.assertEqual(configcontext1.weight, data['weight'])
+        self.assertEqual(sorted([r.pk for r in configcontext1.regions.all()]), sorted(data['regions']))
         self.assertEqual(configcontext1.data, data['data'])
         self.assertEqual(configcontext1.data, data['data'])
 
 
     def test_delete_configcontext(self):
     def test_delete_configcontext(self):

+ 7 - 5
netbox/utilities/api.py

@@ -126,6 +126,8 @@ class SerializedPKRelatedField(PrimaryKeyRelatedField):
 # Serializers
 # Serializers
 #
 #
 
 
+# TODO: We should probably take a fresh look at exactly what we're doing with this. There might be a more elegant
+# way to enforce model validation on the serializer.
 class ValidatedModelSerializer(ModelSerializer):
 class ValidatedModelSerializer(ModelSerializer):
     """
     """
     Extends the built-in ModelSerializer to enforce calling clean() on the associated model during validation.
     Extends the built-in ModelSerializer to enforce calling clean() on the associated model during validation.
@@ -137,13 +139,13 @@ class ValidatedModelSerializer(ModelSerializer):
         attrs.pop('custom_fields', None)
         attrs.pop('custom_fields', None)
         attrs.pop('tags', None)
         attrs.pop('tags', None)
 
 
+        # Skip ManyToManyFields
+        for field in self.Meta.model._meta.get_fields():
+            if isinstance(field, ManyToManyField):
+                attrs.pop(field.name, None)
+
         # Run clean() on an instance of the model
         # Run clean() on an instance of the model
         if self.instance is None:
         if self.instance is None:
-            model = self.Meta.model
-            # Ignore ManyToManyFields for new instances (a PK is needed for validation)
-            for field in model._meta.get_fields():
-                if isinstance(field, ManyToManyField) and field.name in attrs:
-                    attrs.pop(field.name)
             instance = self.Meta.model(**attrs)
             instance = self.Meta.model(**attrs)
         else:
         else:
             instance = self.instance
             instance = self.instance