Django rest framework get or create for PrimaryKeyRelatedField - django

I start to create REST API for my web-application with Django and Django rest framework and I need one logic problem.
There are entities Instruction and Tag. The user visit my service and create self Instruction and add exists Tag OR new Tag for it.
I created my model seriallizer class with using PrimaryKeyRelatedField for relation Instruction<->Tag. But if I do POST for a new Instruction with new Tag I got error: "Invalid pk \"tagname\" - object does not exist.".
I solved this problem with the overriding of the to_internal_value method in my field class.
What is the best practice for solving this problem? It seems to me this problem is typical for web and REST API.
My models:
class Tag(Model):
name = CharField(max_length=32, verbose_name=_("Name"),
unique=True, validators=[alphanumeric], primary_key=True)
def __str__(self):
return self.name
class Instruction(Model):
user = ForeignKey(settings.AUTH_USER_MODEL,
related_name='instructions',
on_delete=CASCADE,
blank=False, null=False,
verbose_name=_("User"))
title = CharField(max_length=256,
verbose_name=_("Title"),
blank=False, null=False)
created_datetime = DateTimeField(verbose_name=_("Creation time"), editable=False)
modified_datetime = DateTimeField(
verbose_name=_("Last modification time"), blank=False, null=False)
tags = ManyToManyField(Tag,
related_name="instructions",
verbose_name=_("Tags"))
class Meta:
ordering = ['-created_datetime']
# singular_name = _("")
def save(self, force_insert=False, force_update=False, using=None,
update_fields=None):
n = now()
if self.id is None:
self.created_datetime = n
self.modified_datetime = n
super(Instruction, self).save(force_insert, force_update, using, update_fields)
def __str__(self):
return self.title
my serializers:
class TagSerializer(serializers.ModelSerializer):
class Meta:
model = Tag
fields = ('name',)
class InstructionSerializer(serializers.ModelSerializer):
tags = PrimaryKeyCreateRelatedField(many=True, queryset=Tag.objects.all())
author = serializers.SerializerMethodField()
def get_author(self, obj):
return obj.user.username
class Meta:
model = Instruction
fields = ('id', 'user', 'title', 'created_datetime', 'modified_datetime', 'tags', 'author')
read_only_fields = ('modified_datetime',)
I created new field class class PrimaryKeyCreateRelatedField and overrided to_internal_value method for creating the new Tag object instead raising with message 'does_not_exist':
PrimaryKeyCreateRelatedField(serializers.PrimaryKeyRelatedField):
def to_internal_value(self, data):
if self.pk_field is not None:
data = self.pk_field.to_internal_value(data)
try:
return self.get_queryset().get(pk=data)
except ObjectDoesNotExist:
# self.fail('does_not_exist', pk_value=data)
return self.get_queryset().create(pk=data)
except (TypeError, ValueError):
self.fail('incorrect_type', data_type=type(data).__name__)
my view:
class InstructionViewSet(viewsets.ModelViewSet):
queryset = Instruction.objects.all()
serializer_class = InstructionSerializer
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
def create(self, request, *args, **kwargs):
data = dict.copy(request.data)
data['user'] = self.request.user.pk
serializer = InstructionSerializer(data=data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
Update
models.py
alphanumeric = RegexValidator(r'^[0-9a-zA-Z]*$',
_('Only alphanumeric characters are allowed.'))
class Tag(Model):
name = CharField(max_length=32, verbose_name=_("Name"),
unique=True, validators=[alphanumeric], primary_key=True)
def __str__(self):
return self.name
class Step(PolymorphicModel):
instruction = ForeignKey(Instruction,
verbose_name=_("Instruction"),
related_name='steps',
blank=False, null=False,
on_delete=CASCADE)
position = PositiveSmallIntegerField(verbose_name=_("Position"), default=0)
description = TextField(verbose_name=_("Description"),
max_length=2048,
blank=False, null=False)
class Meta:
verbose_name = _("Step")
verbose_name_plural = _("Steps")
ordering = ('position',)
unique_together = ("instruction", "position")
def __str__(self):
return self.description[:100]
class Instruction(Model):
user = ForeignKey(settings.AUTH_USER_MODEL,
related_name='instructions',
on_delete=CASCADE,
blank=False, null=False,
verbose_name=_("User"))
title = CharField(max_length=256,
verbose_name=_("Title"),
blank=False, null=False)
created_datetime = DateTimeField(verbose_name=_("Creation time"), editable=False)
modified_datetime = DateTimeField(
verbose_name=_("Last modification time"), blank=False, null=False)
tags = ManyToManyField(Tag,
related_name="instructions",
verbose_name=_("Tags"))
# thumbnail = #TODO: image field
class Meta:
ordering = ['-created_datetime']
# singular_name = _("")
def save(self, force_insert=False, force_update=False, using=None,
update_fields=None):
n = now()
if self.id is None:
self.created_datetime = n
self.modified_datetime = n
super(Instruction, self).save(force_insert, force_update, using, update_fields)
def __str__(self):
return self.title
views.py
class InstructionViewSet(viewsets.ModelViewSet):
queryset = Instruction.objects.all()
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
def get_serializer_class(self):
"""Return different serializer class for different action."""
if self.action == 'list':
return InstructionSerializer
elif self.action == 'create':
return InstructionCreateSerializer
serialiers.py
class PrimaryKeyCreateRelatedField(serializers.PrimaryKeyRelatedField):
def to_internal_value(self, data):
if self.pk_field is not None:
data = self.pk_field.to_internal_value(data)
try:
return self.get_queryset().get(pk=data)
except ObjectDoesNotExist:
# self.fail('does_not_exist', pk_value=data)
return self.get_queryset().create(pk=data)
except (TypeError, ValueError):
self.fail('incorrect_type', data_type=type(data).__name__)
class InstructionCreateSerializer(serializers.ModelSerializer):
tags = PrimaryKeyCreateRelatedField(many=True, queryset=Tag.objects.all())
steps = InstructionStepSerializer(many=True)
user = serializers.HiddenField(default=serializers.CurrentUserDefault())
class Meta:
model = Instruction
fields = ('id', 'user', 'title', 'created_datetime', 'modified_datetime', 'tags', 'steps')
read_only_fields = ('modified_datetime',)
def create(self, validated_data):
tags_data = validated_data.pop('tags')
steps_data = validated_data.pop('steps')
# NOTE: tags need add after creation of the Instruction object otherwise we will got exception:
# "needs to have a value for field "id" before this many-to-many relationship can be used."
instruction = Instruction.objects.create(**validated_data)
for tag in tags_data:
instruction.tags.add(tag)
for step in steps_data:
Step.objects.create(instruction=instruction,
description=step['description'],
position=step['position'])
return instruction
class InstructionSerializer(serializers.ModelSerializer):
tags = serializers.StringRelatedField(many=True)
author = serializers.SerializerMethodField()
steps = InstructionStepSerializer(many=True)
def get_author(self, obj):
return obj.user.username
class Meta:
model = Instruction
fields = ('id', 'user', 'title', 'created_datetime', 'modified_datetime', 'tags', 'author', 'steps')
read_only_fields = ('modified_datetime',)

In my case to solve the problem I need to override the method run_validation. That allow make check of tags and create their (if not exists) before validation.
class InstructionCreateSerializer(serializers.ModelSerializer):
steps = InstructionStepSerializer(many=True)
user = serializers.HiddenField(default=serializers.CurrentUserDefault())
class Meta:
model = Instruction
fields = ('title', 'created_datetime', 'modified_datetime', 'tags', 'steps', 'id', 'user')
read_only_fields = ('modified_datetime',)
def run_validation(self, data=serializers.empty):
if 'tags' in data:
for tag in data['tags']:
Tag.objects.get_or_create(name=tag)
return super(InstructionCreateSerializer, self).run_validation(data)
def create(self, validated_data):
tags_data = validated_data.pop('tags')
steps_data = validated_data.pop('steps')
# NOTE: tags need add after creation of the Instruction object otherwise we will got exception:
# "needs to have a value for field "id" before this many-to-many relationship can be used."
instruction = Instruction.objects.create(**validated_data)
for tag in tags_data:
instruction.tags.add(tag)
for step in steps_data:
Step.objects.create(instruction=instruction,
description=step['description'],
position=step['position'])
return instruction

Apart from the answers given by #YPCrumble and #SijanBhandari, I just had to comment on something in your code.
In the models.py, you have overridden the save method for adding created_at and modified_on. For that you could just add
created_at = models.DateTimeField(auto_now_add=True)
modified_on = DateTimeField (auto_now=True)
The auto_now_add option sets when the object is created for the first time.
It's not editable. The auto_now setting sets whenever the object is saved, ie, whenever object.save() method is called upon.
These usually are used for timestamping the objects for future references.
Why write so many lines, when you could do this on just 2 lines of code.
Just a heads up though!!
For further details, go to the documentation here

In "regular" Django you usually want to create your model instance in the form's save method, not the view. DRF is similar, in that you want to create your model instances in the serializer's create or update methods. The reason for this is that if you need to add a new endpoint to your API you can reuse the serializer and would not have to write duplicate code creating or updating your model instance.
Here's how I'd refactor your code:
Remove the entire create method from your ModelViewSet - you don't need to override that.
Remove the custom PrimaryKeyCreateRelatedField - you just need a PrimaryKeyRelatedField
Add two methods to your serializer - create and update:
In the create method, create your tag objects before saving the instruction object like you can see in the DRF docs. You can get the current user like you were doing in your view via self.context['request'].user in this create method. So you might create the Instruction like Instruction.objects.create(user=self.context['request'].user, **validated_data) and then loop through the tags (like they do for tracks in the docs) to add them to the Instruction.
The docs don't have an example update method but essentially your update method also takes an instance parameter for the existing instruction. See this answer from the creator of DRF for more details

The best way would be sort out everything at your CREATE method of the view.
I believe you tags will be sent from your front-end to the back-end at the format of
[ 1,
{'name': "TEST"},
{'name': 'TEST2'}
]
Here '1' is the existing tag id and 'TEST' and 'TEST2' are the two new tags inserted by
the user. Now you can change your CREATE method as follows:
class InstructionViewSet(viewsets.ModelViewSet):
queryset = Instruction.objects.all()
serializer_class = InstructionSerializer
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
def create(self, request, *args, **kwargs):
data = dict.copy(request.data)
data['user'] = self.request.user.pk
# MODIFICATION.....
tags = self.request.get('tags', None)
tag_list = []
if tags:
for tag in tags:
if isinstance(tag, dict):
new_tag = Tag.objects.create(name=tag['name'])
tag_list.append(new_tag.id)
else:
tag_list.append(int(tag))
data = {
'title': ....
'tags': tag_list,
'user': ...
'author': ...
......
}
serializer = InstructionSerializer(data=data)
I hope it will be helpful for you.

Related

Use same serializer class but with different action in a view in Django rest framework

I have a modelset view in which different customs functions are defined based on the requirement. I have to write another get function in which I want to use the same serializer class. But the field which I have defined in the serializer class in pkfield but for the get function, I want it as a stringfield rather than pk field. How to achieve that??
Also, I have defined depth=1, which is also not working.
class Class(TimeStampAbstractModel):
teacher = models.ForeignKey(
Teacher,
on_delete=models.CASCADE,
null=True,
related_name="online_class",
)
subject = models.ForeignKey(
Subject,
on_delete=models.SET_NULL,
null= True,
related_name= "online_class",
)
students_in_class = models.ManyToManyField(Student, related_name="online_class")
My view:
class ClassView(viewsets.ModelViewSet):
queryset = Class.objects.all()
serializer_class = ClassSerializer
serializer_action_classes = {
'add_remove_students': AddStudentstoClassSerializer,
'get_all_students_of_a_class': AddStudentstoClassSerializer,
}
def get_serializer_class(self):
"""
returns a serializer class based on the action
that has been defined.
"""
try:
return self.serializer_action_classes[self.action]
except (KeyError, AttributeError):
return super(ClassView, self).get_serializer_class()
def add_remove_students(self, request, *args, **kwargs):
"""
serializer class used is AddStudentstoClassSerializer
"""
def get_all_students_of_a_class(self,request,pk=None):
"""
for this I function too, I want to use the same AddStudentstoClassSerializer class but
there is a problem. The field students_in_class is already defined as pkfield, whereas I
want to use it as a stringfields in the response of this function
""""
My serializer:
class AddStudentstoClassSerializer(serializers.ModelSerializer):
students_in_class = serializers.PrimaryKeyRelatedField(
many=True, queryset=Student.objects.all()
)
class Meta:
model = Class
fields = ["students_in_class"]
depth = 1
def update(self, instance, validated_data):
slug = self.context["slug"]
stu = validated_data.pop("students_in_class")
/................other codes....../
return instance
Here we can see the student_in_class is defined as pkfield which is ok when using the update api, but when I want to use the get api and call get_all_students_of_a_class I want the field to be stringfield or some other field. How to do that? Also depth= 1 is also not working.
Update:
Treid the following but still not working:
def to_representation(self, instance):
rep = super().to_representation(instance)
# rep["students_in_class"] = instance.students_in_class
rep['students_in_class'] = StudentSerializer(instance.students_in_class).data
return rep
class StudentSerializer(serializers.ModelSerializer):
user = serializers.PrimaryKeyRelatedField(read_only=True)
class Meta:
model = Student
fields = ['user', 'college_name', 'address']
what i got in the response is
{
"students_in_class": {}
}
it is empty dict. what should be done!
You can override you to_representation method like this.
class AddStudentstoClassSerializer(serializers.ModelSerializer):
students_in_class = serializers.PrimaryKeyRelatedField(
many=True, queryset=Student.objects.all()
)
class Meta:
model = Class
fields = ["students_in_class"]
def to_representation(self, instance):
data = {
"students_in_class": # Write your logic here
}
return data
def update(self, instance, validated_data):
slug = self.context["slug"]
stu = validated_data.pop("students_in_class")
/................other codes....../
return instance

Multiple Queries For Inline instances Django admin

I have created a custom Admin for one of my model. And added a Relational table as one of its inline.
1). Now the thing is that Inline has over a 100 rows. And the inline further has a foreign key object to some other model.
2).Whenever i load the model form it takes a whole lot of time to Load.
3).I debugged and checked the code and number of queries. No query was duplicated and the count was nominal.
4).I have overridden the query set for the inline instance to prefetch its foreign key instance.
5).I went on and raised a random validation error in the formset's clean.
6).What i found out that when the error was raised it had a different query for every inline instance. Say if it has a 100 rows then the query was duplicated 100 times for that inline.
7).Is there any way to prefetch or optimize this scenario as its causing way too lag in my application
Here's the Code:
#model
class MyModel(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
phone_number = models.CharField(max_length=10)
entity1 = models.ForeignKey("entities.entity1", null=True, blank=True, on_delete=models.CASCADE)
entity2 = models.ForeignKey("entities.entity2", null=True, blank=True, on_delete=models.CASCADE)
is_disabled = models.BooleanField(default=False)
name = models.CharField(max_length=24, blank=True, null=True)
class Meta:
db_table = 'my_model'
def __str__(self):
return "{}:{}".format(self.phone_number, self.entity2)
#admin
class Entity2Admin(admin.GeoModelAdmin, VersionAdmin):
list_filter = ('data_status')
readonly_fields = ('source', 'batch','is_live', )
exclude = ('search_key', 'live_at', 'qc_approved_at')
def save_formset(self, request, form, formset, change):
instances = formset.save(commit=False)
for obj in formset.deleted_objects:
obj.delete()
for instance in instances:
if isinstance(instance, MyModel):
if (not instance.created_by):
instance.created_by = request.user
if (not instance.id):
instance.some_field = some_value
instance.save()
formset.save_m2m()
inlines = [MyModelInline]
extra_js = ['js/admin/GoogleMap.js','https://maps.googleapis.com/maps/api/js?key=AIzaSyA-5gVhxxxxxxxxxxxxxxxxxxxxxxx&callback=initGoogleMap']
#MyModelInline
class MyModelInline(admin.TabularInline):
model = MyModel
extra = 0
can_delete = True
show_change_link = False
formset = MyModelFormSet
readonly_fields = ['user']
verbose_name_plural = "MyModels"
fields = ['phone_number', 'name', 'user', 'entity2']
def get_queryset(self, request):
return super(MyModelInline, self).get_queryset(request).select_related('entity2', 'user')
def formfield_for_foreignkey(self, db_field, request, **kwargs):
if db_field.name == "entity2":
object_id = request.resolver_match.kwargs.get('object_id')
kwargs["queryset"] = Entity2.objects.filter(field=value)
return super().formfield_for_foreignkey(db_field, request, **kwargs)
Please help

How to join models in Python djangorestframework

I am trying to joint two models in django-rest-framework.
My code isn't throwing any error but also it isn't showing other model fields that need to be joined.
Below is my code snippet:
Serializer:
class CompaniesSerializer(serializers.ModelSerializer):
class Meta:
model = Companies
fields = ('id', 'title', 'category')
class JobhistorySerializer(serializers.ModelSerializer):
companies = CompaniesSerializer(many=True,read_only=True)
class Meta:
model = Jobhistory
fields = ('id', 'title', 'company_id', 'companies')
View .
class UserJobs(generics.ListAPIView):
serializer_class = JobhistorySerializer()
def get_queryset(self):
user_id = self.kwargs['user_id']
data = Jobhistory.objects.filter(user_id=user_id)
return data
model:
class Companies(models.Model):
id = models.AutoField(primary_key=True)
title = models.CharField(max_length=100, blank=True, default='')
category = models.CharField(max_length=30, blank=True, default='')
created = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ('created',)
def save(self, *args, **kwargs):
title = self.title or False
category = self.category or False
super(Companies, self).save(*args, **kwargs)
class Jobhistory(models.Model):
id = models.AutoField(primary_key=True)
company_id = models.ForeignKey(Companies)
title = models.CharField(max_length=100, blank=True, default='')
created = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ('created',)
def save(self, *args, **kwargs):
company_id = self.company_id or False
title = self.title or False
super(Jobhistory, self).save(*args, **kwargs)
Thanks in advance. Any help will be appreciated.
In your views, you have
serializer_class = JobHistorySerializer()
Remove the parenthesis from this.
The reason for this is apparent in the GenericAPIView, specifically the get_serializer() and get_serializer_class() methods:
def get_serializer(self, *args, **kwargs):
"""
Return the serializer instance that should be used for validating and
deserializing input, and for serializing output.
"""
serializer_class = self.get_serializer_class()
kwargs['context'] = self.get_serializer_context()
return serializer_class(*args, **kwargs)
def get_serializer_class(self):
"""
Return the class to use for the serializer.
Defaults to using `self.serializer_class`.
You may want to override this if you need to provide different
serializations depending on the incoming request.
(Eg. admins get full serialization, others get basic serialization)
"""
assert self.serializer_class is not None, (
"'%s' should either include a `serializer_class` attribute, "
"or override the `get_serializer_class()` method."
% self.__class__.__name__
)
return self.serializer_class
As you can see in get_serializer, it initializes that serializer class with args and kwargs that aren't provided in your view code.

This QueryDict instance is immutable

I have a Branch model with a foreign key to account (the owner of the branch):
class Branch(SafeDeleteModel):
_safedelete_policy = SOFT_DELETE_CASCADE
name = models.CharField(max_length=100)
account = models.ForeignKey(Account, null=True, on_delete=models.CASCADE)
location = models.TextField()
phone = models.CharField(max_length=20, blank=True,
null=True, default=None)
create_at = models.DateTimeField(auto_now_add=True, null=True)
update_at = models.DateTimeField(auto_now=True, null=True)
def __str__(self):
return self.name
class Meta:
unique_together = (('name','account'),)
...
I have a Account model with a foreign key to user (one to one field):
class Account(models.Model):
_safedelete_policy = SOFT_DELETE_CASCADE
name = models.CharField(max_length=100)
user = models.OneToOneField(User)
create_at = models.DateTimeField(auto_now_add=True)
update_at = models.DateTimeField(auto_now=True)
def __str__(self):
return self.name + ' - ' + self.create_at.strftime('%Y-%m-%d %H:%M:%S')
I've created a ModelViewSet for Branch which shows the branch owned by the logged in user:
class BranchViewSet(viewsets.ModelViewSet):
serializer_class = BranchSerializer
permission_classes = (permissions.IsAuthenticated,)
def get_queryset(self):
queryset = Branch.objects.all().filter(account=self.request.user.account)
return queryset
Now to create a new branch, I want to save account field with request.user.account, not with data sent from the rest client (for more security). for example:
def create(self, request, *args, **kwargs):
if request.user.user_type == User.ADMIN:
request.data['account'] = request.user.account
return super(BranchViewSet, self).create(request, *args, **kwargs)
def perform_create(self, serializer):
'''
Associate branch with account
'''
serializer.save(account=self.request.user.account)
In branch serializer
class BranchSerializer(serializers.ModelSerializer):
account = serializers.CharField(source='account.id', read_only=True)
class Meta:
model = Branch
fields = ('id', 'name', 'branch_alias',
'location', 'phone', 'account')
validators = [
UniqueTogetherValidator(
queryset=Branch.objects.all(),
fields=('name', 'account')
)
]
but I got this error:
This QueryDict instance is immutable. (means request.data is a immutable QueryDict and can't be changed)
Do you know any better way to add additional fields when creating an object with django rest framework?
As you can see in the Django documentation:
The QueryDicts at request.POST and request.GET will be immutable when accessed in a normal request/response cycle.
so you can use the recommendation from the same documentation:
To get a mutable version you need to use QueryDict.copy()
or ... use a little trick, for example, if you need to keep a reference to an object for some reason or leave the object the same:
# remember old state
_mutable = data._mutable
# set to mutable
data._mutable = True
# сhange the values you want
data['param_name'] = 'new value'
# set mutable flag back
data._mutable = _mutable
where data it is your QueryDicts
Do Simple:
#views.py
from rest_framework import generics
class Login(generics.CreateAPIView):
serializer_class = MySerializerClass
def create(self, request, *args, **kwargs):
request.data._mutable = True
request.data['username'] = "example#mail.com"
request.data._mutable = False
#serializes.py
from rest_framework import serializers
class MySerializerClass(serializers.Serializer):
username = serializers.CharField(required=False)
password = serializers.CharField(required=False)
class Meta:
fields = ('username', 'password')
request.data._mutable=True
Make mutable true to enable editing in querydict or the request.
I personally think it would be more elegant to write code like this.
def create(self, request, *args, **kwargs):
data = OrderedDict()
data.update(request.data)
data['account'] = request.user.account
serializer = self.get_serializer(data)
serializer.is_valid(raise_exception=True)
self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
Do you know any better way to add additional fields when creating an object with django rest framework?
The official way to provide extra data when creating/updating an object is to pass them to the serializer.save() as shown here
https://docs.djangoproject.com/en/2.0/ref/request-response/#querydict-objects
The QueryDicts at request.POST and request.GET will be immutable when accessed in a normal request/response cycle. To get a mutable version you need to use QueryDict.copy().
You can use request=request.copy() at the first line of your function.

Find where in Django code an 'incorrect type error' is being thrown for a POST

I am trying to discover where in my Django code an incorrect type error message is being thrown:
{"_body":"{\"keywords\":[\"Incorrect type. Expected pk value, received str.\"]}","status":400,"statusText":"Ok","headers":{"Content-Type":["application/json;q=0.8"]},"type":2,"url":"http://127.0.0.1:8000/api/items/"}
I have put a breakpoint in the view's perform_create that handles the POST but this is never executed.
Anyone know where in my code I should set a breakpoint to take a look at what is happening?
My view looks like this:
class ItemViewSet(viewsets.ModelViewSet):
queryset = Item.objects.all().order_by('-date_added')
serializer_class = ItemSerializer
def list(self, request, *args, **kwargs):
this_user = self.request.query_params.get('user', None)
count_of_views = Seen.objects.filter(who_saw=this_user).count()
custom_data = {
'results': ItemSerializer(self.get_queryset(), many=True).data
}
custom_data.update({
'views': count_of_views
})
return Response(custom_data)
def perform_create(self, serializer):
creator = User.objects.get(pk=self.request.data['owner_id'])
the_keywords = self.request.data['keywords'].split
serializer.save(owner=creator)
#serializer.save(keywords=the_keywords)
EDIT: And the serializer is:
class ItemSerializer(serializers.ModelSerializer):
username = serializers.SerializerMethodField()
def get_username(self, obj):
value = str(obj.owner)
return value
def get_keywords(self, obj):
value = str(obj.keywords)
return value
class Meta:
model = Item
fields = ('id', 'url', 'item_type', 'title', 'keywords')
EDIT Item model is:
class Item(models.Model):
owner = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(max_length=60, default='')
url = models.CharField(max_length=250, default='', unique=True)
keywords = models.ManyToManyField(Keyword, related_name='keywords')
Keyword model is:
class Keyword(models.Model):
name = models.CharField(max_length=30)
def __str__(self):
return format(self.name)