I have little experience in python. Please could you help me. There is an old project which has the following structure
# -*- coding: utf-8 -*-
import re
from django.conf import settings
from django.conf.urls import include, url
from django.contrib import admin
from django.views.static import serve
from rest_framework import routers # i added it
import home.views
router = routers.DefaultRouter() # i added it
urlpatterns = [
url(r'^$', home.views.HomeView.as_view()),
url(r'^api/v2/', include('api.v2.urls', namespace='api-v2')),
url(r'^help/', include('helps.urls', namespace='helps')),
url(r'^admin/', include(admin.site.urls)),
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')), # i added it
url(r'^', include(router.urls)) # i added it
]
I would like to make REST API so that you can see all possible routes. So i try to add rest_framework.urls. As I understood it is necessary to use VeiwSet to add it to router. I do not quite understand how I can use what I already have to see links in a REST API? Or for each link i need to create a Veiwset?
For example api.v2.urls contains next: (similar in helps.urls, etc)
# -*- coding: utf-8 -*-
from django.conf.urls import url
import api.v2.views
urlpatterns = [
url(r'^data/info', api.v2.views.info_data),
url(r'^visits$', api.v2.views.visits),
url(r'^additional_info/', api.v2.views.additional_info),
]
a Viewset combines several views into a same class. You can have it for example to provide CRUD api for one of your Django model.
I recommend to read http://www.django-rest-framework.org/api-guide/viewsets/
You can register the Viewset in a router. I will generate an url for every view of the views
class UserViewSet(viewsets.ModelViewSet):
"""
A viewset for viewing and editing user instances.
"""
serializer_class = UserSerializer
queryset = User.objects.all()
in urls.py
from myapp.views import UserViewSet
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register(r'users', UserViewSet, base_name='user')
urlpatterns = [
...
url(r'^', include(router.urls))
]
If you print the router.urls
for url in router.urls: print(url)
You will see something like:
<RegexURLPattern user-list ^ users/$>
<RegexURLPattern user-list ^ users\.(?P<format>[a-z0-9]+)/?$>
<RegexURLPattern user-detail ^ users/(?P<pk>[^/.]+)/$>
<RegexURLPattern user-detail ^ users/(?P<pk>[^/.]+)\.(?P<format>[a-z0-9]+)/?$>
It shows the url for every view of the viewset
You can also have regular View for your REST API. http://www.django-rest-framework.org/api-guide/views/ which can be added to your urls like any usual Django view.
I hope it helps
I believe you will need to declare explicitly the urls that you want to show:
This is what i have in one of my projects:
urlpatterns = [
# Your stuff: custom urls includes go here
url(r'^api/$', api_root, name='api-root'),
]
#api_view(['GET'])
#permission_classes((IsAdminUser, ))
def api_root(request, format=None):
return Response({
'apples': reverse('my-api:oranges-all'),
'oranges': reverse('my-api:oranges-list'),
})
Related
I am trying to learn to create a Backend with Django, together with an Angular frontend.
In order to make the api a little more consistent I tried to create a API schema to use the OpenAPI Generator.
I have run the command ./manage.py generateschema --file schema.yml. But: The yml file does not have any information about the users.url. I have added the get_schema_view from the rest_framework, with the same result.
The (main) app urls.py looks like this:
from django.conf.urls import include
from django.contrib import admin
from django.urls import path
from rest_framework.schemas import get_schema_view
urlpatterns = [
path('admin/', admin.site.urls),
path('api/users/', include('users.urls'), name="users"),
path('api/network/', include('networkController.urls'), name="network"),
path('api/files/', include('fileController.urls'), name="files"),
path('api/', get_schema_view(
title="API Documentation",
description="API for all things"
), name='openapi-schema')
]
The networkController.urls looks like this:
from django.urls import path
from . import views
urlpatterns = [
path('', views.startNetwork)
]
which is found by the schema generator.
The users.urls looks like this:
from django.urls import path
from . import views
urlpatterns = [
path('login/', views.login),
path('register/', views.registerUser)
]
I have tried to move all urls to the (main) backend.urls and include the views directly, I have tried "layering" them all.
# backend.urls:
path('api/', include('api.urls'))
# api.urls:
path('users/', include('users.urls'))
without any changes.
I tried looking up, why - but without success. If I run the server and make a GET-Request via curl to localhost:8000/api/users/login directly, it works perfectly fine.
Could you please help me figure out, what I did wrong or guide me to a tutorial, which would cover the topic a little more detailled?
(And yes. Maybe I should just switch to something like FastAPI, but I really love Djangos Auth.Users and the easy constant, connection to a database)
Thanks in advance!
(EDIT: You can find the whole code in my GitHub)
I just figure out why my code didn't work. I use Class Based Views but I think this will also work for Method Based ones.
It looks like generateschema does not like uppercase method names:
class ...(UpdateAPIView):
serializer_class = ...
permission_classes = [IsAuthenticated]
http_method_names = ['PUT']
...
Instead of ['PUT'] I used ['put']
class ...(UpdateAPIView):
serializer_class = ...
permission_classes = [IsAuthenticated]
http_method_names = ['put']
...
So, replace all the uppercase letters with lowercase letters.
I have two separate apps Product and Tag which i used another app Product_tags to connect them together. in this way, if one of them don't exists, another one will work fine. inside Product_tags, I created a new TagProductSerializer which inherits ProductSerializer and I just added a new field named tag in fields list. product_tags/serializers.py:
class TagProductSerializer(ProductSerializer):
tags = serializers.PrimaryKeyRelatedField(queryset=Tag.objects.all())
class Meta:
model = Product
fields = [
'title',
'tags',
]
#...
and I did the same with Product viewsetproduct_tags/views.py
class TagProductViewset(ProductViewset):
serializer_class = SocialProductSerializer
and in my product_tags/urls.py I imported my Product router and i wanted to register my product viewset again for router. and there is my problem:
product/urls.py
router = routers.DefaultRouter()
router.register('product', ProductViewset)
urlpatterns = [
path('', include(router.urls)),
]
product_tags/urls.py (PROBLEM)
from product.urls import router
from .views import TagProductViewset
router.unregister('product') # I'm looking for something like this
router.register('product',TagProductViewset)
NOTE: I want to show the tags when getting product and because of that, I don't want to use different url for getting tag (e.g "api/product/tags/")
First Try:I tried to register the 'product' again (router.register('product',SocialProductViewset)) but it doesn't works
I fixed my problem but i forgot to say that here. I just created new router in my product_tags/urls.py and then I added it in urlpatterns inside of project/urls.py at top of my original product router.
product_tags/urls.py
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import TagProductViewset
router = DefaultRouter()
router.register('product',TagProductViewset)
urlpatterns = [
path('', include(router.urls)),
]
project/urls.py
from django.urls import path, include
urlpatterns = [
path('api/v1/', include("product_tags.urls")),
path('api/v1/', include("product.urls")),
]
Django-Oscar has apparently been updated to Django 2.0. I am new to Django, I am not sure how I would update the URLs that are mentioned in the Oscar Tutorial:
from django.conf.urls import include, url
from django.contrib import admin
from oscar.app import application
urlpatterns = [
url(r'^i18n/', include('django.conf.urls.i18n')),
# The Django admin is not officially supported; expect breakage.
# Nonetheless, it's often useful for debugging.
url(r'^admin/', include(admin.site.urls)),
url(r'', include(application.urls)),
]
This is the url that is currently available:
urlpatterns = [
path('admin/', admin.site.urls),
]
So, do this mean that I would change the django-oscar URls to?:
path(r'^i18n/', include('django.conf.urls.i18n')),
The documentation on readthedocs is out of date for some reason - here's the most recent version on Github which provides configuration for Django 2.
To use path you need to remove the regular expression syntax in the URLs. The use of include() also has been dropped for url configs passed directly, so you end up with:
from django.urls import include, path
from django.contrib import admin
from oscar.app import application
urlpatterns = [
path('i18n/', include('django.conf.urls.i18n')),
path('admin/', admin.site.urls),
path('', application.urls),
]
Django oscar always put their URLs in their app directory's apps.py file and then include that URL's to project level urls.py file, that's the design decision for Django oscar. But I would recommend you use path() than url() as this will help you to avoid the complexity.
##django-oscar/src/oscar/apps/basket/apps.py
from django.conf.urls import url
from django.contrib.auth.decorators import login_required
from django.utils.translation import gettext_lazy as _
from oscar.core.application import OscarConfig
from oscar.core.loading import get_class
class BasketConfig(OscarConfig):
label = 'basket'
name = 'oscar.apps.basket'
verbose_name = _('Basket')
namespace = 'basket'
def ready(self):
self.summary_view = get_class('basket.views', 'BasketView')
self.saved_view = get_class('basket.views', 'SavedView')
self.add_view = get_class('basket.views', 'BasketAddView')
self.add_voucher_view = get_class('basket.views', 'VoucherAddView')
self.remove_voucher_view = get_class('basket.views', 'VoucherRemoveView')
def get_urls(self):
urls = [
url(r'^$', self.summary_view.as_view(), name='summary'),
url(r'^add/(?P<pk>\d+)/$', self.add_view.as_view(), name='add'),
url(r'^vouchers/add/$', self.add_voucher_view.as_view(),
name='vouchers-add'),
url(r'^vouchers/(?P<pk>\d+)/remove/$',
self.remove_voucher_view.as_view(), name='vouchers-remove'),
url(r'^saved/$', login_required(self.saved_view.as_view()),
name='saved'),
]
return self.post_process_urls(urls)
then imported by project level config.py file
##django-oscar/src/oscar/config.py
# flake8: noqa, because URL syntax is more readable with long lines
from django.apps import apps
from django.conf import settings
from django.conf.urls import url
from django.urls import reverse_lazy
from django.views.generic.base import RedirectView
from oscar.core.application import OscarConfig
from oscar.core.loading import get_class
class Shop(OscarConfig):
name = 'oscar'
def ready(self):
from django.contrib.auth.forms import SetPasswordForm
self.catalogue_app = apps.get_app_config('catalogue')
self.customer_app = apps.get_app_config('customer')
self.basket_app = apps.get_app_config('basket')
self.checkout_app = apps.get_app_config('checkout')
self.search_app = apps.get_app_config('search')
self.dashboard_app = apps.get_app_config('dashboard')
self.offer_app = apps.get_app_config('offer')
self.password_reset_form = get_class('customer.forms', 'PasswordResetForm')
self.set_password_form = SetPasswordForm
def get_urls(self):
from django.contrib.auth import views as auth_views
from oscar.views.decorators import login_forbidden
urls = [
url(r'^$', RedirectView.as_view(url=reverse_lazy('catalogue:index')), name='home'),
url(r'^catalogue/', self.catalogue_app.urls),
url(r'^basket/', self.basket_app.urls),
url(r'^checkout/', self.checkout_app.urls),
url(r'^accounts/', self.customer_app.urls),
url(r'^search/', self.search_app.urls),
url(r'^dashboard/', self.dashboard_app.urls),
url(r'^offers/', self.offer_app.urls),
# Password reset - as we're using Django's default view functions,
# we can't namespace these urls as that prevents
# the reverse function from working.
url(r'^password-reset/$',
login_forbidden(
auth_views.PasswordResetView.as_view(
form_class=self.password_reset_form,
success_url=reverse_lazy('password-reset-done'),
template_name='oscar/registration/password_reset_form.html'
)
),
name='password-reset'),
url(r'^password-reset/done/$',
login_forbidden(auth_views.PasswordResetDoneView.as_view(
template_name='oscar/registration/password_reset_done.html'
)),
name='password-reset-done'),
url(r'^password-reset/confirm/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>.+)/$',
login_forbidden(
auth_views.PasswordResetConfirmView.as_view(
form_class=self.set_password_form,
success_url=reverse_lazy('password-reset-complete'),
template_name='oscar/registration/password_reset_confirm.html'
)
),
name='password-reset-confirm'),
url(r'^password-reset/complete/$',
login_forbidden(auth_views.PasswordResetCompleteView.as_view(
template_name='oscar/registration/password_reset_complete.html'
)),
name='password-reset-complete'),
]
return urls
Oscar's idea is to modularize every app. That's why it stores app's all url to apps.py in every app folder and include that to project level config.py file.
I got an error.
And i have no ideia how to fix it, take a look, this is the error:
TypeError: as_view() takes 1 positional argument but 2 were given
This as you can see is the code of my "model.py" page.
from django.db import models
from django.contrib.gis.db import models
class RoadsLines(models.Model):
gid = models.IntegerField()
geom = models.MultiLineStringField()
def __str__(self): # __unicode__ on Python 2
return '%s %s' % (self.gid, self.geom)
This as you can see is the code of my "views.py" page.
from django.shortcuts import render
# Create your views here.
from django.shortcuts import render
from rest_framework import generics
from world.models import RoadsLines
from world.serializers import RoadsLinesSerializer
class ListCreateRoadsLines(generics.ListCreateAPIView):
queryset = RoadsLines.objects.all()
serializer_class = RoadsLinesSerializer
This as you can see is the code of my "urls.py" page.
from django.conf.urls import url, include
from rest_framework import routers, serializers, viewsets
from world import views
# Routers provide an easy way of automatically determining the URL conf.
router = routers.DefaultRouter()
router.register(r'Roads', views.ListCreateRoadsLines)
# 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'^api/', include('rest_framework.urls', namespace='rest_framework'))
]
What am I doing wrong?
Thank you in advance!
ListCreateRoadsLines is a view, not a viewset. You should include it in your url patterns, instead of trying to register it:
urlpatterns = [
url(r'^Roads$', views.ListCreateRoadsLines.as_view()),
url(r'^', include(router.urls)),
url(r'^api/', include('rest_framework.urls',
namespace='rest_framework'))
]
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)