Reputation: 29
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
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
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)
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