Django序列化器多对多关联数据传递及非空约束问题排查
Hey there! Let's walk through these two issues you're hitting when building your skill-add-to-profile API—they’re super common with Django’s serializers and database relations, so let’s break them down step by step.
That error {"user": {"user": ["This field is required."]}} tells me your serializer is expecting a user value to be sent in the request, but either your frontend isn’t passing it… or more importantly, you shouldn’t be asking the frontend to send it at all.
Why this happens:
By default, Django’s ModelSerializer marks foreign key fields (like your user relation on UserSkill) as required. But for actions like adding a skill to the current logged-in user’s profile, you should automatically populate the user field from the request, not rely on the frontend to send a user ID (which is also a security risk).
Fix steps:
First, update your serializer to either exclude the user field or mark it as read-only, then auto-assign the logged-in user during creation:
# Serializer code class UserSkillSerializer(serializers.ModelSerializer): class Meta: model = UserSkill fields = ["id", "skill_item"] # Remove "user" from fields, or add it to read_only_fields read_only_fields = ["user"] def create(self, validated_data): # Auto-populate the user with the logged-in user from the request validated_data["user"] = self.context["request"].user return super().create(validated_data)
Then make sure your view passes the request to the serializer’s context (most generic views do this by default, but if not, add this):
# View code class UserSkillCreateAPIView(generics.CreateAPIView): serializer_class = UserSkillSerializer def get_serializer_context(self): context = super().get_serializer_context() context["request"] = self.request return context
Now your request body only needs to include the skill_item ID, no user field required.
Even after setting null=True on your skill_item foreign key, you’re still hitting this database constraint error. Here are the most likely culprits:
Why this happens:
- You didn’t apply model migrations: Changing
null=Truein your model doesn’t update the database automatically—Django needs a migration to alter the table’s constraint. - Missing
blank=Trueon the model field:null=Trueaffects the database, butblank=Truetells Django’s form/serializer validation that the field can be left empty. Without it, the serializer will still reject empty values. - Your request isn’t sending a valid
skill_itemID: If you’re trying to associate an existing skill, you need to pass a valid ID in the request body—if you skip it, the database will try to insert a NULL value, which the old constraint (before migration) blocks.
Fix steps:
First, update your UserSkill model to include both null=True and blank=True for the skill_item field (if you want to allow empty skills; if you always require a skill, skip blank=True and ensure the request sends a valid ID):
# Model code class UserSkill(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE) skill_item = models.ForeignKey( SkillItem, on_delete=models.CASCADE, null=True, blank=True # Add this line )
Then run the migrations to update the database:
python manage.py makemigrations python manage.py migrate
If you want to require a skill_item (which makes sense for this feature—users are adding existing skills), update your serializer to ensure it’s pulling valid skill IDs:
class UserSkillSerializer(serializers.ModelSerializer): # Explicitly define the skill_item field to validate against existing skills skill_item = serializers.PrimaryKeyRelatedField( queryset=SkillItem.objects.all(), required=True # Ensure this is set if you want to force a skill selection ) class Meta: model = UserSkill fields = ["id", "skill_item"] read_only_fields = ["user"] def create(self, validated_data): validated_data["user"] = self.context["request"].user return super().create(validated_data)
Finally, double-check your request body is sending a valid skill_item ID, like:
{"skill_item": 1}
内容的提问来源于stack exchange,提问作者Divyanshu Jimmy

