I'm very new to ruby and can not understand this situation.
I'm using active_model_serializers to generate model and serializer.
Now after runing
$ rails g resource post title:string body:string
two files was generated.
app/model/post.rb
app/serializers/post_serializer.rb
So far so good.
But why is the model object (post.rb) empty and has no properties?
class Post < ActiveRecord::Base
end
And why the serializer object contains the properties I defined for a model object? I mean serializer -> component which DO serialization
class PostSerializer < ActiveRecord::Base
attributes :id, :title, :body
end
As per documentation in Active Model serializers
The attribute names are a whitelist of attributes to be serialized.
Active Model serializers are means to selectively transform your model into JSON as per API needs, instead of emitting all the attributes of the Active Model model.
Hence, the attributes are explicitly listed in Active Model Serializer classes
Related
I have the following model structure:
class BaseAccount(models.Model):
# some code
class AccountTypeA(BaseAccount):
# some code
class AccountTypeB(BaseAccount):
# some code
Here are my serializers:
class BaseAccountSerializer(serializers.ModelSerializer):
class Meta:
model = BaseAccount
fields = '__all__'
The extended models are defined exactly in the same way.
When I try to serialize the AccountTypeA, I receive back an error stating that the fields from Base account are unknown.
Any idea?
Easy solution to all my problems:
https://pypi.org/project/django-rest-polymorphic/
We can use serializer as a field inside another serializer..
Wonder why there's a Field class and Serializer class in DRF?
class CommentSerializer(serializers.Serializer):
user = UserSerializer()
content = serializers.CharField(max_length=200)
created = serializers.DateTimeField()
example serializer is taken from the doc https://www.django-rest-framework.org/api-guide/serializers/
As you can see, UserSerializer is much like a Field .
I'm just curious why they have serializer and field class separately..
Serilaizer is infact a field in DRF. Serializers can be nested and that is why it can be used as a field in other serializers. And yes, if you check the source code, the BaseSerializer is a subclass of Field as the serializer is just a special case of a field.
In my opinion:
In django rest framwork, you can think Serializer like a mask. It cover your origin data and change it to anything you want. Like format your json data , or validate your input data have correct format or not.
In your example,
content = serializers.CharField(max_length=200)
created = serializers.DateTimeField()
Comment have 2 direct field type CharField and DateTimeField.
user = UserSerializer()
Comment have field type is UserSerializer. This is different Serializer, and django know your CommentSerializer will have relationship with UserSerializer. And anything define in UserSerializer will use in here, for format json output or validate. And with define this nested objects, your output json will have more data like
'user': {'email': 'foobar', 'username': 'doe'}
And if you want create Comment with one user, you must pass all validate define in UserSerializer.
Conclude: in this example
Field class use for direct field.
Serializer class for relationship with other class
I have this code that brings one vacancy from my model Vacancy and then render in json the attributes according to the serializer VacancyDetailSerializer:
Controller
vacancy = Vacancy.find(params[:id])
render json: vacancy, serializer: VacancyDetailSerializer,
include: [:restaurant]
The thing here is that in the include: [:restaurant] I want to specify a custom serializer the way I did with vacancy, because right now is taking the serializer of RestaurantSerializer, but I don't want to take that file, is there a way to do it with the include? Maybe is here in the controller, or maybe in the serializer?
If you have belongs_to :restaurant association in the VacancyDetailSerializer, then serializer for this association can be specified:
class VacancyDetailSerializer < ActiveModel::Serializer
belongs_to :restaurant, serializer: AnotherRestaurantSerializer
end
Or it can be overridden by providing a block:
class VacancyDetailSerializer < ActiveModel::Serializer
belongs_to :restaurant do
AnotherRestaurantSerializer.new(object.restaurant)
end
end
Or a custom association serializer lookup can be implemented.
I have a json response from a web request which almost maps to my django model.
How do I serialize this json(preferably with a model serializer),but override one field, so I can map it to a differently named field on the Django model. (I have one field "expected_value" in the json object, but I want to map that to the "actual_value" of my Django model).
You can add extra fields to a ModelSerializer or override the default fields by declaring fields on the class, just as you would for a Serializer class.
Something like the code snippet below should work.
class MySerializer(serializers.ModelSerializer):
expected = serializers.Field(source='actual')
class Meta:
model = MyModel
fields = ('field1', 'field2', 'expected')
I have two related models and serializers for both of them. When I am serializing one of these models (the serializer has a depth of 1) the result includes some fields from the related object that should't be visible. How an I specify which serializer to use for the relation? Or is there anyway to tell Rest Framework to exclude some fields from the related object?
Thank you,
I think one way would be to create an extra serializer for the model where you want to return only limited number of fields and then use this serializer in the serializer of the other model. Something like this:
class MyModelSerializerLimited(serializers.ModelSerializer):
class Meta:
model = MyModel
fields = ('field1', 'field2') #fields that you want to display
Then in the other serializer use the MyModelSerializerLimited:
class OtherModelSerializer(serializers.ModelSerializer):
myfield = MyModelSerializerLimited()
class Meta:
model = OtherModel
fields = ('myfield', ...)
depth = 1
You could override restore_fields method on serializer. Here in restore_fields method you can modify list of fields - serializer.fields - pop, push or modify any of the fields.
eg: Field workspace is read_only when action is not 'create'
class MyPostSerializer(ModelSerializer):
def restore_fields(self, data, files):
if (self.context.get('view').action != 'create'):
self.fields.get('workspace').read_only=True
return super(MyPostSerializer, self).restore_fields(data, files)
class Meta:
model = MyPost
fields = ('id', 'name', 'workspace')