I am starting a new project with Django and neo4j, and the most promising library for developing REST services is TastyPie (Django Rest Framework is to tied to ORM, and neo4j is not a relational database).
I am following this tutorial in order to make TastyPîe to work with not relational databases, and I already override the get methods, but I get this error when trying to access the endpoint:
Page not found (404)
Request Method: GET
Request URL: http://127.0.0.1:8000/api/items_manager/items/
Using the URLconf defined in AttractoraGraph.urls, Django tried these URL patterns, in this order:
admin/
api/ general/
api/ items_manager/ items/ ^(?P<resource_name>item)/$ [name='api_dispatch_list']
api/ items_manager/ items/ ^(?P<resource_name>item)/schema/$ [name='api_get_schema']
api/ items_manager/ items/ ^(?P<resource_name>item)/set/(?P<pk_list>.*?)/$ [name='api_get_multiple']
api/ items_manager/ items/ ^(?P<resource_name>item)/(?P<pk>.*?)/$ [name='api_dispatch_detail']
The current path, api/items_manager/items/, didn't match any of these.
This is my general urls.py:
from django.contrib import admin
from django.urls import path
from django.urls import path, include
api_url_patterns = [
path('general/', include('GeneralApp.urls')),
path('items_manager/', include('ItemsManagerApp.urls')),
]
urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include(api_url_patterns)),
This is my application's urls.py:
from django.urls import path, include
from ItemsManagerApp import resources
urlpatterns = [
path('items/', include(resources.ItemResource().urls)),
]
this is my resources.py:
from tastypie import fields, utils
from tastypie.authorization import Authorization
from tastypie.resources import Resource
from ItemsManagerApp import models
class ItemResource(Resource):
uid = fields.CharField(attribute='uid')
name = fields.CharField(attribute='name')
description = fields.CharField(attribute='description')
created = fields.DateTimeField(default=utils.now, attribute='created')
def get_object_list(self, request):
return list(Item.nodes.all())
def obj_get_list(self, bundle, **kwargs):
return self.get_object_list(bundle.request)
def obj_get(self, bundle, **kwargs):
item = Item.nodes.filter(uid=kwargs['pk'])
return item
I can see that the endpoint url api/items_manager/items/ is in the list, but with something else that is not referenced in the documentation.
I'll appreciate any idea of how to solve this.
In this situation, you can try to access this endpoint http://127.0.0.1:8000/api/items_manager/items/item/.
Maybe this tutorial can help you.
Related
The bounty expires in 4 days. Answers to this question are eligible for a +50 reputation bounty.
varnie wants to draw more attention to this question.
I have the following urls.py for an app named service where I register API endpoints:
from .views import AccessViewSet, CheckViewSet
app_name = "api"
router = DefaultRouter()
router.register(r"access/(?P<endpoint>.+)", AccessViewSet, basename="access")
router.register(r"check/(?P<endpoint>.+)", CheckViewSet, basename="check")
urlpatterns = [
path("", include(router.urls)),
]
Below is my project's urls.py where I use it:
from django.conf import settings
from django.contrib import admin
from django.urls import include, path
import service.urls as service_urls
urlpatterns = [
# ...
path("service/", include('service.urls')),
]
The APIs themselves are functioning properly, but I am having trouble making them work with DRF's default API root view. The view is displaying an empty list of available endpoints. I'm not sure, but this issue may be related to the regular expressions I'm using when registering endpoints, such as r"access/(?P<endpoint>.+). If this is indeed the problem, how can I resolve it?"
DefaultRouter needs to run reverse(viewname) on your views to generate urls for the default view. It won't know about your dynamic parameter endpoint when it runs.
If it's acceptable to change your url structure to {endpoint}/access/... and {endpoint}/check/... you can:
router.register(r"access", AccessViewSet, basename="access")
router.register(r"check", CheckViewSet, basename="check")
urlpatterns = [
re_path(r"(?P<endpoint>.+)/", include(router.urls)),
]
After which, each {endpoint}/ view should have a working default API view.
If you need to preserve your url structure, you'll have to manually generate a list of available routes like this:
from collections import OrderedDict
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.reverse import reverse
class ApiRoot(APIView):
"""My API root view"""
def get(self, request, format=None):
"""List of available API endpoints"""
api_methods = [
"access-list",
"check-list",
]
endpoints = [
"endpoint-a",
"endpoint-b",
]
routes = OrderedDict()
for endpoint in endpoints:
for method in api_methods:
routes[endpoint + method] = reverse(
method, endpoint=endpoint, request=request, format=format
)
return Response(routes)
Notice the endpoint=endpoint in the reverse call.
If the code above doesn't help, please, expand your question with more details of what you're trying to archive in the first place. I have a feeling you might want to replace your viewsets with an EndpointViewSet with custom ViewSet actions for check and access.
Finally, if you're looking for routes like {endpoint_id}/access/{access_id}/... and {endpoint_id}/check/{check_id}/... check out drf-nested-routers - a drop-in replacement for DRF's Routers that supports nesting.
When I try a GET request on one of my API endpoints it can't find the endpoint.
urls.py file looks like this
from django.urls import path, include
from django.contrib import admin
from api.resources import NoteResource
note_resource = NoteResource()
urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include(note_resource.urls)),
]
api.resources looks like this
from tastypie.resources import ModelResource
from api.models import Note
class NoteResource(ModelResource):
class Meta:
queryset = Note.objects.all()
resource_name = 'note'
Any idea why this is happening?
Solution: It appears that http://127.0.0.1:8000/api/note/ works properly.. why would this be?
You should also have one url entry in note_resource.urls for only /api request. Something similar to
path('api/', APIClass).
But, you never need that endpoint. Because, /api does not represent any actual request in your system.
I rather suggest to have following endpoints :
path('api/notes/',include(note_resource.urls))
in your main urls.py.
So that you can have multiple urls in main urls.py file representing each app.
path('api/<APP_NAME>(s)/',include(<APP_NAME>.urls))
And, you will manage other endpoints in your app urls.py file:
# Create a new Note
path(
'create/',
NoteCreate.as_view()
),
I have created a page where a user can add a new item (notes in this case) and I am making use of CBV which I have recently started learning.
This is my model form
class NoteForm(forms.ModelForm):
class Meta:
model = Note
fields = ('title', 'note', 'tags')
This is the view in views.py
class NoteCreate(CreateView):
model = Note
form_class = NoteForm
template_name = "add_note.html"
Then this is the url as I used in the urls.py of the app
from django.conf.urls import patterns, url
from . import views
from madNotes.views import NoteCreate, NoteIndex,
urlpatterns = patterns(
'',
url(r'^notes/add/$', NoteCreate.as_view(), name="new_note"),
url(r'^$', NoteIndex.as_view()),
url(r'^(?P<slug>\S+)/$', views.NoteDetail.as_view(), name="entry_detail"),
)
NB: I used the same url as the main page at 127.0.0.1:8000 in the projects urls.py file and it worked.
I have seen several tutorials and even the docs and can't seem to find what I am doing wrong. Will I also need to add a function in order for it to be saved in the db or the CBV will do it all?
EDit: The error I get is this
Page not found (404)
Request Method: GET
Request URL: http://127.0.0.1:8000/notes/add/
Here is the project's urls.py
from django.conf.urls import patterns, include, url
from django.contrib import admin
from MadNotez import settings
from registration.backends.default.views import RegistrationView
from madNotes.forms import ExRegistrationForm
if settings.DEBUG:
import debug_toolbar
urlpatterns = patterns('',
url(r'^__debug__/', include(debug_toolbar.urls)),
url(r'accounts/register/$', RegistrationView.as_view(form_class = ExRegistrationForm), name='registration_register'),
url(r'^accounts/', include('registration.backends.simple.urls')),
url(r'^admin/', include(admin.site.urls)),
url('^markdown/', include('django_markdown.urls')),
url('^notes/', include('madNotes.urls')),
#url(r'^$', views.NoteCreate.as_view(), name="new note"), when I used it here it worked
)
you say that is the urls.py of the app, which means it is included by the project's urls.py.
As you show now, all the app's URIs go under the notes prefix:
url('^notes/', include('madNotes.urls')),
so as things stand at present the correct URI for the page is
http://127.0.0.1:8000/notes/notes/add/
In order to clean things up a bit, I'd suggest to modify the app's urls.py to
url(r'^add/$', NoteCreate.as_view(), name="new_note"),
so that the page can be reached at
http://127.0.0.1:8000/notes/add/
This way all the app's pages/services are available under the notes prefix and with a simple name that is consistent with their action (i.e. add, delete, etc)
I've been working on the Django tutorial. I'm on the part where it is "Write Views That Actually Do something." (Part 3)
I'm trying to use the index.html template that it gives you, but I keep getting a 404 error that says
Request Method: GET
Request URL: http://127.0.0.1:8000/polls/index.html
Using the URLconf defined in mysite.urls, Django tried these URL patterns, in this order:
^polls/ ^$ [name='index']
^polls/ ^(?P<question_id>\d+)/$ [name='detail']
^polls/ ^(?P<question_id>\d+)/results/$ [name='results']
^polls/ ^(?P<question_id>\d+)/vote/$ [name='vote']
^admin/
The current URL, polls/index.html, didn't match any of these.
I don't know if one of the regex are wrong? I've been messing around with it for a while now and I have had no luck getting it to work.
I can go to /polls just fine. But /polls/index.html does not work.
Any help would be appreciated.
The version of Django that I'm using is 1.7.4
Django view functions or classes use the template you define, so that you do not have to specify it in the URL. The urls.py file matches your defined regex to send requests to views.
If you truly wanted to use that URL, you would have to define ^polls/index.html$ in your urls.py and direct it to your view.
From what you're asking it sounds like you essentially want to output a static html file on a URL defined in your urlpatterns in urls.py.
I strongly suggest you take a look at Class Based Views.
https://docs.djangoproject.com/en/1.7/topics/class-based-views/#simple-usage-in-your-urlconf
The quickest way to go from what you've got, to rendering polls/index.html would be something like;
# some_app/urls.py
from django.conf.urls import patterns
from django.views.generic import TemplateView
urlpatterns = patterns('',
(r'^polls/index.html', TemplateView.as_view(template_name="index.html")),
)
But I'm sure you'll want to pass things to the template so class based views will be what you need. So the alternative to the above with added context would be;
# some_app/views.py
from django.views.generic import TemplateView
class Index(TemplateView):
template_name = "index.html"
def get_context_data(self, **kwargs):
context = super(Index, self).get_context_data(**kwargs)
context['foo'] = 'bar'
return context
Then obviously adding {{ foo }} to your index.html would output bar to the user. And you'd update your urls.py to;
# some_app/urls.py
from django.conf.urls import patterns
from .views import Index
urlpatterns = patterns(
'',
(r'^polls/index.html', Index.as_view()),
)
I am trying to use Django's account system, including the #login_required decorator. My settings.py file includes django.contrib.auth and I have done a syncdb.
Page not found (404)
Request Method: GET
Request URL: http://localhost:8000/accounts/login/?next=/
Using the URLconf defined in dashboard.urls, Django tried these URL patterns, in this order:
^$ [name='home']
The current URL, accounts/login/, didn't match any of these.
You're seeing this error because you have DEBUG = True in your Django settings file. Change that to False, and Django will display a standard 404 page.
I see the above after trying to #login_required-decorate my home view.
It seems to be choking because it is redirected to accounts/login/, which I have not prepared for in my urls.py.
What can I add to urls.py or elsewhere so that the login_required decorator will do its usual behaviour?
Thanks,
Set the LOGIN_URL in your settings. The default value is '/accounts/login/'
The decorator also takes an optional login_url argument:
#login_required(login_url='/accounts/login/')
And, from the docs:
Note that if you don’t specify the login_url parameter, you’ll need to
ensure that the settings.LOGIN_URL and your login view are properly
associated. For example, using the defaults, add the following line to
your URLconf:
(r'^accounts/login/$', 'django.contrib.auth.views.login'),
path('accounts/login/', admin.site.urls),
Add this line in your urls.py project folder. Then it will work fine.
from django.contrib.auth.decorators import login_required
#login_required(login_url='/accounts/login/')
Add above two lines in your views.py file.
What worked for me in Django 2.2.1 - include re_path('^accounts/', admin.site.urls), in my project urls.py:
urls.py
from django.conf import settings
from django.conf.urls import include
from django.conf.urls import re_path
from django.conf.urls.static import static
from django.contrib import admin
from django.urls import path
urlpatterns = [
path('admin/', admin.site.urls),
re_path('^accounts/', admin.site.urls),
]
And in my views.py:
views.py
from django.contrib.auth.decorators import login_required
from django.views.generic import TemplateView
#method_decorator(login_required, name='dispatch')
class HomePageView(TemplateView):
"""
Home Page View
"""
template_name = 'amp/home.html'
Hope that helps.
UPDATE: To avoid warnings from django in regards to admin urls being loaded twice, I used a redirect instead in urls.py:
urls.py
urlpatterns = [
re_path('^accounts/', admin.site.urls),
re_path(r'^admin/', RedirectView.as_view(url='/accounts/', permanent=True))
]
More on redirect view here.