Django 프로젝트를 개발하다 보면, 기본 User 모델의 groups나 user_permissions 필드를 다룰 때 TypeError가 생길수있다.
이번에 User 모델을 직접 생성하거나 데이터를 직렬화하는 과정에서 아래와 같은 에러가 발생했다.
TypeError at /accounts/signup/
Direct assignment to the forward side of a many-to-many set is prohibited. Use groups.set() instead.
에러 원인
Django의 groups와 user_permissions 필드는 ManyToManyField
ManyToManyField는 직접 할당할 수 없음
아래와 같이 User(**validated_data) 형태로 객체를 생성하려 하면, 내부적으로 직접 할당이 시도되면서 에러가 발생함
해결 방법
ManyToManyField 데이터를 처리하려면 set() 메서드를 사용해야 함.
set() 메서드를 호출하기 전, validated_data에서 해당 데이터를 분리해야 함 -> .pop() 메서드를 활용
기존 코드 (에러 발생 코드)
class UserSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True, required=True, validators=[validate_password])
password2 = serializers.CharField(write_only=True, required=True)
class Meta:
model = User
fields = "__all__"
extra_kwargs = {
'email': {'required': True},
'first_name': {'required': True},
'last_name': {'required': True},
'nickname': {'required': True},
'birthday': {'required': True},
'phone_number': {'required': True},
}
def validate(self, data):
if data['password'] != data['password2']:
raise serializers.ValidationError({
"password": "비밀번호가 일치하지 않습니다."
})
return data
def create(self, validated_data):
validated_data.pop('password2')
password = validated_data.pop('password')
user = User(**validated_data)
user.set_password(password)
user.save()
return user
위 코드에서 groups와 user_permissions 필드가 포함된 데이터를 처리하지 못해 에러가 발생함.
수정된 코드
class UserSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True, required=True, validators=[validate_password])
password2 = serializers.CharField(write_only=True, required=True)
groups = serializers.PrimaryKeyRelatedField(many=True, queryset=Group.objects.all(), required=False)
user_permissions = serializers.PrimaryKeyRelatedField(many=True, queryset=Permission.objects.all(), required=False)
class Meta:
model = User
fields = "__all__"
extra_kwargs = {
'email': {'required': True},
'first_name': {'required': True},
'last_name': {'required': True},
'nickname': {'required': True},
'birthday': {'required': True},
'phone_number': {'required': True},
}
def validate(self, data):
if data['password'] != data['password2']:
raise serializers.ValidationError({
"password": "비밀번호가 일치하지 않습니다."
})
return data
def create(self, validated_data):
groups = validated_data.pop('groups', [])
user_permissions = validated_data.pop('user_permissions', [])
validated_data.pop('password2')
password = validated_data.pop('password')
user = User(**validated_data)
user.set_password(password)
user.save()
# ManyToManyField 처리
user.groups.set(groups)
user.user_permissions.set(user_permissions)
return user
주요 변경 사항
groups와 user_permissions를 분리
validated_data.pop()을 사용해 ManyToManyField 데이터를 따로 분리함
groups와 user_permissions가 없을 수도 있으니 default=[] 설정을 추가
ManyToManyField 데이터 설정
user.groups.set(groups)와 user.user_permissions.set(user_permissions)로 데이터를 설정
Serializer 필드 정의
PrimaryKeyRelatedField를 사용해 groups와 user_permissions 필드를 명시적으로 정의
정리
Django의 ManyToManyField는 .set() 또는 .add() 메서드로 처리해야 함
직렬화 과정에서 데이터는 pop()으로 분리 후 처리하는 것이 안정적
Serializer에 필요한 필드를 명시적으로 정의해도 좋다.
'프로젝트' 카테고리의 다른 글
뉴욕타임스 API를 활용한 뉴스 저장 및 조회 시스템 (0) | 2025.01.10 |
---|---|
django 소셜로그인 시 url 패턴 오류 (0) | 2025.01.09 |
Django에서 Social Account 연동 시 IntegrityError 해결 방법 (0) | 2025.01.08 |
Django 오류 : Apps aren't loaded yet (0) | 2025.01.07 |
Django 회원가입 및 회원정보수정 시 Serializer 분리 (0) | 2025.01.06 |