I have a few URLs that I want to exclude from my REST API documentation. I'm using Django REST Swagger and the only documentation I can find (https://github.com/marcgibbons/django-rest-swagger) doesn't really tell me much. There is the "exclude_namespaces" part of SWAGGER_SETTINGS in settings.py, but there is no real explanation or example of how to use this.
Simply put, I want to exclude any URLs from the docs that start with the following:
/api/jobs/status/
/api/jobs/parameters/
How could I go about doing this?
Thanks in advance for any help offered :P
the namespaces to exclude are the one defined in your urls.py.
So for example, in your case:
urls.py:
internal_apis = patterns('',
url(r'^/api/jobs/status/',...),
url(r'^/api/jobs/parameters/',...),
)
urlpatterns = urlpatterns + patterns('',
url(r'^', include(internal_apis, namespace="internal_apis")),
...
)
and in your settings.py:
SWAGGER_SETTINGS = {
"exclude_namespaces": ["internal_apis"], # List URL namespaces to ignore
}
This is well described in there
For all of those who found the above answer not helpful:
I guess that "exclude_namespaces" doesn't work anymore in new versions of django swagger. I had almost the same problem (I didnt't want to show my internal apis in documentation) and the above solution didn't work for me. I've been searching for like an hour for a solution and finally found something helpful.
There are some attributes that you can pass to SchemaGenerator. One of them is urlconf. You can set it to be "yourproject.api.urls" and it will get only urls defined there! Of course, you have to make sure that all the urls that you want to exclude from your api documentation are not included there.
I hope that at least one person found my answer helpful ;).
A problem comes when you want to have many urls.py included in your api documentation. I don't know what should be done then. If anyone comes up with an answer to this new problem - feel free to comment my answer. thanks!
With new version of django swagger, we don't need to create view to exclude some urls. Below code will disable test2 url.
from rest_framework_swagger.views import get_swagger_view
urlpatterns1 = [
url(r'^', include(router.urls)),
url(r'^test/', include('test.urls')),
url(r'^test1/', Test2.as_view()),
]
schema_view = get_swagger_view(title='API Documentation', patterns=urlpatterns1)
urlpatterns = urlpatterns1 + [
url(r'^docs/', schema_view),
url(r'^test2/', Test2.as_view()),
]
Ola's answer is correct. exclude_namespaces is no longer supported.
For finer control of the documentation, create your own schema view by using a function-based or class-based view. This can be useful if you want to produce documentation for specific URL patterns, or URL confs.
In your views.py, you can do the following:
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.schemas import SchemaGenerator
from rest_framework_swagger import renderers
class SwaggerSchemaView(APIView):
renderer_classes = [
renderers.OpenAPIRenderer,
renderers.SwaggerUIRenderer
]
def get(self, request):
generator = SchemaGenerator(title='Your API Documentation', urlconf='your_app.urls')
schema = generator.get_schema(request=request)
return Response(schema)
The above will only render documentation for the URLs that are specified in the urlconf argument of the SchemaGenerator. Also, don't forget to set up your urls.py as well:
from django.conf.urls import url
from views import SwaggerSchemaView
urlpatterns = [
url(r'^api/v1/docs/$', SwaggerSchemaView.as_view(), name='docs'),
]
For the newest version of drf-swagger you can defile url patterns in the schema generator.
For example:
url_patterns = (
url(r'^api/v1/', include(router.urls, namespace='api')),
)
generator = schemas.SchemaGenerator(title='Core API', patterns=url_patterns)
A more flexible solution would be:
from django.contrib import admin
from django.urls import include, path
from rest_framework_swagger.views import get_swagger_view
urlpatterns = [
path('admin/', admin.site.urls),
path('users/', include('user.urls', namespace="user")),
path('locations/', include('location.urls')),
path('departments/', include('department.urls', namespace="department")),
path('my_secret_api/', include('secret.urls', namespace="secret_api")),
]
to_exclude = ['secret_api',] # some more namespaces here
swagger_urls = [item for item in urlpatterns if hasattr(item,"namespace") and item.namespace not in to_exclude]
schema_view = get_swagger_view(title='Highky', patterns=swagger_urls)
urlpatterns += [
path('api/docs/', schema_view),
]
urlpatterns will have all five paths, but swagger_urls will have four paths excluding secret_api.
All of your URLs and includes will continue to work as they were, except we are now passing our modified urlpatterns that we want to show in the Swagger docs. The checks will also cover the include where you don't specify a namespace (like in our case, where the namespace is not defined in the location).
views.py
any view class
class ...ViewSet(viewsets.ModelViewSet):
queryset = ....objects.all().order_by('-id')
serializer_class = ...Serializer
http_method_names = ['get', 'post', 'patch', 'delete'] # add or exclude
any function-based view
#api_view(['get']) # target field
def function(request):
...
return Response(...)
Related
I want to include some django app's urls, in two different parent routes. The problem is, if I try to do this, then I will not be able to use reverse function properly for that app's urls.
This is where I'm stuck. The following url configurations will result in creation of two different url sets, e.g:
/api/v4/auth/{login, register, ...}
/api/auth/{login, register, ...}
app A (urls.py)
from auth import views
urlpatterns = [
url(r'^login/', views.login, name='login'),
url(r'^register/', views.register, name='register'),
...
]
main app (urls.py)
from auth import urls as auth_urls
urlpatterns = [
url(r'^api/v4/auth/', include(auth_urls)),
url(r'^api/auth/', include(auth_urls)),
...
]
Now, if I try to use reverse function like below:
def get_login_url():
return reverse('login')
I would probably get one of the possible outputs which I don't know how to control!
I don't know if django supports appending some kind of prefix to names of the urls that are being included or is there any tricks to hack around it or not!
You can use namespaces
from auth import urls as auth_urls
urlpatterns = [
url(r'^api/v4/auth/', include(auth_urls, namespace='auth1'))),
url(r'^api/auth/', include(auth_urls, namespace='auth2'))),
...
]
This way, you will be able to reverse alling auth1:login
Here's my code
from django.urls import path
urlpatterns = [
# /audios/
path('', views.audio ),
# /audios/4344/
path('(<record_id>[0-9]+)/', views.record_detail),
]
Please can someone help out
try this :
path(r'^record/(?P<record_id>[0-9]+)/$', views.record_detail)
Django 2.0 has came with new update of defining a new way for url patterns by path. In new url patterns you don't need to define urls in regex(see 3rd url pattern). Refer
But you can also write url patterns like we define in django < 2. 0 by re_path which is available in django.urls refer
Or you can use old django style of defining url patterns which is defined in django.conf.urls which helps you to define re pattern for urls.
from django.urls import re_path, path
from djnago.conf.urls import url,include
urlpatterns += [
url('(<record_id>[0-9]+)/',views.record_detail),
#or
re_path('(<record_id>[0-9]+)/', views.record_detail),
#or
path('<int:record_id>/', views.record_detail)
]
Just like #Exprator wrote, the path should be:
path('<int:record_id>/', views.record_detail, name='record_detail'),
However, I think maybe there is a problem in view "record_detail", the view should declare like this:
def record_detail(request, record_id):
then, you can refer your record_id in your view body.
Here is my code:
urlpatterns = [
path('', views.index, name='index'),
path('<int:record_id>/', views.record_detail, name='record_detail'),
]
from django.http import HttpResponse
def index(request):
return HttpResponse("Hello, world.")
def record_detail(request, record_id):
return HttpResponse("Hello, world. You're record is: "+str(record_id))
Here is result:
How do I add extra context to all admin webpages?
I use default Django Admin for my admin part of a site.
Here is an url entry for admin:
urlpatterns = [
url(r'^admin/', admin.site.urls),
]
And my apps register their standard view models using:
admin.site.register(Tag, TagAdmin)
My problem, is that I want to display an extra field in admin template header bar and I have no idea how to add this extra context.
My first bet was adding it in url patterns like below:
urlpatterns = [
url(r'^admin/', admin.site.urls, {'mycontext': '123'}),
]
But that gives an error:
TypeError at /admin/tickets/event/4/change/
change_view() got an unexpected keyword argument 'mycontext'
Can you give any suggestion? I really do not want to modify every AdminModel class I have to insert this context, as I need it on every admin page.
Thanks.
Found the solution, url registration has to be:
urlpatterns = [
url(r'^admin/', admin.site.urls, {'extra_context': {'mycontext': '123'}}),
]
Its a context dictionary inside of a dictionary with 'extra_context' as a key.
Another technique, more complex but allows different context per request (probably unavailable at OP time):
my_project/admin.py (create if missing)
from django.contrib import admin
from django.contrib.admin.apps import AdminConfig
class MyAdminConfig(AdminConfig):
default_site = 'my_project.admin.MyAdminSite'
class MyAdminSite(admin.AdminSite):
def each_context(self, request):
context = super().each_context(request)
context.update({
"whatever": "this is",
"just a": "dict",
})
return context
settings.py
INSTALLED_APPS = [
...
'my_project.admin.MyAdminConfig', # replaces 'django.contrib.admin'
...
The replace / extend admin class code is taken from the official docs except this is all in one file.
I'm having some weird issues with class-based-views and reverse_lazy.
Following error shows up when calling the website:
ImproperlyConfigured at /dashboard/student/
The included urlconf core.urls doesn't have any patterns in it
My views.py:
class DashStudentMain(TemplateView):
model_class = None
template_name = 'learn/dashboard/snip_student_1.html'
tab_list = {
("Main", reverse_lazy('dash_student_main_url')),
#("History", reverse_lazy('dash_student_main_url'))
}
active_tab = "Main"
My core.urls:
from django.conf.urls.defaults import patterns, include, url
from django.contrib import admin
from django.views.generic import RedirectView
from django.conf import settings
admin.autodiscover()
urlpatterns = patterns(
'',
url(r'^$', 'core.views.home', name='home_url'),
url(r'^home', 'core.views.home'),
url(r'^dashboard/', include('tc_learn.dashboard.urls')),
...
)
My tc_learn.dashboard.urls:
from django.conf.urls.defaults import patterns, url
from .views import DashStudentMain, DashStudentHistory
urlpatterns = patterns(
# Student + Tabs
url(r"^", DashStudentMain.as_view()),
url(r"^student/$", DashStudentMain.as_view(), name="dash_student_main_url"),
url(r"^student/history/$", DashStudentHistory.as_view(), name="dash_student_history_url"),
I've
restarted the server, to make sure urls were loaded properly
commented out ("Main", reverse_lazy('dash_student_main_url')) to make sure that the urls.py syntax is fine
deleted the line url(r"^", DashStudentMain.as_view()), since it's not used anyway, but without it /dashboard/student doesn't work at all..
Any idea what I might be missing? Thanks!
EDIT:
It looks like the issue is coming from the tab_list object.
When I directly assign the object via tab_list = reverse_lazy('dash_student_main_url'), the code works fine. When I use it inside a list, it's showing that error. Does anyone know of work-around for this scenario?
Change this code:
tab_list = {
("Main", reverse_lazy('dash_student_main_url')),
#("History", reverse_lazy('dash_student_main_url'))
}
to:
tab_list = [
("Main", reverse_lazy('dash_student_main_url')),
#("History", reverse_lazy('dash_student_main_url'))
]
Contrary to a name you gave the variable, you were not creating a list, but a set. Elements were evaluated immediately at the time of set creation, because sets need to know more about values they contain. Changing it to a proper list will allow the elements to be evaluated lazily, as intended.
In tc_learn.dashboard.urls: you are missing the first argument (empty prefix in your case). Change it to:
urlpatterns = patterns(
'',
url(r"^", DashStudentMain.as_view()),
url(r"^student/$", DashStudentMain.as_view(), name="dash_student_main_url"),
url(r"^student/history/$", DashStudentHistory.as_view(), name="dash_student_history_url"),
)
Also, the first regex should be r"^$" if you want it to represent an empty one
And see if it works. Let me know!
How do I accomplish a simple redirect (e.g. cflocation in ColdFusion, or header(location:http://) for PHP) in Django?
It's simple:
from django.http import HttpResponseRedirect
def myview(request):
...
return HttpResponseRedirect("/path/")
More info in the official Django docs
Update: Django 1.0
There is apparently a better way of doing this in Django now using generic views.
Example -
from django.views.generic.simple import redirect_to
urlpatterns = patterns('',
(r'^one/$', redirect_to, {'url': '/another/'}),
#etc...
)
There is more in the generic views documentation.
Credit - Carles Barrobés.
Update #2: Django 1.3+
In Django 1.5 redirect_to no longer exists and has been replaced by RedirectView. Credit to Yonatan
from django.views.generic import RedirectView
urlpatterns = patterns('',
(r'^one/$', RedirectView.as_view(url='/another/')),
)
Depending on what you want (i.e. if you do not want to do any additional pre-processing), it is simpler to just use Django's redirect_to generic view:
from django.views.generic.simple import redirect_to
urlpatterns = patterns('',
(r'^one/$', redirect_to, {'url': '/another/'}),
#etc...
)
See documentation for more advanced examples.
For Django 1.3+ use:
from django.views.generic import RedirectView
urlpatterns = patterns('',
(r'^one/$', RedirectView.as_view(url='/another/')),
)
There's actually a simpler way than having a view for each redirect - you can do it directly in urls.py:
from django.http import HttpResponsePermanentRedirect
urlpatterns = patterns(
'',
# ...normal patterns here...
(r'^bad-old-link\.php',
lambda request: HttpResponsePermanentRedirect('/nice-link')),
)
A target can be a callable as well as a string, which is what I'm using here.
Since Django 1.1, you can also use the simpler redirect shortcut:
from django.shortcuts import redirect
def myview(request):
return redirect('/path')
It also takes an optional permanent=True keyword argument.
If you want to redirect a whole subfolder, the url argument in RedirectView is actually interpolated, so you can do something like this in urls.py:
from django.conf.urls.defaults import url
from django.views.generic import RedirectView
urlpatterns = [
url(r'^old/(?P<path>.*)$', RedirectView.as_view(url='/new_path/%(path)s')),
]
The ?P<path> you capture will be fed into RedirectView. This captured variable will then be replaced in the url argument you gave, giving us /new_path/yay/mypath if your original path was /old/yay/mypath.
You can also do ….as_view(url='…', query_string=True) if you want to copy the query string over as well.
With Django version 1.3, the class based approach is:
from django.conf.urls.defaults import patterns, url
from django.views.generic import RedirectView
urlpatterns = patterns('',
url(r'^some-url/$', RedirectView.as_view(url='/redirect-url/'), name='some_redirect'),
)
This example lives in in urls.py
Beware. I did this on a development server and wanted to change it later.
Firefox 5 'caching' 301 redirects
I had to clear my caches to change it. In order to avoid this head-scratching in the future, I was able to make it temporary like so:
from django.views.generic import RedirectView
url(r'^source$', RedirectView.as_view(permanent=False,
url='/dest/')),
You can do this in the Admin section. It's explained in the documentation.
https://docs.djangoproject.com/en/dev/ref/contrib/redirects/
page_path = define in urls.py
def deletePolls(request):
pollId = deletePool(request.GET['id'])
return HttpResponseRedirect("/page_path/")
This should work in most versions of django, I am using it in 1.6.5:
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect
urlpatterns = patterns('',
....
url(r'^(?P<location_id>\d+)/$', lambda x, location_id: HttpResponseRedirect(reverse('dailyreport_location', args=[location_id])), name='location_stats_redirect'),
....
)
You can still use the name of the url pattern instead of a hard coded url with this solution. The location_id parameter from the url is passed down to the lambda function.