I'm learning how do RESTfull web services using django_rest_framework. I have this in urls.py :
urlpatterns = patterns('',
url(r'^tests/', 'Web_Services.views.test'),
)
ans I have a test function in views.py :
#api_view(['GET', 'POST'])
def test(request, format=None):
return Response({'Test OK!'})
my problem is that what when I add /?format=xml or anything other than json to the url I get 404 error. Another question : I get Assignment to reserved built-in symbol: format warning. I know what's it means but it's not me who decided to call it format. What I must do to resolve this problem.
Try adding this to your settings.py:
REST_FRAMEWORK = {
...your other DRF settings
'DEFAULT_RENDERER_CLASSES': (
'rest_framework.renderers.XMLRenderer',
'rest_framework.renderers.JSONRenderer',
)
}
See the relevant DRF documentation here:
http://www.django-rest-framework.org/api-guide/renderers#setting-the-renderers
A couple other things I can think...perhaps it's related to your url pattern not having $, can you try:
url(r'^tests/$', 'Web_Services.views.test'),
Also, make sure your data is valid JSON, try returning ["TestOK!]. Note the double-quotes.
Do you have any other urlpatterns defined in the project?
Related
I'm using Django's LocaleMiddleware to internationalize a part of the website I'm working on.
Here is my project's urls.py:
from django.conf.urls import patterns, include, url
from django.conf.urls.i18n import i18n_patterns
urlpatterns = patterns('',
url(r'^api/stuff/(?P<stuff_id>)\d+/$', ApiStuff.as_view()),
)
urlpatterns += i18n_patterns('',
url(r'^stuff/', DoStuff.as_view()),
)
The problem is, when ApiStuff.as_view() returns a 404 response (other error codes behave as expected), the LocaleMiddleware operates the request to make it redirect to /en/api/stuff/<stuff_id>, even though the /api namespace is clearly not in the i18n_patterns (at the end, it generates a 404 error too, but the content of my original response is lost).
Here is the code of ApiStuff:
import django.http
from django.views.generic import View
from project.stuff.models import Stuff
class ApiStuff(View):
#staticmethod
def get(request, *args, **kwargs):
stuff_id = kwargs['stuff_id']
try:
stuff = Stuff.objects.get(pk=stuff_id)
except Stuff.DoesNotExist:
return response({"error": "stuff not found"}, 404)
result = stuff.serialize()
return response(result)
def response(data, status=200):
data = json.dumps(data)
return django.http.HttpResponse(data, status=status, content_type='application/json')
I'm using django 1.6.10 (I know, it's late, but I can't update the version right now).
Am I missing something?
This is an old bug that has been tracked here:
https://code.djangoproject.com/ticket/17734
The 404 error handler is a default handler of Django. It obviously takes the current language into account in order to translate the "not found" message.
Unless you can upgrade to a newer version you probably need to define your own error handler (including route/url).
EDIT:
As a workaround it might be possible to extend the LocaleMiddleware and maybe also CommonMiddleware. However, it could be that the 404 handler does its magic nevertheless. Might be worth a shot though because it should only require few lines of code.
Citing the ticket:
when you request /api/raising/404/, it is redirecting the user to /en/api/raising/404/ (assuming it detects the language as en). If it tests before redirecting the user if /en/api/raising/404/ is resolvable, it would find out that this would raise a 404 as well and thus would not redirect the user.
EDIT 2:
As an alternative you could simply not use i18n_patterns and just detect/switch the language via browser/cookie/parameter. I did that for a project (which included Django CMS) where I kept running into problems with these URLs. It is definitely not a prerequisite for localized Django sites to use i18n URL patterns. It's just something on top, but not at all necessary. Localization will work just fine without it. If you need help with the middleware for switching languages, drop a comment.
One can get around this issue by using following url config
urlpatterns += i18n_patterns(
url(r'^(?!api.*)stuff', DoStuff.as_view()),
)
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(...)
How can I support old and new URI versions both working without breaking the reverse()?
For example, I have:
urlpatterns = patterns('',
url(r'^(old_part|new_part)/other/$', 'some_view'),
)
In this case /old_part/other/ and /new_part/other/ point to the same view but reverse() method fails because it doesn't know how to form link properly.
Also, what if we have url(r'^(old_part|new_part)/other/', include(sub_patterns)) how can it be handled?
Do you have any ideas?
Thanks for your help.
I suppose you are migrating. This means you don't want old url work, you want it to redirect to new url. Probably with 301 HTTP code (permanent redirect).
Having several urls for same content makes your site harder to use and hurts your SEO. Permanent redirect will tell Google and any other search engine to reindex page with new address.
You can do it this way in Django:
from django.views.generic import RedirectView
urlpatterns = patterns('',
url(r'^new_part/other/$', 'some_view'),
url(r'^old_part/other/$',
RedirectView.as_view(url='new_part/other/', permanent=True)),
)
If you need to capture everything with a subpath, you can capture url ending and add it to redirect url this way:
urlpatterns = patterns('',
url(r'^new_part/other/$', include(sub_patterns)),
url(r'^old_part/other/(?P<rest>.*)$',
RedirectView.as_view(url='new_part/other/%(rest)s', permanent=True)),
)
You can use redirect_to generic view in Django 1.4 and earlier.
If you want without a redirect, you could try this
url(r'^(?P<url>old_part|new_part)/other/$', 'some_view', name='some_view'),
Then your view will look like this
def some_view(request, url):
...
Then call reverse like this:
# will return /old_part/other/
reverse('some_view', kwargs={'url': 'old_part'})
# will return /new_part/other/
reverse('some_view', kwargs={'url': 'new_part'})
Just redirect the old urls to the new ones (with a 301 Moved Permanently).
NB : if you really insist on supporting both sets of urls (not a good idea IMHO), you'll have to have two distinct url patterns, and choose which one reverse() should resolve to.
I'm looking to redirect a list of old URLs to a list of new URLs in a Django/Heroku app.
Since I'm using Heroku, I can't just use an .htaccess file.
I see that rails has rack-rewrite, but I haven't seen anything like that for Django.
Django has redirects app, which allows to store redirects list in database:
https://docs.djangoproject.com/en/dev/ref/contrib/redirects/
Also here a generic RedirectView:
https://docs.djangoproject.com/en/1.3/ref/class-based-views/#redirectview
And the lowest level is HttpResponseRedirect:
https://docs.djangoproject.com/en/dev/ref/request-response/#django.http.HttpResponseRedirect
You can use redirect. Please check below code.
from django.shortcuts import redirect
return redirect(
'/', permanent=True
)
It worked for me.
Try redirect_to
Example from the docs for a 301 redirect:
urlpatterns = patterns('django.views.generic.simple',
('^foo/(?P<id>\d+)/$', 'redirect_to', {'url': '/bar/%(id)s/'}),
)
While the redirects app mentioned in the accepted answer is a pretty nice solution, it also involves a database call for every 404 error. I wanted to avoid this so ended up just manually implementing this in a URL conf.
"""redirects.py that gets included by urls.py"""
from django.urls import path, reverse_lazy
from django.views.generic.base import RedirectView
def redirect_view(slug):
"""
Helper view function specifically for the redirects below since they take
a kwarg slug as an argument.
"""
return RedirectView.as_view(
url=reverse_lazy('app_name:pattern_name', kwargs={'slug': slug}),
permanent=True)
urlpatterns = [
path('example-redirect/', redirect_view('new-url')),
]
I am very new to Python and Django.
I am using Django - 1.4.5. I am trying to get user input from form, redirect the url with the user input like
Httpresponseredirect('abc/xyz/%s' %variable)
I could see in browser that the response is redirected, but it throws a 404 error. The urls.py also has the url defined.
urls.py
urlpatterns = pattern('',
url (r'abc/xyz/(?P<variable>)/pqr' , 'view_name')
)
Can you please throw some light on it.
On further debugging I could figure out that the issue is with passing the argument to reverse function. When I pass a static page with no arguments, it redirects to the correct view. But when I redirect with arguments it throws me a NoreverseMatch error. I am redirecting it this way
return HttpResponseRedirect(reverse('view_name', kwargs= {'group':'group'}))
In urls.py it is defined as:
url (r'app/$' , 'app.view.app') ,
url (r'^my/first/(?P<group>)/$ , 'app.webapi.json.list_record', name ='view_name;),
list_record is a function in app.webapi.json.py.
Please let me know if any more details is required.
User reverse function in you view, first add a url name:
Httpresponseredirect(reverse('my_view_name', args=[variable]))
and (like #sushail said) fix the regexp:
urlpatterns = pattern('',
url (r'^abc/xyz/(?P<variable>)/pqr/$' , 'view_name', name='my_view_name')
)
you need to use complete path as the regexpression matchs abc/xyz/..../pqr
Httpresponseredirect('/abc/xyz/%s/pqr/' %variable)
and like (like #lalo said)
urlpatterns = pattern('',
url (r'^abc/xyz/(?P<variable>)/pqr/$' , 'view_name')
)
please checkwith / at begining and end, what is the view_name, it looks like you must have such a view in project directory,or you have to add the apppath in urlpatterns
`urlpatterns = pattern('<yourappname>.views',`