ManytoMany relationship serializer - python

I've encountered a huge problem with a single Many to many relationship, Im trying to send the id's of the users to the group serializer in order for me to save them and create the group however the id is never recorded and grupos is created with nothing but saves nombre and creates the object.
Models.py
class Usuarios(models.Model):
class Meta:
db_table = "Usuarios"
idUsuario = models.AutoField(primary_key=True)
tipoUsuario = models.BooleanField(blank=False)
nombre = models.CharField(max_length=100,blank=False)
idUser = models.IntegerField(blank=False)
idEscuela = models.ForeignKey(Escuelas, on_delete=models.CASCADE)
class Grupos(models.Model):
class Meta:
db_table = "Grupos"
idGrupo = models.AutoField(primary_key=True)
nombre = models.CharField(max_length=30,blank=False,unique=True)
idUsuario = models.ManyToManyField(Usuarios)
class idUsuarioSerializer(serializers.Serializer):
#idUsuario = serializers.IntegerField(required=True)
class Meta:
model = Usuarios
fields = ('idUsuario',)
class GrupoSerializer(serializers.Serializer):
nombre = serializers.CharField(required=True)
idUsuario = idUsuarioSerializer(many=True)
class Meta:
model = Grupos
fields = ('nombre','idUsuario')
def create(self, validated_data):
idUsuarios_data = validated_data.pop('idUsuario')
grupo = Grupos.objects.create(**validated_data)
for idUsuario_data in idUsuarios_data:
#print(**idUsuario_data)
#Usuarios.objects.create(grupo=grupo,**idUsuario_data)
grupo.idUsuario.add(**idUsuario_data)
grupo.save()
return grupo
However this saves nothing on idUsuario field and also if I do it like the documentation it gives me an error "group is not a valid keyword" or even if I use "idGrupo" it says the same, I already check other answers looks like it's not possible, already tried add method too.
I send the following json
{
"nombre": "4B",
"idUsuario":[{"id":1},{"id":2}]
}

Try something like this,
for idUsuario_data in idUsuarios_data:
grupo.idUsuario.add(idUsuario_data['id'])
grupo.save()

Related

Django REST: Set all Serializer fields as not required at once

Is there any way to set my serializer fields as not required by default? it'll take me hours to set every field of every serializer I have as not required so I wanted to know if there's any shortcut.
One example:
class ComputersSerializer(serializers.ModelSerializer):
name = serializers.CharField(required=False)
serial = serializers.CharField(required=False)
otherserial = serializers.CharField(required=False)
contact = serializers.CharField(required=False)
contact_num = serializers.CharField(required=False)
comment = serializers.CharField(required=False)
date_mod = serializers.DateTimeField(required=False)
is_template = serializers.IntegerField(default=0)
template_name = serializers.CharField(required=False)
is_deleted = serializers.IntegerField(default=0)
is_dynamic = serializers.IntegerField(default=0)
ticket_tco = serializers.DecimalField(max_digits=20, decimal_places=4, required=False)
uuid = serializers.CharField(required=False)
date_creation = serializers.DateTimeField(required=False)
is_recursive = serializers.IntegerField(default=0)
last_inventory_update = serializers.DateTimeField(required=False)
computertypes = ComputertypesSerializer(required=False)
computermodels = ComputermodelsSerializer(required=False)
entities = EntitiesSerializer(required=False)
networks = NetworksSerializer(required=False)
locations = LocationsSerializer(required=False)
autoupdatesystems = AutoupdatesystemsSerializer(required=False)
users = assistanceSerializers.UsersSerializer(required=False)
groups = assistanceSerializers.GroupsSerializer(required=False)
states = StatesSerializer(required=False)
users_tech = assistanceSerializers.UsersSerializer(required=False)
groups_tech = assistanceSerializers.GroupsSerializer(required=False)
manufacturers = ManufacturersSerializer(required=False)
class Meta:
model = Computers
fields = '__all__'
For the moment I had to set it for each field. I've been searching if someone had the same problem but it looks like I'm lazier than the rest of programmers.
If you want to make the field optional, it should be defined in your model.
The ModelSerializer will react to that.
From the docs:
If you're using Model Serializer default value will be False if you have specified blank=True or default or null=True at your field in your Model.
Try this:
class ComputersSerializer(serializers.ModelSerializer):
class Meta:
model = Computers
fields = '__all__'
extra_kwargs = {field.name:{'required': False} for field in Computers._meta.get_fields()}

Cannot assign "'value'": "model.attr" must be a "model" instance

I am new en django, I have the next models in models.py
class Persona(models.Model):
cedula_p= models.CharField(primary_key=True, max_length=10)
Nombre_p= models.CharField(User, max_length=100)
fecha_nacimiento_p= models.DateField()
#11111, User1, 01/01/1991
#22222, User2, 02/02/1992
#Others 13998 items
def __str__(self):
return "{0},{1}".format(self.cedula_p, self.Nombre_p)
class Producto(models.Model):
Nombre_prod = models.CharField(max_length=100)
precio = models.PositiveIntegerField()
def __str__(self):
return "{0}".format(self.Nombre_prod)
class compra(models.Model):
cedula_prod= models.ForeignKey(Persona, max_length=10, on_delete=models.CASCADE)
producto = models.ForeignKey(Producto, on_delete=models.CASCADE)
The forms.py is:
class formulario_compra(forms.ModelForm):
cedula_prod = forms.CharField()
#I have 14.000 elements, for that reason i don't use select o choicefield
class Meta:
model = compra
fields = '__all__'
#input test cedula_prod: 11111 or 22222
and the views.py
class crear_persona(CreateView):
model = Persona
form_class = formulario_persona
template_name = 'web1.html'
success_url = reverse_lazy('EjemploVista1')
class crear_compra(CreateView):
model = compra
form_class = formulario_compra
template_name = 'Web2.html'
success_url = reverse_lazy('EjemploVista2')
in the forms, in formulario_compra i don't use the default form for cedula_prod because would be a list with some values (14000), so, I use a charField. I need to verify that the input exists in the model Persona.cedula_p. At the moment to try to save appear:
Cannot assign "11111": "compra.cedula_prod" must be a "Persona" instance.
I try different things, but I can't solve this situation.
Because your model take ForeignKey you cannot assign character type. So, you have to use sthg like ModelChoiceField.
class formulario_compra(forms.ModelForm):
cedula_prod = ModelChoiceField(queryset=Persona.objects.all())
You can see here to check the corresponding form and model fields.

How do you add existing objects to a ManyToMany field using Serializer?

I am trying to create an API with Artists and Songs, with a ManyToMany relationship between the two. Using the API to create a Song with an Artist that is not in the database works fine. The problem arises when I attempt to use the POST method to create a new Song with an Artist that already exists in the database. I tried overwriting the SongSerializer create() method using get_or_create() based on another post here, but I kept getting Bad Request errors when the Artist already exists in the database. The relevant code snippets:
models.py
class Artist(models.Model):
artist_name = models.CharField(max_length=200, unique=True)
class Meta:
ordering = ['artist_name']
def __str__(self):
return self.artist_name
class Song(models.Model):
song_title = models.CharField(max_length=200)
artists = models.ManyToManyField(Artist, related_name='songs')
class Meta:
ordering = ['song_title']
def __str__(self):
return self.song_title
serializers.py
class ArtistNameSerializer(serializers.ModelSerializer):
class Meta:
model = Artist
fields = ('artist_name',)
def to_representation(self, value):
return value.artist_name
class SongTitleSerializer(serializers.ModelSerializer):
songs = serializers.PrimaryKeyRelatedField(read_only=True, many=True)
def to_representation(self, value):
return value.song_title
class Meta:
model = Song
fields = ('songs',)
class ArtistSerializer(serializers.HyperlinkedModelSerializer):
songs = SongTitleSerializer(read_only=True, many=True)
class Meta:
model = Artist
fields = ('id', 'artist_name', 'songs')
class SongSerializer(serializers.HyperlinkedModelSerializer):
artists = ArtistNameSerializer(many=True)
class Meta:
model = Song
fields = ('id', 'song_title', 'artists',)
def create(self, validated_data):
artist_data = validated_data.pop('artists')
song = Song.objects.create(**validated_data)
song.save()
for artist_item in artist_data:
a, created = Artist.objects.get_or_create(artist_name=artist_item['artist_name'])
song.artists.add(a)
return song
I've done some tests and it looks like the program doesn't even go into the create() method I'm using, going straight to showing me the Bad Request error. What am I missing? Thanks in advance!
On you Artist model you have a constrain on the artist_model field (unique=True)
if you print the serializer in question with:
print(SongSerializer())
you get something like this:
SongSerializer():
id = IntegerField(label='ID', read_only=True)
song_title = CharField(max_length=200)
artists = ArtistNameSerializer(many=True):
artist_name = CharField(max_length=200, validators=[<UniqueValidator(queryset=Artist.objects.all())>])
under the artist_name field is a Validator "UniqueValidator"
so in case of a write operation you can disable the validator in the serializer with:
class ArtistNameSerializer(serializers.ModelSerializer):
class Meta:
model = models.Artist
fields = ('artist_name',)
extra_kwargs = {
'artist_name': {
'validators': [],
}
}
hope this help..

Django Rest Framework: dynamic database on POST - RelatedField or PrimaryKeyRelatedField

I'm developing RESTFul services with DRF and I have multiple databases depending on the country (see my last question here)
I'm having a problem now with relationships, I have two models: Category and SubCategory:
class SubCategory(models.Model):
objects = CountryQuerySet.as_manager()
id = models.AutoField(primary_key=True,db_column='sub_category_id')
name = models.TextField()
female_items_in_category = models.BooleanField()
male_items_in_category = models.BooleanField()
kids_items_in_category = models.BooleanField()
category = models.ForeignKey('Category')
class Meta:
managed = True
db_table = Constants().SUBCATEGORY
And the serializer is:
class SubCategorySerializer(serializers.ModelSerializer):
category = PrimaryKeyRelatedField(queryset=Category.objects.using('es').all())
class Meta:
model = SubCategory
fields = ('id', 'name','female_items_in_category','male_items_in_category','kids_items_in_category','category')
If I don't set the queryset with the proper country it fails, because it doesn't know where to get the category.
Here the problem
I already set the country in the serializer context (in the ModelViewSet):
def get_serializer_context(self):
return {Constants().COUNTRY: self.kwargs.get(Constants().COUNTRY)}
But I can not find the proper way to get the self.context.get(Constants().COUNTRY) in the serializer.
Do you any have an idea to solve this? Thanks!
Well, I found a solution to my problem: I overwrite the method get_fields in the serializer:
def get_fields(self, *args, **kwargs):
fields = super(SubCategorySerializer, self).get_fields()
country = self.context.get(Constants().COUNTRY)
qs = Category.objects.using(country).all()
fields['category'].queryset = qs
return fields
And that works!

Django Rest Framework depth based on direction

I have two models:
class Organization(models.Model):
name = models.CharField(max_length=64)
class OrgUser(User):
organization = models.ForeignKey(Organization, related_name='users')
role = models.CharField(max_length=1, choices=USER_TYPE_CHOICES)
class UserSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = OrgUser
depth = 1
fields = ('email', 'role', 'organization',)
class OrganizationSerializer(serializers.HyperlinkedModelSerializer):
users = USerSerializer(many=True)
class Meta:
model = Organization
depth = 1
fields = ('name', 'users',)
I'm using the Django REST Framework and I'm trying to get the following output for the given URLS:
GET /organization/
{
'name':'Hello World',
'users':[{ 'email':'test#gmail.com', 'role':'A' }]
}
GET /user/
{
'email':'test#gmail.com',
'role':'A',
'organization':{ 'name':'Hello World' }
}
So what's happening is GET /organization/ is giving me the users array and the organization information again.
I've been racking my brain setting the depth property on my serializer, but I can't figure it out for the life of me. If someone could please point me in the right direction, I'd greatly appreciate it.
The problem is that you want different output from your UserSerializer depending on if it's being used alone (i.e. at GET /user/) or as a nested relation (i.e. at GET /organization/).
Assuming you want different fields in both, you could just create a third Serializer to use for the nested relationship that only includes the fields you want in the OrganizationSerializer. This may not be the most elegant way to do it, but I can't find any alternatives.
Sample code:
class Organization(models.Model):
name = models.CharField(max_length=64)
class OrgUser(User):
organization = models.ForeignKey(Organization, related_name='users')
role = models.CharField(max_length=1, choices=USER_TYPE_CHOICES)
class UserSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = OrgUser
depth = 1
fields = ('email', 'role', 'organization',)
class OrganizationUserSerializer(serializers.HyperlinkedModelSerializer): # New Serializer
class Meta:
model = OrgUser
depth = 1
fields = ('email', 'role',)
class OrganizationSerializer(serializers.HyperlinkedModelSerializer):
users = OrganizationUserSerializer(many=True) # Change to new serializer
class Meta:
model = Organization
depth = 1
fields = ('name', 'users',)

Categories

Resources