Reputation: 543
For example
class People(models.Model):
name = models.CharField(max_length=20)
class Blog(models.Model):
author = models.ForeignKeyField(People)
content = models.TextField()
and then,
class CreateBlogSerializer(serializers.Serializer):
#author id
author = serializers.IntegerField()
content = serializers.TextField()
In views, I need to get author_id , check if the id exists and get the author instance, it's fussy to do that.
serializer = CreateBlogSerializer(data=request.DATA)
if serializer.is_valid():
try:
author = Author.objects.get(pk=serializer.data["author"])
except Author.DoesNotExist:
return Response(data={"author does not exist"})
blog = Blog.objects.create(author=author, content=serializer.data["content"])
Is there a ForeignKeyField to deserialize and validate primarykey data and then return a instance.
class CreateBlogSerializer(serializers.Serializer):
author = serializers.ForeignKeyField(Author)
content = serializers.TextField()
serializer = CreateBlogSerializer(data=request.DATA)
if serializer.is_valid():
#after deserialization , the author id becomes author model instance
blog = Blog.objects.create(author=serializer.data["author"], content=serializer.data["content"])
else:
#the author id does not exist will cause serializer.is_valid=Flase
PS
I knew PrimaryKeyRelatedField in ModelSerializer,but I can't use ModelSerializer here, the model structures are complex, the above are just examples。
My first thought is to write a customer field.
Upvotes: 0
Views: 2040
Reputation: 543
class ForeignKeyField(WritableField):
def __init__(self, model_name, *args, **kwargs):
super(ForeignKeyField, self).__init__(*args, **kwargs)
self.model_name = model_name
self.model_instance = None
def from_native(self, pk):
if not isinstance(pk, int):
raise ValidationError("pk must be int")
try:
self.model_instance = self.model_name.objects.get(pk=pk)
return self.model_instance
except self.model_name.DoesNotExist:
raise ValidationError('object does not exist')
def to_native(self, obj):
return self.model_instance
I hacked it, but I don't konw why it works.
Usage: there is a little difference
class t_serializer(serializers.Serializer):
author = ForeignKeyField(Author)
@api_view(["POST"])
def func(request):
serializer = t_serializer(data=request.DATA)
if serializer.is_valid():
print isinstance(serializer.data["author"], Author)
#print True
else:
print serializer.errors
Upvotes: 1
Reputation: 1981
It appears that what you want is custom validation code.
For this particular instance, you could write the following.
class CreateBlogSerializer(serializers.Serializer):
author = serializers.ForeignKeyField(Author)
content = serializers.TextField()
def validate_author(self, attrs, source):
"""
Verify that the author exists.
"""
author = attrs[source]
if Author.objects.filter(pk=author).exists():
return attrs
raise serializers.ValidationError("Specified Author does not exist!")
Now when you call serializer.is_valid()
this check will occur.
So you can then do this elsewhere in your code,
if serializer.is_valid():
blog = Blog.objects.create(author=serializer.data["author"], content=serializer.data["content"])
And be sure that if the given blog
is created, there is a corresponding Author
already in the DB.
So Django Rest Framework provides a method of adding custom validation to serializers. This can be done with by providing methods of the following format in the serializer class validate_<field name>
. These methods will set the source
value to name of the given field, in our example author
, which can then be used with the attrs
variable to get the current value of the field (attrs
contains all the values passed into the serializer).
These validation methods are each called with then serializer.is_valid()
method is called. They are supposed to just return attrs
if the given test passes, and raise a ValidationError
otherwise.
They can get somewhat complex, so it is probably best if you read the full documentation here, http://www.django-rest-framework.org/api-guide/serializers#validation
Upvotes: 0