Issue
I'm creating an api that will register users related to a customer and also to an organizational group, but I'm having problems registering the user's group.
whenever I try to register I get the following error:
"Direct assignment to the forward side of a many-to-many set is prohibited. Use grupo.set() instead."
Could you help me understand what I'm doing wrong?
my models.py
class Cliente(models.Model):
nome = models.CharField(max_length=100, unique=True, null=True)
documento = models.CharField(max_length=30, blank=True, default='00.000.000/0001-00')
logo = models.CharField(max_length=255, blank=True, null=True)
data_de_criacao = models.DateField(default=date.today)
cliente_ativo = models.BooleanField(default=True)
background_img = models.CharField(max_length=255, blank=True, null=True)
cor_primaria = models.CharField(max_length=10, blank=True, null=True)
cor_secundaria = models.CharField(max_length=10, blank=True, null=True)
def __str__(self):
return self.nome
class GrupoOrganizacional(models.Model):
id_grupo = models.BigAutoField(primary_key=True, unique=True)
nome_grupo = models.CharField(max_length=100, blank=False, null=False)
cliente = models.ForeignKey(Cliente, blank=True, null=True ,on_delete=models.CASCADE)
def __str__(self):
return self.nome_grupo
class Usuario(AbstractUser):
objects = CustomUserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
cliente = models.ForeignKey(Cliente, blank=True, null=True ,on_delete=models.CASCADE)
first_name = models.CharField(max_length=100, blank=False, null=False)
last_name = models.CharField(max_length=100, blank=False, null=False)
username = models.CharField(max_length=50, blank=True, null=True)
email = models.EmailField(max_length=100, blank=False, null=False, unique=True, error_messages={'unique': "O email cadastrado já existe."})
password = models.CharField(max_length=100, blank=False, null=False)
usuario_ativo = models.BooleanField(default=True)
grupo = models.ManyToManyField(GrupoOrganizacional, related_name='grupos')
is_staff = models.BooleanField(default=True)
is_superuser = models.BooleanField(default=False)
def __str__(self):
return "%s (%s)" %(self.first_name, self.cliente)
my views.py
class GruposViewSet(viewsets.ModelViewSet):
''' Lista todos os grupos cadastrados '''
queryset = GrupoOrganizacional.objects.all()
serializer_class = ListaGruposSerializer
permission_classes = [IsAuthenticated, IsAdminUser]
class UsuariosViewSet(viewsets.ModelViewSet):
''' Lista todos os usuarios cadastrados'''
queryset = Usuario.objects.all()
serializer_class = UsuarioSerializer
permission_classes = [IsAuthenticated, IsAdminUser]
my serializers.py
class GruposDoUsuarioSerializer(PrimaryKeyRelatedField ,serializers.ModelSerializer):
'''Serializer para listar todos os grupos organizacionais cadastrados'''
#grupo_id = serializers.PrimaryKeyRelatedField( many=True, read_only=True )
class Meta:
model = GrupoOrganizacional
fields = ['id_grupo']
class UsuarioSerializer(serializers.ModelSerializer):
'''Serializer para listar, criar e atualizar os usuarios'''
grupo = GruposDoUsuarioSerializer(many=True, queryset=GrupoOrganizacional.objects.all()) # Quando usado, envia uma lista não suportada
password = serializers.CharField(
style={'input_type': 'password'},
write_only=True,
label="Senha"
)
password_confirm = serializers.CharField(
style={'input_type': 'password'},
write_only=True,
label="Confirme a senha"
)
is_staff = serializers.BooleanField(
label="Membro da Equipe",
help_text="Indica que usuário consegue acessar o site de administração."
)
is_superuser = serializers.BooleanField(
label="SuperUsuário",
help_text="Indica que este usuário tem todas as permissões sem atribuí-las explicitamente."
)
class Meta:
model = Usuario
fields = ('id','cliente', 'first_name', 'last_name', 'username', 'email',
'password', 'password_confirm', 'usuario_ativo', 'grupo', 'is_staff', 'is_superuser')
extra_kwargs = {'password': {'write_only': True}}
def create(self, validated_data):
'''Permite caradastrar e atualizar contas'''
usuario = Usuario.objects.create(**validated_data)
grupo_data = validated_data.get('id_grupo')
password = self.validated_data.get('password')
password_confirm = self.validated_data.get('password_confirm')
for grupo_data in grupo_data:
GrupoOrganizacional.objects.create(usuario=usuario, **grupo_data)
if password != password_confirm:
raise serializers.ValidationError({'password': 'As senhas não são iguais.'})
#usuario.grupo.set(usuario)
#usuario.set_grupo(grupo)
usuario.set_password(password)
usuario.save()
return usuario
I had no problems with the customer registration, only in the group registration.
I've already tried to change my code based on the DRF documentation and some doubts from here, I realized that the problem is probably in the serializer.py, but I still can't understand what is causing the error
some references of what I tried to do:
At some point the groups stopped showing up on the api page, so I used this reference to solve the problem:
EDIT: I was able to solve all the problems by replacing all the valid answer data with a for:
for grupo in grupo_data:
usuario.grupo.add(grupo)
Solution
Try something like:
grupo_organizacional_list = []
for grupo_data in grupo_data:
grupo_organizacional_list.append(GrupoOrganizacional(**grupo_data))
grupo_organizacional_list = GrupoOrganizacional.bulk_create(grupo_organizacional_list)
usario.grupo.set(*grupo_organizacional_list)
EDIT: With the traceback, the error seems to come from the first line of the create function. Try something like this:
def create(self, validated_data):
'''Permite caradastrar e atualizar contas'''
grupo_data = validated_data.pop('grupo')
usuario = Usuario.objects.create(**validated_data)
Removing the grupo field from the validated data before the creation occurred should prevent django from throwing the error
Answered By - Alombaros
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.