Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django Rest Framework - Create foreign key object on POST

I have a simple DRF REST API that I want to use to create blog articles. I want to be able to add tags to those blog articles so users can search tags and see related articles. However, the tags may not exist yet. I have created an Article Model with a ForeignKey field to a Tag Model like this:

class Tag(models.Model):

    name = models.CharField(max_length=32)

    def _str__(self):
        return self.name

    class Meta:
        ordering = ('name',)

class Article(models.Model):

    title = models.CharField(max_length=256)
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    content = models.TextField()
    date = models.DateTimeField(auto_now_add=True)
    tags = models.ForeignKey(Tag, on_delete=models.CASCADE, blank=True, default=None)

    def __str__(self):
        return self.title

    class Meta:
        ordering = ('date', 'id')

Ideally what I want is to be able to POST a new Article with a set of tags, and if any of the tags don't exist, create them in the DB. However, as it is currently, the tags need to already exist to be added to the Article. Visually, DRF shows this as a dropdown that is populated with pre-existing tags:

DRF Interface

How can I add or create multiple Tags from my Article API endpoint?

EDIT: As requested, I've added my views.py

views.py:

from api.blog.serializers import ArticleSerializer, TagSerializer
from rest_framework import viewsets

# /api/blog/articles
class ArticleView(viewsets.ModelViewSet):

    queryset = Article.objects.all()
    serializer_class = ArticleSerializer

# /api/blog/tags
class TagView(viewsets.ModelViewSet):

    queryset = Tag.objects.all()
    serializer_class = TagSerializer

For completeness, here are my serializers from my REST API's serializers.py.

serializers.py:

class ArticleSerializer(serializers.ModelSerializer):

    class Meta:
        model = Article
        fields = '__all__'


class TagSerializer(serializers.ModelSerializer):

    class Meta:
        model = Tag
        fields = '__all__'

urls.py:

from rest_framework import routers

router = routers.DefaultRouter()
router.register('articles', views.ArticleView)
router.register('tags', views.TagView)

urlpatterns = [
    path('', include(router.urls)),
]
like image 483
Sam Avatar asked Oct 28 '18 01:10

Sam


Video Answer


1 Answers

Overriding the create() method of the serializer as

class ArticleSerializer(serializers.ModelSerializer):
    tags = serializers.CharField()

    class Meta:
        model = Article
        fields = '__all__'

    def create(self, validated_data):
        tag = validated_data.pop('tags')
        tag_instance, created = Tag.objects.get_or_create(name=tag)
        article_instance = Article.objects.create(**validated_data, tags=tag_instance)
        return article_instance
like image 163
JPG Avatar answered Oct 25 '22 00:10

JPG