I have this view
class UserView(GenericAPIView):
def get(self, request, format=None, **kwargs):
pass
def post(self, request, format=None, **kwargs):
pass
This works fine with this url
url(r'^user$', UserView.as_view(),name='user'),
but i want to have custom url
def custom():
pass
I want that
url(r'^user/custom/$', UserView.as_view(custom),name='user'),
How can i do that
You can't do this.
from django.conf.urls import url
from django.views.generic import TemplateView
urlpatterns = [
url(r'^about/', TemplateView.as_view(template_name="about.html")),
]
Any arguments passed to as_view() will override attributes set on the
class. In this example, we set template_name on the TemplateView. A
similar overriding pattern can be used for the url attribute on
RedirectView.
If you want a 'custom' url, Use the Functions Based views
Urls
url(r'^user/custom/$', custom, name='user'),
Views
def custom(request):
# your custom logic
# return something
Edit 1*
If you want pass parameters to the CBV.
class View(DetailView):
template_name = 'template.html'
model = MyModel
# custom parameters
custom = None
def get_object(self, queryset=None):
return queryset.get(custom=self.custom)
Url
url(r'^about/', MyView.as_view(custom='custom_param')),
Related
I'm trying to register a simple method into a DRF and I'm having some problems. The route is not showing in API Explorer.
It's probably something simple that I'm missing..
How can I get the register route to show in the API?
Resuts (empty)
GET /api/
HTTP 200 OK
Allow: GET, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept
{}
Urls
from django.conf.urls import url, include
from django.contrib import admin
from rest_framework import routers
from rest_framework_jwt.views import obtain_jwt_token
from reservations.views.homepage import HomepageView
from users.views import UserViewSet
""" API routes
"""
router = routers.DefaultRouter()
router.register(r'test', UserViewSet, base_name='users')
""" Route patterns
"""
urlpatterns = [
url(r'^$', HomepageView.as_view(), name='homepage'),
url(r'^api/', include(router.urls)),
url(r'^api-token-auth/', obtain_jwt_token),
url(r'^admin/', admin.site.urls),
]
Viewset
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from rest_framework import viewsets
from rest_framework.response import Response
class UserViewSet(viewsets.ViewSet):
def register(self, request):
return Response({
'status': 'User registered'
})
ViewSet has some specific methods for every method (GET, POST, PUT etc) like list, detail, create, update etc. You should use that methods. Api explorer decides on the basis of these methods that which method is allowed by your view. You can see these methods here.
In your case, I suppose you want to create new user. So you should use create method like this.
class UserViewSet(viewsets.ViewSet):
def create(self, request, *args, **kwargs):
return Response({
'status': 'User registered'
})
If you want to work only with then list, create method you must have in it. Please check below example of my code. please check this link for more information http://www.django-rest-framework.org/api-guide/viewsets/
class UserViewSet(viewsets.ViewSet):
def list(self, request):
queryset = crm_models.EmployeeLeaveApp.objects.all()
serializer = serializers.EmployeeVisitSerializer(queryset, many=True)
return Response(serializer.data)
def retrieve(self, request, pk=None):
queryset = crm_models.EmployeeLeaveApp.objects.all()
user = get_object_or_404(queryset, pk=pk)
serializer = serializers.EmployeeVisitSerializer(user)
return Response(serializer.data)
def list(self, request):
pass
def create(self, request):
pass
def retrieve(self, request, pk=None):
pass
def update(self, request, pk=None):
pass
def partial_update(self, request, pk=None):
pass
def destroy(self, request, pk=None):
pass
Use #list_route for this. marking extra actions for routing
...
#list_route(methods=['post'])
def register(self, request):
return Response({
'status': 'User registered'
})
I have a Serializer in my code like this
class SampleSerializer(serializers.ModelSerializer):
class Meta:
model = Model
and Viewset like this
class SampleViewSet(GenericAPIView):
serializer_class = SampleSerializer
def get(self, request, *args, **kwargs):
pass
def post(self, request, *args, **kwargs):
pass
def put(self, request, *args, **kwargs):
pass
I have url like this for this viewset
Url #1:
url(r'^sample/$', SampleViewSet.as_view())
This makes url for all methods I have in my viewset like get, post and put etc. I want to make separate url for my get method but using same serializer. This url will look like this
Url #2:
url(r'^sample/(?P<model_id>\d+)/$', SampleViewSet.as_view())
How can I do this using same Viewset and Serializer? When I write Url #2 in urls.py, Swagger shows me all three type (get, post and put) of methods for that Url.
You could use require_GET decorator from django.views.decorators.http for this, and use it in your URL config:
urlpatterns = [
url(r'^sample/$', SampleViewSet.as_view()),
url(r'^sample/(?P<model_id>\d+)/$', require_GET(SampleViewSet.as_view())),
]
for more fine tuning there is also a require_http_method decorator which receives allowed methods in its parameters, e.g.:
url(r'^sample/(?P<model_id>\d+)/$', require_http_method(['GET', 'DELETE'])(SampleViewSet.as_view()))
See https://docs.djangoproject.com/en/dev/topics/class-based-views/intro/#decorating-in-urlconf for details.
Why don't you inherit ViewSet from viewsets.ViewSet and map your urls view DefaultRouter?
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register(r'sample', SampleViewSet)
urlpatterns = router.urls
It will handle all urls for your. /sample/:id now will be available for GET, PUT and DELETE methods.
Also if it plain CRUD for your Sample model, there is a better solution to use a viewsets.ModelViewset.
Error log:
error HomePageView' object has no attribute 'META'
urls.py
from django.conf.urls import url
from hello.views import HomePageView
urlpatterns = (
url(r'^$', HomePageView.as_view(), name='home'),
)
views.py
import textwrap
from django.shortcuts import render
from django.utils import timezone
from django.http import HttpResponse
from django.views.generic.base import View
class HomePageView(View):
def dispatch(request, *args, **kwargs):
c = {}
return render(request, 'welcome.html', c)
welcome.html
<html>
<head>
<title>Greetings to Django</title>
</head>
<body>
<h1 style="color:green;" align="center">Greetings to the world of Django Web Framework </h1>
</body>
</html>
The first parameter to dispatch, like all instance methods, should be self. request is passed as a keyword argument.
Note however that you should not be overriding dispatch. By doing so you are negating all the benefits of using class based views; you might as well use a standalone function. Instead, subclass TemplateView, set template_name as a class attribute, and define get_context_data when you actually need to pass some data to the template.
As already you are called view by name then It would be much better you can simply import all views like :
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$',HomePageView.as_view(), name='home'),
]
and mostly we use camelcase to define view name as: homePageView()
please go through it. https://docs.djangoproject.com/en/1.10/intro/tutorial01/#url-argument-name
In your views.py file, in a class function you need to use self as an argument.
Change this line def dispatch(request, *args, **kwargs): to def dispatch(self, request, *args, **kwargs):
class HomePageView(View):
def dispatch(self, request, *args, **kwargs):
c = {}
return render(request, 'welcome.html', c)
I have a class based view which just displays a list of configurations.
This view is added to the Django Admin site by using the following code:
#admin.register(ZbxHostConf)
class ZbxHostConfListViewAdmin(admin.ModelAdmin):
review_template = 'admin/admzbxhostconf_list.html'
def get_urls(self):
urls = super(ZbxHostConfListViewAdmin, self).get_urls()
my_urls = patterns('',
(r'^zbxhostconflist/$', self.admin_site.admin_view(self.review)),
)
return my_urls + urls
def review(self, request):
return ZbxHostConfListView.as_view()(request)
The template extends the admin/base_site.html template. I can access the site only after I log in to the Django Admin site. Unfortunately the template cannot access the context data provided by the admin view.
As the Django documentation suggests the context data will be provided directly to the TemplateResponse function:
def my_view(self, request):
# ...
context = dict(
# Include common variables for rendering the admin template.
self.admin_site.each_context(request),
# Anything else you want in the context...
key=value,
)
return TemplateResponse(request, "sometemplate.html", context)
For function-based views there is the possibility of the extra_context argument but class-based views don't provide this argument. I guess I have to modify the get_context_data function but I don't really understand how I can provide the admin context data to the get_context_data function of my class based view. Any suggestions?
This might not be a correct answer, but I believed you could try something like this.
#!/usr/bin/python3
from django.contrib import admin
class MyTemplateView(TemplateView):
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context.update(admin.site.each_context(self.request))
return context
I think I'm experiencing a threadding issue with the Django class-based views I have written.
After launching the application, the UpdateView functions fine until CreateView is called/visited. Then subsequent UpdateViews populate the 'code' field with the value generated in the get_initial method of CreateView.
The problem only shows itself on the web server, and not when using the development runserver command.
E.g. if an instance of MyObject has a code of '123', then visiting the UpdateView shows the code in the form as '123'. After visiting a page which calls CreateView, a new code is generated by get_initial(), say '456'. From then on, visiting any url which calls UpdateView shows '456' in the form instead of the instances actual code.
Sample myproject.app.views.myobject view classes:
from django.contrib.auth.decorators import permission_required
from django.utils.decorators import method_decorator
from django.views import generic
from myproject.app.forms import MyObjectForm
from myproject.app.models import MyObject
class EditMixin(generic.base.View):
form_class = MyObjectForm
def get_success_url(self):
return self.object.get_absolute_url()
def form_valid(self, form):
self.object = form.save(commit=False)
if not self.object.pk:
self.object.created_by = self.request.user
self.object.updated_by = self.request.user
self.object.save()
messages.success(self.request, 'Object saved.')
return HttpResponseRedirect(self.get_success_url())
class CreateView(EditMixin, generic.edit.CreateView):
model = MyObject
#method_decorator(permission_required('app.add_myobject'))
def dispatch(self, *args, **kwargs):
return super(CreateView, self).dispatch(*args, **kwargs)
def get_initial(self):
initial = super(CreateView, self).get_initial()
#TODO: proper auto-generation of code
myobject = MyObject.objects.order_by('-code')[0]
code = int(myobject.code) + 1
initial.update({'code': str(code)})
return initial
class UpdateView(EditMixin, generic.edit.UpdateView):
#method_decorator(permission_required('app.change_myobject'))
def dispatch(self, *args, **kwargs):
return super(UpdateView, self).dispatch(*args, **kwargs)
def get_queryset(self):
return MyObject.objects.filter(created_by=self.request.user)
Url Patterns:
from myproject.app.views import myobjects
urlpatterns = patterns('',
url(r'^$', myobjects.ListView.as_view(), name='myobject_list'),
url(r'^(?P<pk>[\d]+)/$', myobjects.DetailView.as_view(),
name='myobject_detail'),
url(r'^(?P<pk>[\d]+)/edit$', myobjects.UpdateView.as_view(),
name='myobject_edit'),
url(r'^new$', myobjects.CreateView.as_view(),
name='myobject_new'),
)
Can anyone help explain where I might be causing the threadding issue, and the best practice to avoid this?
Try removing the call to super's get_initial. It's seems to use a class property instead of an instance property, causing you trouble. Try this:
def get_initial(self):
myobject = MyObject.objects.order_by('-code')[0]
code = int(myobject.code) + 1
initial={'code': str(code)}
return initial