Firstly, I would like to mention that I've already seen many SO posts about this issue, but still couldn't figure out the problem occurring here. I would like to POST a JSON object to my Django application, which looks like this:
{
"id": "1363362773409783808",
"text": "@MsLaydeeLala Damn haha. Reminds me of my dog. If someone comes into my room while I\u2019m sleeping he gets up and growls at them if he doesn\u2019t recognize them right away.",
"created_at": "2021-02-21T05:39:49.000Z",
"author": {
"id": "112233445566778899",
"username": "Elrafa559",
"name": "EL RAFA"
},
"keywords": [
{
"name": "dog"
}
]
}
and save it to my database, where my models are:
class Keyword(models.Model):
"""
Represents keywords which we are looking for, must be unique, 20 chars max.
"""
name = models.CharField(max_length=20, unique=True)
def __str__(self):
return self.name
class TwitterAccount(models.Model):
id = models.CharField(max_length=20, primary_key=True)
username = models.CharField(max_length=80)
name = models.CharField(max_length=80)
class Tweet(models.Model):
id = models.CharField(max_length=20, primary_key=True)
text = models.CharField(max_length=380) # 280 for tweet, 100 for links
created_at = models.DateTimeField()
author = models.ForeignKey(TwitterAccount, on_delete=models.CASCADE)
keywords = models.ManyToManyField(Keyword)
def __str__(self):
return str(self.author.username) + "/" + str(self.id)
class TweetKeyword(models.Model):
# TODO is CASCADE the right choice?
tweet = models.ForeignKey(Tweet, on_delete=models.CASCADE)
keyword = models.ForeignKey(Keyword, on_delete=models.CASCADE)
for that, I've written this serializer:
class TweetSerializer(serializers.ModelSerializer):
author = TwitterAccountSerializer()
keywords = KeywordSerializer(many=True)
class Meta:
model = Tweet
fields = ["id", "text", "created_at", "author", "keywords"]
# depth = 1
def create(self, validated_data):
print(validated_data)
try:
author = validated_data.pop('author')
author, did_create = TwitterAccount.objects.update_or_create(**author)
print('644444')
tweet = Tweet.objects.update_or_create(author=author, **validated_data)
keywords_data = validated_data.pop('keywords')
for keyword_data in keywords_data:
Keyword.objects.update_or_create(**keyword_data)
return tweet
except Exception as e:
print("Exception occured in method .create in TweetSerializer")
print(e.args)
return None
the error I'm getting in the method create of TweetSerializer is:
("Field 'id' expected a number but got [OrderedDict([('name', 'dog')])].",)
('`create()` did not return an object instance.',)
could anyone explain why the field keywords
is getting treated as if it is id
?
One way to do what you want is to:
Here is the code (I have removed the author part):
def create(self, validated_data):
keywords_data = validated_data.pop("keywords")
tweet = Tweet.objects.update_or_create(**validated_data)[0]
for keyword_data in keywords_data:
keyword = Keyword.objects.update_or_create(**keyword_data)[0]
tweet.keywords.add(keyword)
return tweet
You can read the DRF documentation about that, there is not that precise example but there are others and a lot of explanation.