Tankard666
Tankard666

Reputation: 29

Wrong redirects when using defaultRouter() for ModelViewSet in Django-REST-framework

I have a Django Project where i made 3 Different Apps: "blog", "users", "api". It is a Website where messages can be posted by using a model Post. I want to use an Django Rest API for accessing the Model. It works, but it messes with some redirects of the UpdateView and DeleteView of "blog". I think it could be a problem with using DefaultRouter() ?

When i try to use my blog/PostupdateView blog/PostDeleteView ( inherited from UpdateView and DeleteView) views, i keep getting redirected to /api/blog/postid/ instead of just accessing my detailView where the path should be just /blog/postid/ and i cannot figure out why.

my Post Model:

class Post(models.Model):
    ...
    def __str__(self):
        return self.title

    def get_absolute_url(self):
        return reverse('post-detail', kwargs={'pk': self.pk})

my Serializer:

class PostSerializer(serializers.ModelSerializer):
   class Meta:
        model = Post
        fields = ('id', 'title', 'content', 'date_posted', 'author', 'rooms')

my api view for Post:

  class PostView(viewsets.ModelViewSet):
        queryset = Post.objects.all()
        serializer_class = PostSerializer

My urls Files:

main urls.py:

urlpatterns = [
    ...
    path('', include('blog.urls')),
    path('api/',include('api.urls')),
]

blog/urls.py:

urlpatterns = [
   ...
    path('post/<int:pk>/', PostDetailView.as_view(),name='post-detail'),
    path('post/new/', PostCreateView.as_view(),name='post-create'),
   ...
]

api/urls.py:

router = routers.DefaultRouter()
router.register('post', views.PostView)

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

my PostCreateView in blog/views.py

class PostCreateView( LoginRequiredMixin, UserPassesTestMixin, CreateView):
    model = Post
    fields = ['title', 'content', 'rooms']

    def test_func(self):
        ...

    def get_form(self, form_class=None):
        ...

    def form_valid(self, form):
        ...

When using PostCreateView, i should be redirected to the detail-view of the created Post, as defined in the Post model. Instead im getting redirected to the api url that is generated by the router in api/urls.py

Upvotes: 1

Views: 1145

Answers (2)

Lindsay Hefton
Lindsay Hefton

Reputation: 41

I am new and can't comment, so I'll answer OP's question in the comment on the accepted answer, for anyone else who find this.

When you register a route with the default router, Django will automatically assign a set of url's for them, which are in the format {basename}-{something else}, where {something else} depends on what action you called and the HTTP method. The basename is determined by the queryset attribute of the viewset (so your basename would be post).

For "GET" + "retrieve" action, the url will be {basename}-detail, which for your queryset translated to post-detail, which overrides the post-detail you defined for the non-api view.

You can get around it by registering the router with a basename, so the non-api post-detail URL name will correspond to the post/<pk> URL, and {other basename}-detail can correspond to the API view:

router.register('post', views.PostView, basename='api-post')

https://www.django-rest-framework.org/api-guide/routers/

Upvotes: 0

JPG
JPG

Reputation: 88449

One of the easy methods to solve the issue is, change the get_absolute_url() method as

class Post(models.Model):
    ...

    def __str__(self):
        return self.title

    def get_absolute_url(self):
        return "/blog/{}/".format(self.pk)

UPDATE

What was the problem?

You are defined the URLs with the same name, post-detail, for API and usual view. You should name the URLs with unique names.

# blog/urls.py
urlpatterns = [
    ...
    path('post/<int:pk>/', PostDetailView.as_view(), name='blog-post-detail'),
    path('post/new/', PostCreateView.as_view(), name='blog-post-create'),
    ...
]
#models.py
class Post(models.Model):
    ...

    def __str__(self):
        return self.title

    def get_absolute_url(self):
        return reverse('blog-post-detail', kwargs={'pk': self.pk})

Upvotes: 1

Related Questions