how to customize fields in nested serializer? - python

class ListSerializer(serializers.ModelSerializer):
user = UserSerializer()
class Meta:
model = JobseekerProfile
fields = ('user',)
*How to modify this fields so that I can add only one field from user like user.username? *

You can add ReadOnlyField Field in the serializer. This field only use when you try to retrieve your data. (GET method)
class ListSerializer(serializers.ModelSerializer):
user = serializers.ReadOnlyField(source='user.username')
class Meta:
model = JobseekerProfile
fields = ('user',)

class ListSerializer(serializers.ModelSerializer):
user = serializers.CharField(read_only=True, source='user.username')
class Meta:
model = JobseekerProfile
fields = ('user',)
Try it

Related

DRF Read only field is still validated

I have a field that I want always to be the user. My serializer is like this:
class MySerializer(serializers.ModelSerializer):
class Meta:
model = MyModel
fields = '__all__'
read_only_fields = ('user',)
def perform_save(self, serializer):
serializer.save(user=self.request.user)
class MyModel(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
...
But it gives me the error NOT NULL constraint failed: app_my_model.user_id but the field is read_only... I don't get this.
First of all, there is no method named perform_save() for a serializer, it's for the viewset class. This may be the problem
Use the save() method as below
class MySerializer(serializers.ModelSerializer):
class Meta:
model = MyModel
fields = '__all__'
read_only_fields = ('user',)
def save(self, **kwargs):
kwargs['user'] = self.context['request'].user
return super().save(**kwargs)

Django Rest Framework Serializer Doesn't Display ALL Fields

I have a problem where DRF isn't displaying all of my fields correctly for a model class / reference table (specifically the primary key).
My Model Class looks like this (very simple):
class UnitOfIssue(models.Model):
code = models.CharField(max_length=2, primary_key=True)
description = models.CharField(max_length=16)
class Meta:
ordering = ('code',)
def __str__(self):
return "{0} - {1}".format(self.code, self.description)
My Serializer Looks like this:
class UnitOfIssueSerializer(serializers.HyperlinkedModelSerializer):
"""
"""
url = serializers.HyperlinkedIdentityField(
read_only=True,
view_name='unitofissue-detail',
format='html',
lookup_field='code')
class Meta:
model = UnitOfIssue
fields = ('code', 'description', 'url')
# fields = '__all__'
And I'm using a generic view:
class UnitOfIssueDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = UnitOfIssue.objects.all()
serializer_class = UnitOfIssueSerializer
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
lookup_field = 'code'
In order for the UnitOfIssue primary key code to be displayed in the auto-generated UI, I have to define fields = ('code', 'description', 'url') in the serializer instead of fields = '__all__'.
I want to just be able to use the '__all__' syntax but I can't figure out what's going wrong.
Also, I'm using Django==1.11.13 and djangorestframework==3.8.2
This issue plagued me for weeks, and yet it was such a simple error. I fixed it by changing the serializer base class from:
class UnitOfIssueSerializer(serializers.HyperlinkedModelSerializer):
to:
class UnitOfIssueSerializer(serializers.ModelSerializer):

Lack of data with serialization model with ManyToManyField

Here's are examples I have:
models.py:
class Example(models.Model):
title = models.CharField(...)
description = models.CharField(...)
class Foo(models.Model):
example = models.ManyToManyField(Example)
serializers.py:
class FooSerializer(serializers.ModelSerializer):
class Meta:
model = Foo
fields = '__all__'
depth = 1
views.py:
...
serialized_data = [FooSerializer(foo).data for foo in Foo.objects.all().get]
In output, I receive only Example's IDs, but is there any way I could get title and description fields also (details of m2mfield)? As I understand, Foo.objects.all().get simply doesn't contain this data, but maybe I could somehow get it and use it?
I could also rebuild models if needed, but currently I use m2mf because of needs to contain multiple objects as related to this model data.
update
models.py:
class Event(models.Model):
ts = models.BigIntegerField(editable=False)
class Foo(Event):
user = models.ForeignKey(User, ...)
example = *...(remains to be the same)*
foos = models.ForeignKey('self', **somemore** null=True)
serializers.py:
class EventSerializer(serializers.ModelSerializer):
class Meta:
model = Event
fields = '__all__'
def to_representation(self, instance):
result = {'ts': instance.ts}
if isinstance(instance, Foo):
result['foo'] = FooSerializer(instance).data
return result
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id', 'username')
class FooSerializer(serializers.ModelSerializer):
# user = UserSerializer(read_only=True) # with this I have an error: Got AttributeError when attempting to get a value for field 'username' on #serializer 'UserSerializer'
class Meta:
model = Foo
fields = '__all__'
depth = 1
You could use depth attribute to achieve desired output.
The default ModelSerializer uses primary keys for relationships, but
you can also easily generate nested representations using the depth
option.The depth option should be set to an integer value that
indicates the depth of relationships that should be traversed before
reverting to a flat representation.
class FooSerializer(serializers.ModelSerializer):
class Meta:
model = Foo
fields = '__all__'
depth = 1
Apart from the answer, I would like to change your views.py code, cause it seems like very bad :(. Do it on DRF Way as
serialized_data = FooSerializer(Foo.objects.all(), many=True).data<br>
Example View
from rest_framework.viewsets import ModelViewSet
class FooViewset(ModelViewSet):
serializer_class = FooSerializer
queryset = Foo.objects.all()
UPDATE-1
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
exclude = ('password',) # add fields that are need to be excluded
class FooSerializer(serializers.ModelSerializer):
user = UserSerializer()
class Meta:
model = Foo
fields = '__all__'
depth = 1
depth = 1 will serializer all fields in the model, (It's same as setting the fields=='__all__' in Meta class of serializer)
UPDATE-2
class FooSerializer(serializers.ModelSerializer):
user = UserSerializer()
class Meta:
model = Foo
fields = '__all__'
depth = 1
def to_representation(self, instance):
real_data = super().to_representation(instance).copy()
# DO YOUR EXTRA CHECKS
child = UserSerializer(instance.child_foo).data
if child:
real_data.update({"child_data": child})
# After your checks, add it to "real_data"
return real_data
and I assumed I have a Foo model as
class Foo(models.Model):
example = models.ManyToManyField(Example)
user = models.ForeignKey(User)
child_foo = models.ForeignKey('self', null=True, blank=True)
In your serializer add depth = 1. Example where 'users' is the related field:
FooSerializer(serializers.ModelSerializer):
class Meta:
model = Foo
fields = ('id', 'account_name', 'users', 'created')
depth = 1

Django CreateView - Display only particular objects in foreignkey field

I have a CreateView view that holds a bunch of fields that need to be filled by the user when creating a new contact. Now, I want the user to be able to see and choose only from the categories that they'd created.
This is the model of Category:
class Category(models.Model):
class Meta:
verbose_name = _('category')
verbose_name_plural = _('categories')
name = models.CharField(max_length=100, unique=True)
profile = models.ForeignKey(Profile, on_delete=models.CASCADE)
def __unicode__(self):
return self.name
This is the view:
class ContactCreate(LoginRequiredMixin, generic.edit.CreateView):
model = models.Contact
success_url = reverse_lazy('site:contacts')
fields = ['firstname', 'lastname', 'phone1', 'phone2', 'email', 'city', 'category']
template_name = 'site/contacts.html'
context_object_name = 'all_contacts'
What I need the user to see is a select that has only the categories which include the appropriate profile foreign key associated with them.
I'd be glad to get some help with this. Thank you!
You can override the get_form method of the view and set the queryset of the appropriate field:
class ContactCreate(LoginRequiredMixin, generic.edit.CreateView):
# ...
def get_form(self, *args, **kwargs):
form = super(ContactCreate, self).get_form(*args, **kwargs)
form.fields['categories'].queryset = Category.objects.filter(profile=self.request.user.profile)
return form
This, of course, assumes that your Profile model has a OneToOneField to User with related_name 'profile', otherwise you'd have to adjust the filtering.

Pass extra arguments to nested Serializer in Django Rest Framework

I have such serializer:
class FirstModelSerializer(serializers.ModelSerializer):
secondModel = SecondModelSerializer()
class Meta:
model = FirstModel
fields = '__all__'
Where secondModel is ManyToMany field of FirstModel.
Is there any way to pass FirstModel object id to SecondModelSerializer?
It was easier then I thought. I just had to use context like this
class FirstModelSerializer(serializers.ModelSerializer):
secondModel = SerializerMethodField()
class Meta:
model = FirstModel
fields = '__all__'
def get_secondModel(self, obj):
return SecondModelSerializer(obj.secondModel.all(), many=True, context={'first_model_id': obj.id)).data
And use self.context.get('first_model_id') in SecondModelSerializer to get to this id.

Categories