i have created a url using NestedSimpleRouter. And the url that i have created is that :
http://localhost:8000/api/category/1/subcategory/
And In above url 1 in the id of category .And my problem is that
i want to create the url like this
http://localhost:8000/api/category/1/subcategory/1/interest
this 1 is subcategory_id
So How can i define Nested url for this url .My urls.py is given below:
urls.py:
from django.urls import path,include
from rest_framework_nested import routers
from campaignapp import views
router = routers.DefaultRouter()
router.register('campaign',views.CampaignViewSet)
router.register('interestbundle',views.InterestBundleViewSet)
router.register('category',views.CategoryViewSet,'category')
category_router = routers.NestedSimpleRouter(router, r'category', lookup='category')
category_router.register(r'subcategory', views.SubcategoryViewSet, base_name='category-subcategory')
urlpatterns = [
path('',include(router.urls)),
path('',include(category_router.urls))
]
You can add extra actions to your viewset using action or list_route or detail_route(older version of django rest framework) decorator. This decorator is applicable all ViewSets which inherit from ViewSetMixin class.
Related
I'm trying to figure out why the Django REST Framework throws a 404 Not Found when I POST data with the code below, because when I load the browsable API with the URL it correctly displays the object list with the HTML form to POST data.
The Django project that serve the API run in a Docker container as well as the client, but in a separate Docker host.
How could I fix the issue ?
Server
Console logs
django-1 | Not Found: /api/strategy/target/
django-1 | [26/Sep/2022 14:27:05] "POST /api/strategy/target/ HTTP/1.1" 404 23
project/project/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path("api/strategy/", include("strategy.urls")),
]
strategy/urls.py
from django.urls import path, include
from rest_framework import routers
from strategy.api.views import TargetViewSet
router = routers.DefaultRouter()
router.register("target", TargetViewSet, basename="targets-list")
urlpatterns = [
path('', include(router.urls)),
]
strategy/views.py
from rest_framework import viewsets
from strategy.api.serializers import TargetSerializer
from rest_framework.decorators import permission_classes
from rest_framework.permissions import IsAdminUser
# Create new model
#permission_classes([IsAdminUser])
class TargetViewSet(viewsets.ModelViewSet):
serializer_class = TargetSerializer
queryset = Target.objects.all()
Client
res = requests.post("http://1.2.3.4:8001/api/strategy/target/",
data=data,
headers={'Authorization': 'Bearer {0}'.format(token)}
)
router.register("target", TargetViewSet, basename="targets-list")
The defination of the router is correct but I think the basename you have there is the problem. Since you have a queryset defined in your views, you can remove the basename completely. You only need to use basename if you define your own get_queryset function.
So try this and let's see if it works out for you.
router.register("target", TargetViewSet")
I've been studying the viewset and router docs for Django and I can't figure out how to set up a route to access the method on a viewset.
For example, here is my urls.py:
from rest_framework.routers import DefaultRouter
from users.views import (UserViewSet, testing)
router = DefaultRouter()
router.register(r"users", UserViewSet, basename="users")
urlpatterns = [
path('testing', testing)
]
And then this is my views file in my user directory
#csrf_exempt
class UserViewSet:
def create(self):
return JsonResponse({
'the create endpoint'
})
#csrf_exempt
def testing(request):
return JsonResponse({
"title": "My json res"
})
Using postman, I can hit the endpoint example.com/testing and have the json response logged out. However, I try to hit example.com/users/create and I get a 404. I thought the basename propery when registering the viewset with the router would group all of the methods inside that class under that route path and then the methods would all be their own endpoint. Am I thinking about this incorrectly? Any help would be lovely as I am new to Django. I've mostly done Express and Laravel. Thanks!
You didn't convert your router into a urlpatterns list, so you won't be able to access your viewset regardless.
To convert the router:
from rest_framework.routers import DefaultRouter
from users.views import (UserViewSet, testing)
router = DefaultRouter()
router.register(r"users", UserViewSet, basename="users")
urlpatterns = [
path('testing', testing),
*router.urls,
]
In Django Rest Framework, a viewset's create method is executed during a POST request to a particular uri. In your case, this uri would be /users.
If you would like to add an additional method that triggers at /users/create, you will need to use the action decorator:
from rest_framework import viewsets
from rest_framework.response import JsonResponse
class UserViewSet(viewsets.ViewSet):
#action(methods=['GET'], url_path='create')
def my_custom_action(self):
return JsonResponse({
'the create endpoint'
})
Since create is a reserved method on DRF viewsets, you will need to name the method something else (in the example, my_custom_action), and set the url_path parameter accordingly.
If you were to omit the url_path, the path would default to the name of the method, eg. /users/my_custom_action.
I am using Django Built-in Admin panel, is there any way to remove app name from urls?
If I want to access User listing, it redirects me to 27.0.0.1:8000/admin/auth/user/ can I make it 27.0.0.1:8000/admin/user/ without the app name auth?
Thanks,
As documented here you can create a custom AdminSite and override the get_urls method. This simple code should to the job:
In your common.admin.py
from django.contrib.admin import AdminSite
class MyAdminSite(AdminSite):
def get_urls(self):
urlpatterns = super().get_urls()
for model, model_admin in self._registry.items():
urlpatterns += [
path('%s/' % (model._meta.model_name), include(model_admin.urls)),
]
return urlpatterns
my_admin = MyAdminSite('My Admin')
my_admin.register(YourModel)
...
Note that you register your models with the new custom AdminSite instance.
Then in your projects urls.py
from common.admin import my_admin as admin
from django.urls import path
urlpatterns = [
path('admin/', admin.urls),
# Your other patterns
]
I can't seem to get the urls to match in oscar. My oscar app is a subapp in my main app. My understanding is to create views and urls in the app.py in the sub modules in oscar.It keeps throwing NoReverseMatch. Oscar pages all loads, just not my custom views
in myapp/shop/dashboard/app.py
from django.contrib.auth import views as auth_views
from django.contrib.auth.forms import AuthenticationForm
from django.conf.urls import include, url
from oscar.core.application import DashboardApplication
from oscar.core.loading import get_class
from views import HomeViews
class DashboardApplication(DashboardApplication):
def get_urls(self):
urls = [
url(r'^someurl/', HomeViews.dosomething, name="hi"),
]
return self.post_process_urls(urls)
application = DashboardApplication()
in myapp/shop/dashboard/views.py
from django.conf import settings
from django.db.models import User
from oscar.app.partner.models import Partner
from django.middleware.csrf import get_token
from oscar.apps.dashboard.views import HomeView as CoreHomeView
class HomeView(CoreHomeView):
def dosomething(request):
return HttpResponse("hello")
in my main app, I registered the shop in my settings.py
INSTALLED_APPS =[
...
]] + get_core_apps(['shop'])
and in my main app url I have included oscar urls
from shop.app import application as shop_app
urlpatterns = i18n_patterns(
url(r'^shop/', include(shop_app.urls)),
You need to extend the existing urls list, not replace it. That is mostly why you get no reverse match errors because the default urls that oscar might have, don't exist anymore. For any other non-oscar-forked app, this would have been okay (just your own urls and nothing else).
class DashboardApplication(DashboardApplication):
def get_urls(self):
my_urls = [
url(r'^someurl/', HomeViews.dosomething, name="hi"),
]
default_urls = super(DashboardApplication, self).get_urls()
return self.post_process_urls(my_urls) + default_urls
I have been trying to get django-registration to use the view RegistrationFormUniqueEmail and following the solution from this django-registration question. I have set my urls.py to
from django.conf.urls import patterns, include, url
from registration.forms import RegistrationFormUniqueEmail
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns('',
url(r'^admin/', include(admin.site.urls)),
(r'^users/', include('registration.backends.default.urls')),
url(r'^users/register/$', 'registration.backends.default.views.RegistrationView',
{'form_class': RegistrationFormUniqueEmail,
'backend': 'registration.backends.default.DefaultBackend'},
name='registration_register'),
)
However, I can still create multiple accounts with the same email. What is the problem? Shouldn't django-registration be using the view that I specified? I am currently using django-registration 0.9b1.
The version of Django registration you are using has been rewritten to use class based views. This means a different approach is required in your urls.py.
First, You need to subclass the RegistrationView, and set the custom form class.
from registration.backends.default.views import RegistrationView
from registration.forms import RegistrationFormUniqueEmail
class RegistrationViewUniqueEmail(RegistrationView):
form_class = RegistrationFormUniqueEmail
Then, use your custom RegistrationViewUniqueEmail subclass in your urls. As with other class based views, you must call as_view().
url(r'^user/register/$', RegistrationViewUniqueEmail.as_view(),
name='registration_register'),
Make sure your customised registration_register view comes before you include the default registration urls, otherwise it won't be used.
The version 1.2 of django-registration-redux allows the unique email option with the following urls.py patterns:
url(r'^accounts/register/$', RegistrationView.as_view(form_class=RegistrationFormUniqueEmail), name='registration_register'),
url(r'^accounts/', include('registration.backends.default.urls')),
If you need to do something more, like a specific URL option, you can subclass the RegistrationView in your app views.py and RegistrationForm in your app forms.py