How to remove last / character in root URL API in Django - django

API only work with url below:
http://127.0.0.1:1997/api/v1/groups/
How can I remove the last '/' so that it works like below:
http://127.0.0.1:1997/api/v1/groups
My config url code:
import os
from django.contrib import admin
from django.urls import path, include
from rest_framework import routers
from rest_framework.schemas import get_schema_view
from rest_framework_swagger.renderers import SwaggerUIRenderer, OpenAPIRenderer
from groups import views as group_views
API_VERSION = os.getenv('API_VERSION')
API_ROOT = f"api/{API_VERSION}/"
router = routers.DefaultRouter()
router.register('groups', group_views.GroupViewSet)
schema_view = get_schema_view(
title='next_blog',
renderer_classes=[OpenAPIRenderer, SwaggerUIRenderer])
urlpatterns = [
path('admin', admin.site.urls),
path('api_auth', include(
'rest_framework.urls', namespace='rest_framework')),
path('docs', schema_view, name='docs'),
path(API_ROOT, include(router.urls)),
]
Thanks everyone !

Set the trailing_slash argument to False when instantiating the router.
router = DefaultRouter(trailing_slash=False)
Django Rest Framework Default Router

Related

How to get rid of app name in the particular url?

I have this urls.py in my app
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from products import views
app_name = 'products'
router = DefaultRouter()
router.register(r'products', views.ProductViewSet, basename='products')
router.register(r'categories', views.ProductCategoryViewSet, basename='categories')
router.register(r'brands', views.BrandViewSet, basename='brands')
urlpatterns = [
path('', include(router.urls)),
]
And this is my project's urls.py
from django.contrib.auth import views as auth_views
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('login/', auth_views.LoginView.as_view(template_name='users/login.html'),
name='login'),
path('logout/', auth_views.LoginView.as_view(template_name='users/logout.html'),
name='logout'),
path('__debug__/', include('debug_toolbar.urls')),
]
urlpatterns += [
...
path('products/', include('products.urls', namespace='products')),
...
]
And viewsets:
from rest_framework import viewsets, permissions
from .models import (
Product,
ProductCategory,
Brand,
)
from .serializers import ProductSerializer, ProductCategorySerializer, BrandSerializer
#all other viewsets are the same
class ProductViewSet(viewsets.ModelViewSet):
queryset = Product.objects.all()
serializer_class = ProductSerializer
permission_classes = [permissions.IsAuthenticatedOrReadOnly]
A router for my app generates urls almost as expected, I can go to 'site/products/categories' for categories 'site/products/brands' for brands BUT for products url is 'site/products/products'. How to make it not to add app name in this case? I want it to be just 'site/products'.
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from products import views
app_name = 'products'
router = DefaultRouter()
router.register(r'categories', views.ProductCategoryViewSet, basename='categories')
router.register(r'brands', views.BrandViewSet, basename='brands')
router.register(r'', views.ProductViewSet, basename='products')
urlpatterns = [
path('', include(router.urls)),
]
Django is trying to match url to one url from list of router urls, so if you have two same urls, but one is faster in list, Django will pick always the first one.

Django Rest Swagger Not showing up all the APIs

I am working with Django Rest swagger. But it's not showing up all the APIs.
The url paths for /tickets are missing:
Even path to /dj-rest-auth/user/ is missing as well:
Backend/urls.py
from django.contrib import admin
from django.urls import path, include
from rest_framework_swagger.views import get_swagger_view
schema_view = get_swagger_view(title='API')
urlpatterns = [
path('admin/', admin.site.urls),
#path('api/v1/', include(api_urlpatterns)),
#path('dj-rest-auth/', include('dj_rest_auth.urls')),
path('dj-rest-auth/', include('dj_rest_auth.urls')),
path('dj-rest-auth/registration/', include('dj_rest_auth.registration.urls')),
path('api/', include('ticket.urls')),
path('swagger/', schema_view)
]
Tickets/urls.py
from django.urls import path
from ticket import views
urlpatterns = [
path('tickets/', views.ticket_list),
path('tickets/<int:pk>/', views.ticket_detail),
]
My directory structure:
Try with below code:
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.AllowAny',
),
.......
.......
}
I solved this by going in settings.py file and set DEBUG=True.

Django - reverse nested url with drf-nested-routers

I configured my api url as
localhost:port/app_name/students/{student_id}/macro/{macro_id}/lto
using drf-nested-routers extension. Basically, each students has some macro categories assigned, that in turns have some Long Term Objectives (LTOs). I've tested it using curl and Postman and everything seems to work.
Now I need to write a more precise test case for my LTO model.
This is my urls.py
from django.urls import path, re_path
from django.conf.urls import include
from rest_framework import routers
from app_name.views.views import UserViewSet, StudentViewSet, MacroViewSet, LTOViewSet, MacroAssignmentViewSet
from rest_framework_nested import routers as nested_routers
# application namespace
app_name = 'app_name'
router = routers.DefaultRouter()
router.register(r'users', UserViewSet, basename='user')
router.register(r'macro', MacroViewSet, basename='macro')
router.register(r'macro-assignments', MacroAssignmentViewSet, basename='macro-assignment')
student_router = routers.DefaultRouter()
student_router.register(r'students', StudentViewSet, basename='student')
lto_router = nested_routers.NestedSimpleRouter(student_router, r'students', lookup='student')
lto_router.register(r'macro/(?P<macro_pk>.+)/lto', LTOViewSet, basename='lto')
urlpatterns = [
re_path('^', include(router.urls)),
re_path('^', include(student_router.urls)),
re_path('^', include(lto_router.urls)),
]
The issue is that I cannot use the reverse() method correctly to get the url of my LTOViewSet to test it.
self.url = reverse('app_name:student-detail:lto', {getattr(self.student, 'id'), getattr(self.macro, 'id')})
This gives the following error
django.urls.exceptions.NoReverseMatch: 'student-detail' is not a registered namespace inside 'app_name'
In other test cases, I use very similar sentences and those work fine
self.list_url = reverse('app_name:student-list')
reverse('app_name:student-detail', {post_response.data['id']})
So here's the minimally reproducible example:
# main/viewsets.py
from rest_framework.viewsets import ModelViewSet
from django.contrib.auth.models import User, Group
class StudentViewSet(ModelViewSet):
model = User
class LTOViewSet(ModelViewSet):
model = Group
# main/urls.py
from django.urls import re_path, include
from rest_framework import routers
from rest_framework_nested import routers as nested_routers
from .viewsets import StudentViewSet, LTOViewSet
# application namespace
app_name = "main"
student_router = routers.DefaultRouter()
student_router.register(r"students", StudentViewSet, basename="student")
lto_router = nested_routers.NestedSimpleRouter(
student_router, r"students", lookup="student"
)
lto_router.register(r"macro/(?P<macro_pk>.+)/lto", LTOViewSet, basename="lto")
urlpatterns = [
re_path("^", include(student_router.urls)),
re_path("^", include(lto_router.urls)),
]
reverse('main:lto-detail', args=(1,1,1))
Out[5]: '/api/students/1/macro/1/lto/1/'
So indeed your error was passing just the router basename not a final endpoint to reverse and because of the nesting we were thrown off by student-detail not reversing (which I still don't get).

How to resolve an error 404 for django-social?

I want to be able to login through social media. Followed all the steps (registered app), the login works just fine but does not go through because django does not recognize my url.
This is my call to the api endpoint
facebookLogin(token: string):any{
return this.http.post(environment.api + 'fblogin/', {token:this.token}).subscribe(
(onSucess:any) => {
localStorage.setItem(this._tokenKey, onSucess.token)
}, onFail => {
console.log(onFail)
}
);
}
But I get the following error : POST http://127.0.0.1:8000/api/fblogin/ 404 (Not Found). From this I know there to be something wrong with my django urls. And indeed going to http://127.0.0.1:8000/api/fblogin/ gave me a page not found error and that it tried to match several other urls.
However I can't see what is wrong with my urls
URLS in my app
from django.conf.urls import url, include
from rest_framework import routers
from . import views
from rest_framework_jwt.views import obtain_jwt_token, refresh_jwt_token
from social_django import urls
router = routers.DefaultRouter()
router.register(r'users', views.UserViewSet)
urlpatterns = [
url(r'^', include(router.urls)),
url(r'fblogin/', include(urls)),
url(r'auth/', obtain_jwt_token),
url(r'refresh/', refresh_jwt_token)
]
URLS in my project
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include('Backend.api.urls'))
]
Other URLS like http://127.0.0.1:8000/api/users/ do work. I also am under the impression that all of my settings are in order.
I suggest that I might be because of the order and way in which you have defined URLs.py try the below format
from django.conf.urls import url, include
from rest_framework import routers
from . import views
from rest_framework_jwt.views import obtain_jwt_token, refresh_jwt_token
from social_django import urls
router = routers.DefaultRouter()
router.register(r'users', views.UserViewSet)
urlpatterns = [
url(r'^fblogin/', include(urls)),
url(r'^auth/', obtain_jwt_token),
url(r'^refresh/', refresh_jwt_token)
] + router.urls

Seeing only one endpoint in browsable API instead of two

How come I can only see one of my URLs (users) instead of both in the django rest browsable API?
urls:
urlpatterns = [
path("admin/", admin.site.urls),
path("api-auth/", include("rest_framework.urls")),
path("", include("accounts.urls")),
path("", include("properties.urls")),
]
I expected to see users AND properties
accounts.urls:
from django.urls import path, include
from accounts.views import UserViewSet
from rest_framework import routers
router = routers.DefaultRouter()
router.register(r"users", UserViewSet)
urlpatterns = [path("", include(router.urls))]
properties.urls:
from django.urls import path, include
from properties.views import PropertyViewSet, UnitViewSet
from rest_framework import routers
router = routers.DefaultRouter()
router.register(r"properties", PropertyViewSet)
router.register(r"units", UnitViewSet)
urlpatterns = [path("", include(router.urls))]