Not able to add url in Django router - django

I am not able to add workers URL which is pointing to a method in views.py. In below urls.py configuration, I had created a DefaultRouter, and registered 6 URLs. First 5 are working good(They are Class Based Views), however the last URL(workers, which is method based view) is not working. This URL is not matched with any of the URLs listed in url.conf. Error message I am getting 'Using the URLconf defined in maidFactory.urls, Django tried these URL patterns, in this order:. . . . . . .The current URL, workers/, didn't match any of these.'
router = routers.DefaultRouter()
router.register(r'users', views.UserViewSet)
router.register(r'groups', views.GroupViewSet)
router.register(r'slots', views.SlotViewSet)
router.register(r'city', views.CityViewSet)
router.register(r'location',views.LocationViewSet,base_name='locationMy')
router.register(r'workers',views.WorkerViewSet,base_name='getWorkersBySlotAndLocation')
# Wire up our API using automatic URL routing.
# Additionally, we include login URLs for the browsable API.
urlpatterns = [
url(r'^', include(router.urls)),
#url(r'^', include('maidFactory.api.urls')),
url(r'^admin/', include(admin.site.urls)),
url(r'^auth/', include('rest_framework_social_oauth2.urls')),
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))]
My method based view is as follows:
def WorkerViewSet(request):
cursor = connection.cursor()
#cursor.execute("UPDATE bar SET foo = 1 WHERE baz = %s", [self.baz])
cursor.execute("select p.wid,p.fname, a.description from workerProfile as p, workerAccount as a where a.isactive=1 and a.wid=p.wid")
row = cursor.fetchone()
return HttpResponse(row)

Your WorkerViewSet is not a actual DRF ViewSet but a Django function-based view returning Django HttpResponse.
You should convert it to a proper DRF viewset and then register your router with this viewset.
Another option is to add this as a url in urlpatterns in your urls file and it should work perfectly.
urlpatterns = [
url(r'^my/url/path/$', my_views.WorkerViewSet), # This will work
....
]

Related

Django Rest Framework: incorrect hyperlink on second viewset of same model

I'm trying to provide two distinct APIs using DRF but I'm unable to get the second app to stop creating
hyperlinked references based on the first. It's essentially the same problem as Django Rest Framework with multiple Viewsets and Routers for the same object but I'm unable to get it working.
app1/urls.py:
router = SimpleRouter(trailing_slash=False)
router.register(prefix=r'article', viewset=app1.ArticleViewSet, basename=r'article')
urlpatterns = [path(f'', include(router.urls)]
app2/urls.py:
router = SimpleRouter(trailing_slash=False)
router.register(prefix=r'published', viewset=app2.ArticleViewSet, basename=r'published')
urlpatterns = [path(f'', include(router.urls)]
site/urls.py:
urlpatterns = [
path('app1/', include('app1.urls')),
path('app2/', include('app2.urls')),
]
While both viewsets are of the same model, the queryset & serializer for each is different.
When I GET an item from /app2/published, it has an app1 URL:
"url": "http://localhost:8000/app1/article/5461"
What I'm wanting is for items retrieved via app2 to have:
"url": "http://localhost:8000/app2/published/5461"
From looking at the docs, it appears that providing basename should do what I want, but I'm not having any luck with getting it to work.
Try the following code in your site/urls.py:
from app1.urls import router as app1_router
from app2.urls import router as app2_router
router = routers.DefaultRouter()
router.registry.extend(app1_router.registry)
router.registry.extend(app2_router.registry)
urlpatterns = [
path('', include(router.urls)), # default page to show api
path('api-auth/', include('rest_framework.urls', namespace='rest_framework'))
]
You can see an example here, which has same structure as you need.

Django Rest Framework GET request with params

I'm trying to make a get request with params (srcFilename) in Django Rest Framework. I'm pretty confused about where to add the "req.query.srcFilename" (as it would be in javascript) in django. I read I have to add the complete url with the params in "<>" as shown in the code below, but it wont find the url.
views.py:
#api_view(['GET'])
def api_generate_signed_url(request, srcFilename):
print(f'srcFilename: {srcFilename}')
bucket = storage_client.bucket(bucket_name)
blob = bucket.blob(srcFilename)
if request.method == 'GET':
url = blob.generate_signed_url(
version="v4",
# This URL is valid for 15 minutes
expiration=datetime.timedelta(minutes=15),
# Allow GET requests using this URL.
method="GET",
)
print(f"Generated GET signed URL: {url}")
return Response(url)
urls.py:
from django.urls import include, path
from rest_framework import routers
from .views import api_generate_signed_url
router = routers.DefaultRouter()
urlpatterns = [
path('', include(router.urls)),
path('api-auth/', include('rest_framework.urls', namespace='rest_framework')),
path(r'signedurl?srcFilename=<srcFilename>', api_generate_signed_url),
]
When trying this in Postman I get the following error:
The current path, signedurl, didn't match any of these.
Postman screenshot
You have to change your path as below...
path('signedurl', api_generate_signed_url),
No need to write ?srcFilename=<srcFilename>. Just remove it.
Then in your view access your request parameters through the QueryDict request.query_params.get('srcFilename').

Different templates usage caused by changing the order in URLs (auth / registration)

I am using in my project built-in auth tools and django-registration
I have my logout template at:
/accounts/templates/registration/logout.html
If urls.py looks like:
urlpatterns = [
...
url(regex = r'^accounts/', view = include('registration.backends.hmac.urls')),
url(regex = r'^accounts/', view = include('django.contrib.auth.urls')),
...
]
It uses my template. It's OK.
But if I reorganize url like:
urlpatterns = [
...
url(regex = r'^accounts/', view = include('django.contrib.auth.urls')),
url(regex = r'^accounts/', view = include('registration.backends.hmac.urls')),
...
]
It uses built-in admin logout template.
Why does it happen?
Edit
In their tutorial I see that they say about 'registration.backends.hmac.urls':
That URLconf also sets up the views from django.contrib.auth (login,
logout, password reset, etc.), though if you want those views at a
different location, you can include() the URLconf
registration.auth_urls to place only the django.contrib.auth views at
a specific location in your URL hierarchy.
But when I open it, it seems to have no connection with auth urls/views:
EDIT: OK, now I see.
"""
URLconf for registration and activation, using django-registration's
HMAC activation workflow.
"""
from django.conf.urls import include, url
from django.views.generic.base import TemplateView
from .views import ActivationView, RegistrationView
urlpatterns = [
url(r'^activate/complete/$',
TemplateView.as_view(
template_name='registration/activation_complete.html'
),
name='registration_activation_complete'),
# The activation key can make use of any character from the
# URL-safe base64 alphabet, plus the colon as a separator.
url(r'^activate/(?P<activation_key>[-:\w]+)/$',
ActivationView.as_view(),
name='registration_activate'),
url(r'^register/$',
RegistrationView.as_view(),
name='registration_register'),
url(r'^register/complete/$',
TemplateView.as_view(
template_name='registration/registration_complete.html'
),
name='registration_complete'),
url(r'^register/closed/$',
TemplateView.as_view(
template_name='registration/registration_closed.html'
),
name='registration_disallowed'),
url(r'', include('registration.auth_urls')),
]
The last url pattern in registration.backends.hmac.urls includes registration.auth_urls, which provides urls for login, logout and so on.
url(r'', include('registration.auth_urls')),
If you include django.contrib.auth.urls, above the hmac urls, then the logout view from django.contrib.auth will be used. This view uses a different template, registration/logged_out.html. Since you haven't overridden this, the admin template is used.
The django url dipatcher which maps urls to views checks urls in order from first to last:
Django runs through each URL pattern, in order, and stops at the first
one that matches the requested URL.
So the order of the similar urls determinate which url is matched. I.e. the first is matched.

DRF Browsable API only shows one Router

Essentially, depending on the order in which I add my routes to my urlpatterns the browsable API will only show one router at a time. Here's my code:
urls.py:
from django.conf.urls import url, include
from rest_framework import routers
from .views import PlantViewSet
# url router
router = routers.DefaultRouter()
router.register(r'plants', PlantViewSet, base_name='Plants')
djoser_urls = [url(r'^', include('djoser.urls')), ]
urlpatterns = [
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
url(r'^docs/', include('rest_framework_swagger.urls')),
# url(r'^', include(router.urls)),
# url(r'^', include('djoser.urls')),
] + djoser_urls + router.urls
This only displays the djoser urls:
However simply reversing the order in which I add the urls:
urls.py:
from django.conf.urls import url, include
from rest_framework import routers
from .views import PlantViewSet
# url router
router = routers.DefaultRouter()
router.register(r'plants', PlantViewSet, base_name='Plants')
djoser_urls = [url(r'^', include('djoser.urls')), ]
urlpatterns = [
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
url(r'^docs/', include('rest_framework_swagger.urls')),
# url(r'^', include(router.urls)),
# url(r'^', include('djoser.urls')),
] + router.urls + djoser_urls
This only displays the router urls!
The same thing happens when I just use the include() lines I've commented out, whichever comes first in the list is the only router that gets displayed. Furthermore, no matter which router gets picked up the api-auth/ and docs/ urls are never shown. Is there anyway to get a unified api root without having to create my own custom view?
This doesn't have anything to do with Django REST framework, it happens because of how Django deals with duplicate urls.
You are trying to have a single url be handled by two different views: The DRF router index and the djoser root view. Django will only display the first view matching the search pattern that it finds, which is generally the first urls that are included in the url patterns.
Django REST framework will also not detect multiple routers that are available and group them together on the same page, which is sounds like you are hoping to see. Even if it could, djoser doesn't use a router so there is no way that DRF could actually know to include it.
Is there anyway to get a unified api root without having to create my own custom view?
So to answer the main question: No it is not possible for Django REST framework to automatically group these views together. You are going to need to create your own customer view to handle this.

URL not resolved with APIView in Django REST Framework

I'm starting out with DRF and ran into some trouble when trying to set up a simple APIView.
This is the view:
class SongSearchView(views.APIView):
def get(self, request, query, format=None):
return Response(['Justin Bieber - Boyfriend', 'Justin Timberlake - My Love'])
and these are the URL patterns:
router = DefaultRouter()
urlpatterns = patterns('',
url(r'^api/song_search/(?P<query>[a-zA-Z0-9\w]+)/$', views.SongSearchView.as_view()),
url(r'^admin/', include(admin.site.urls)),
url(r'^api/', include(router.urls)),
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
url(r'^$', views.index, name='index'),
)
and when I try to access http://127.0.0.1:8000/api/song_search/?query=justin I get a
Page not found (404)
Request Method: GET
Request URL: http://127.0.0.1:8000/api/song_search/?query=justin
What is the issue? :(
Your Url pattern Regular expression is wrong.. If you still want to stick to your current url pattern , I suggest you change your request url from
http://127.0.0.1:8000/api/song_search/?query=justin to http://127.0.0.1:8000/api/song_search/justin