Skip to content

Fix duplicate validation errors for GenericIPAddressField with protocol#9982

Open
AsahiTakemura wants to merge 1 commit into
encode:mainfrom
AsahiTakemura:fix/duplicate-ip-validation
Open

Fix duplicate validation errors for GenericIPAddressField with protocol#9982
AsahiTakemura wants to merge 1 commit into
encode:mainfrom
AsahiTakemura:fix/duplicate-ip-validation

Conversation

@AsahiTakemura

Copy link
Copy Markdown

Summary

Fixes #9645

When a Django model uses GenericIPAddressField(protocol='IPv4') or GenericIPAddressField(protocol='IPv6'), the serializer generates duplicate validation errors for invalid input:

{'address': [
    ErrorDetail(string='Enter a valid IPv4 address.', code='invalid'),
    ErrorDetail(string='Enter a valid IPv4 or IPv6 address.', code='invalid'),
]}

Root Cause

Django adds a protocol-specific validator (validate_ipv4_address or validate_ipv6_address) to the model field. DRF's IPAddressField.__init__ also adds the same validator via ip_address_validators(). The existing code in field_mapping.py only removes validate_ipv46_address, leaving the protocol-specific validators in place, causing duplication.

Fix

In rest_framework/utils/field_mapping.py, extend the validator filter to also remove validate_ipv4_address and validate_ipv6_address:

if isinstance(model_field, models.GenericIPAddressField):
    validator_kwarg = [
        validator for validator in validator_kwarg
        if validator not in (
            validators.validate_ipv46_address,
            validators.validate_ipv4_address,
            validators.validate_ipv6_address,
        )
    ]

Test Plan

Added two new test cases:

  • test_ip_address_validation_with_protocol_ipv4 — verifies only 1 error for invalid input with protocol='IPv4'
  • test_ip_address_validation_with_protocol_ipv6 — verifies only 1 error for invalid input with protocol='IPv6'

All existing tests continue to pass.

🤖 Generated with Claude Code

When a Django model uses GenericIPAddressField(protocol='IPv4') or
(protocol='IPv6'), the model field gets a protocol-specific validator
(validate_ipv4_address or validate_ipv6_address) from Django. DRF's
IPAddressField also adds the same validator via ip_address_validators(),
resulting in duplicate error messages.

Fix: Remove validate_ipv4_address and validate_ipv6_address from the
serializer's validator_kwarg, in addition to the already-removed
validate_ipv46_address.

Fixes encode#9645

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes duplicated validation errors produced by DRF ModelSerializer when mapping Django GenericIPAddressField with an explicit protocol (IPv4/IPv6), by adjusting how model validators are carried over into serializer fields.

Changes:

  • Filter out Django’s validate_ipv4_address / validate_ipv6_address validators (in addition to validate_ipv46_address) when building serializer field kwargs.
  • Add new ModelSerializer tests covering GenericIPAddressField(protocol='IPv4') and protocol='IPv6'.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.

File Description
rest_framework/utils/field_mapping.py Extends the GenericIPAddressField validator filtering to avoid duplicated IP validation errors.
tests/test_model_serializer.py Adds regression tests asserting a single validation error for protocol-specific GenericIPAddressField.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +443 to +452
class IPAddressFieldModel(models.Model):
address = models.GenericIPAddressField(protocol='IPv4')

class Meta:
app_label = 'test_model_serializer'

class TestSerializer(serializers.ModelSerializer):
class Meta:
model = IPAddressFieldModel
fields = '__all__'
Comment on lines +461 to +470
class IPAddressFieldModel(models.Model):
address = models.GenericIPAddressField(protocol='IPv6')

class Meta:
app_label = 'test_model_serializer'

class TestSerializer(serializers.ModelSerializer):
class Meta:
model = IPAddressFieldModel
fields = '__all__'
Comment on lines 208 to +212
if isinstance(model_field, models.GenericIPAddressField):
validator_kwarg = [
validator for validator in validator_kwarg
if validator is not validators.validate_ipv46_address
if validator not in (
validators.validate_ipv46_address,
Comment on lines +454 to +458
s = TestSerializer(data={'address': 'not an ip address'})
self.assertFalse(s.is_valid())
self.assertEqual(1, len(s.errors['address']),
'Unexpected number of validation errors: '
'{}'.format(s.errors))
Comment on lines +472 to +476
s = TestSerializer(data={'address': 'not an ip address'})
self.assertFalse(s.is_valid())
self.assertEqual(1, len(s.errors['address']),
'Unexpected number of validation errors: '
'{}'.format(s.errors))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Duplicated GenericIPAddressField validation errors with ModelSerializer and protocol

2 participants