Home > Software design >  DRF update model with many-to-many field
DRF update model with many-to-many field

Time:07-18

I have two models with many-to-many relationship and I also have nested routers between them.

When I'm trying to create a tag at the endpoint api/page/4/tags/, tag is created in the database for tags, but nothing happend in my table for many to many relationship. How can I fix it? I want to update my M2M everytime a new tag is created. Thank you

models.py

class Tag(models.Model):
title = models.CharField(max_length=30, unique=True)

class Page(models.Model):
...
tags = models.ManyToManyField(Tag, related_name='pages')

My serializers.py

class TagSerializer(serializers.ModelSerializer):

class Meta:
    model = Tag
    fields = '__all__'

class PageSerializer(serializers.ModelSerializer):

tags = TagSerializer(many=True)
owner = serializers.HiddenField(default=serializers.CurrentUserDefault())

class Meta:
    model = Page
    fields = ['id', 'title', 'uuid', 'description', 'owner', 'is_private', 'tags']

views.py

class PageViewSet(viewsets.ModelViewSet):
queryset = Page.objects.all()
serializer_class = PageSerializer

def perform_update(self, serializer):
    serializer.save(owner=self.request.user)
    class TagViewSet(viewsets.ModelViewSet):
    serializer_class = TagSerializer
    queryset = Tag.objects.all()
class NestedTagViewSet(CreateModelMixin, ListModelMixin, GenericViewSet):
    queryset = Tag.objects.all()
    serializer_class = TagSerializer
    permission_classes = (IsAuthenticatedOrReadOnly,)


    def get_page(self, request, page_pk=None):
        page = get_object_or_404(Page.objects.all(), pk=page_pk)

        self.check_object_permissions(self.request, page)

        return page

    def create(self, request, *args, **kwargs):
        self.get_page(request, page_pk=kwargs['page_pk'])
        return super().create(request, *args, **kwargs)


    def get_queryset(self):
        return Tag.objects.filter(pages=self.kwargs['page_pk'])

    def list(self, request, *args, **kwargs):
        self.get_page(request, page_pk=kwargs['page_pk'])
        return super().list(request, *args, **kwargs)

my urls.py

from django.urls import path, include
from rest_framework_nested import routers

from .views import PageViewSet, TagViewSet, NestedTagViewSet

router = routers.SimpleRouter()
router.register(r'pages', PageViewSet)


pages_router = routers.NestedSimpleRouter(router, r'pages', lookup='page')
pages_router.register(r'tags', NestedTagViewSet, basename='page-tags')

app_name = 'page'

urlpatterns = [
    path(r'', include(router.urls)),
    path(r'', include(pages_router.urls)),
]


I'm trying to create new tags at the api/ ^pages/(?P<page_pk>[^/.] )/tags/$ [name='page-tags-list'] host

CodePudding user response:

I will assume after you create a tag you want to add it to the current page in the route.

With this in mind, you have a tag viewset, so you need to override the create method when you are creating a tag.

class TagViewSet(viewsets.ModelViewSet):
    serializer_class = TagSerializer
    queryset = Tag.objects.all()

    def create(self, request, *args, **kwargs):
        response = super().create(request, *args, **kwargs)
        new_tag = Tag.objects.get(id=response["id"])
        page = Page.objects.get(id=kwards["page_pk"])
        page.tags.add(new_tag)
        return response

The idea is to create a tag and after you create it, append it to the page M2M relationship. Hope this helps.

  • Related