Skip to content

Conversation

Genarito
Copy link

@Genarito Genarito commented Sep 26, 2025

Note: Before submitting a code change, please review our contributing guidelines.

Description

Hi!
First of all, thank you for the library, it's very useful for my work!

While working on a project, I got a 500 error in production due to a configuration error on my part (copy-paste 🤦‍♂️): when using a PrimaryKeySerializer on a ManyToMany field and setting default=None like this:

class ManyToManyTarget(RESTFrameworkModel):
    name = models.CharField(max_length=100)


class ManyToManySource(RESTFrameworkModel):
    name = models.CharField(max_length=100)
    targets = models.ManyToManyField(ManyToManyTarget, related_name='sources')


class ManyToManySourceSerializer(serializers.ModelSerializer):
    targets = serializers.PrimaryKeyRelatedField(
        many=True,
        queryset=ManyToManyTarget.objects.all(),
        default=None  # <---- This
    )

It crashes at runtime with the following exception when no value is provided for targets field:

my_file.py:XXX: in some_func
    instance = serializer.save()
rest_framework\serializers.py:210: in save
    self.instance = self.create(validated_data)
rest_framework\serializers.py:1017: in create
    field.set(value)
venv\lib\site-packages\django\db\models\fields\related_descriptors.py:1328: in set
    objs = tuple(objs)

Now it seems simple and intuitive, but in production, with thousands of lines, dozens of serializers, and hundreds of fields, it took me a long time to figure out what the problem was.
To prevent errors in production, I added a new validation in the get_fields() method with a super descriptive message indicating a solution (I also added some tests to check this new behavior).
I couldn't find an earlier place to perform the validation, but this change allows the validation to run for other methods such as create() or update(). If you have a better place where the code block could be moved, please let me know, and I'll make the necessary adjustments.

Finally, since this is my first time collaborating on the project, I added some help to the contributing.md file to explain a few things, such as the -s parameter in pytests, which allows you to obtain the output during testing, or django.test.TestCase inheritance so you can use the Django DB. If you think it shouldn't be there, or you don't like the format, let me know and I can make the changes.

Thanks and best regards!

@Genarito Genarito changed the title Validation many to many Validation on many to many field when default=None Sep 26, 2025
Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR adds validation to prevent runtime errors when using PrimaryKeyRelatedField with many=True and default=None on ManyToMany fields, which causes crashes when trying to save the serializer.

  • Adds validation in get_fields() method to detect and prevent the problematic configuration
  • Includes comprehensive tests to verify the validation works correctly
  • Updates contributing documentation with helpful testing tips

Reviewed Changes

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

File Description
rest_framework/serializers.py Adds validation logic to detect ManyToMany fields with invalid default=None configuration
tests/test_serializer.py Adds test class to verify the new validation raises appropriate errors
docs/community/contributing.md Adds documentation for database testing and pytest output options

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Comment on lines +1094 to +1095
for field_name in declared_fields.keys():
if field_name in info.relations and info.relations[field_name].to_many and declared_fields[field_name].default is None:
Copy link
Preview

Copilot AI Sep 27, 2025

Choose a reason for hiding this comment

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

The variable info is referenced but not defined in the current scope. This will cause a NameError when the validation runs.

Copilot uses AI. Check for mistakes.

Copy link
Author

Choose a reason for hiding this comment

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

info is perfectly defined in line 1080

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
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.

2 participants