I don't want to have the day in the URL for a detail view while using Django's dated_based generic views. I tried the following but get a TypeError at /logbook/2013/january/testing/ object_detail() takes at least 6 arguments (7 given):
models.py
class Entry(models.Model):
pub_date = models.DateTimeField()
def get_absolute_url(self):
return "/logbook/%s/%s/" % (self.pub_date.strftime("%Y/%B").lower(), self.slug)
urls.py:
from __future__ import absolute_import
from django.conf.urls import patterns, include, url
from .models import Entry
from . import views
urlpatterns += patterns('',
url(r'^logbook/(?P<year>\d{4})/(?P<month>[A-Za-z]+)/(?P<slug>[\w-]+)/$',
views.entry_detail),
)
views.py:
import functools
from django.views.generic import date_based
from .models import Entry
def prepare_arguments(view):
#functools.wraps(view)
def wrapped(request, *args, **kwargs):
kwargs['allow_future'] = request.user.is_staff
kwargs['queryset'] = Entry.objects.all() if request.user.is_staff
else Entry.objects.published()
kwargs['date_field'] = 'pub_date'
return view(request, *args, **kwargs)
return wrapped
#prepare_arguments
def entry_detail(request, *args, **kwargs):
return date_based.object_detail(request, *args, **kwargs)
Is it possible to modify the code above and continue to use the date_based generic view without the day in the URL? If not, can someone please give an example of a simple custom view for the URL pattern url(r'^logbook/(?P<year>\d{4})/(?P<month>[A-Za-z]+)/(?P<slug>[\w-]+)/$', views.entry_detail)?
Thanks to Alasdair for pointing me in the right direction and to ccbv.co.uk. I ended up using DetailView and this worked:
urls.py:
from django.views.generic import DetailView
urlpatterns += patterns('',
url(r'^logbook/(?P<year>\d+)/(?P<month>[-\w]+)/(?P<slug>[\w-]+)/$',
DetailView.as_view(model=Entry),
name="entry_detail"),
)
views.py:
# nothing needed here for the detail view to work, though in the future
# I would like to have the generic view code here instead to accomplish
# the same thing as `DetailView.as_view(model=Entry), name="entry_detail"`
# in urls.py, and would appreciate an example of this.
Related
I'm practicing in Django and I want to know how requests and view mechanisms work correct in Django.
I started an app called ghcrawler in my django project. I designed like it has to send responses that recevied from localhost/ghcrawler and localhost/ghcrawler/results
So this is the urls.py in ghcrawler/ app folder.
from django.urls import path, include
from .views import main_view, results_view
urlpatterns = [
path('', main_view.as_view() , name='ghcrawler'),
path('ghresults', results_view.as_view(), name='getresults')
]
localhost/grcrawler page works well as expected. I just want to wire the requests coming to localhost/ghcrawler/results to getresults() function in results_view class defined in views.py, however it doesn't even write the 'h1' to the console
ghcrawler/views.py:
from django.views.generic import TemplateView
from django.shortcuts import render
from django import forms
from django.http import HttpResponse
from .github_requester import search_user
class main_view(TemplateView):
template_name = 'ghcrawler.html'
# Handle the post request received from /ghcrawler/
def post(self, request, *args, **kwargs):
if request.method == 'POST':
user = search_user(request.POST.get("username", ""))
if user == None:
print("User not found.")
else:
print(user)
return HttpResponse("OK")
class results_view(TemplateView):
template_name = 'ghresults.html'
def getresults(self, request, *args, **kwargs):
print('h1')
Rather than localhost/ghcrawler/results you mapped localhost/ghcrawler/ghresults to your view.
the rigth code would be:
urlpatterns = [
path('', main_view.as_view() , name='ghcrawler'),
path('results', results_view.as_view(), name='ghresults')
]
the firs argument in pathis the actual path
the secont argumen is the view
the third argument name is optional and used for addressing your view independant of your path
class results_view(TemplateView):
template_name = 'ghresults.html'
def get(self, request, *args, **kwargs):
print('h1')
I have a working class based view. But when adding #login_required I get the error:
AttributeError: 'function' object has no attribute 'as_view'
Something is happening to the ResultListView here:
from django.urls import path
from .views import ResultListView
urlpatterns = [
path('meetings/', ResultListView.as_view(), name='meetings'),
]
My views.py:
#login_required
class ResultListView(ListView):
template_name = ...
def get_queryset(self):
return Result.objects.filter(rider__user=self.request.user)
Which is all working fine until I put the decorator in. Very confused now, I don't see why ResultListView should loose its attributes when sending it through the decorator.
The #login_required decorator only decorates functions, not classes, you can make use of a mixin, or decorate the function that is the result of the .as_view() call.
Option 1: Using the LoginRequiredMixin
You can make use of the LoginRequiredMixin [Django-doc] that you need to put before the ListView in the parent classes:
from django.contrib.auth.mixins import LoginRequiredMixin
class ResultListView(LoginRequiredMixin, ListView):
template_name = …
def get_queryset(self):
return Result.objects.filter(rider__user=self.request.user)
Option 2: decorate the .as_view() result
An alternative is to decorate the outcome of the .as_view, which is indeed a function:
from django.urls import path
from .views import ResultListView
from django.contrib.auth.decorators import login_required
urlpatterns = [
path('meetings/', login_required(ResultListView.as_view()), name='meetings'),
]
I have a list view (for the admin site) that uses a template as follows:
class UserImageListPendingView(ListView):
model = UserImage
queryset = UserImage.objects.filter(status=ImageBase.PENDING)
template_name = 'userimage_list_pending.html'
context_object_name = 'userimage_list'
paginate_by = 5
#method_decorator(staff_member_required)
def dispatch(self, *args, **kwargs):
return super(UserImageListPendingView, self).dispatch(*args, **kwargs)
Although this works there are problems with putting the URL in urls.py:
urlpatterns = [
url(r'^admin/app/pendinguserimages/?$', login_required(
UserImageListPendingView.as_view()),
name='pendinguserimages'),
...
]
...as this stops the redirection working properly.
I did try to define the URL through admin.py:
def get_admin_urls(urls):
def get_urls():
return patterns('',
url(r'^app/pendinguserimages/?$',
UserImageListPendingView.as_view(), name='pendinguserimages'),
url(r'^app/checkuserimage/(?P<pk>[0-9]+)/?$',
userimage_check, name='checkuserimage'),
...
) + urls
return get_urls
admin_urls = get_admin_urls(admin.site.get_urls())
admin.site.get_urls = admin_urls
... but there was an error when reversing the checkuserimage URL.
How would I go about converting this view to fit in better with the admin site, but still use the template?
I didn't need to rewrite the ListView afterall. After defining the URLs in admin.py instead of in urls.py, all I needed to do was put "admin:" in front of the name when reversing the URL in the template, as follows:
check
I'm leaning Python to develop a website. I use Django framework to develop. To create a VIEW using django.views.generic.base.TemplateView.
So I wanna to get value 'user_name' and 'mail' from URL, but don't know how to do that! I cannot import request within this view.
Here is Views.py:
from django.views.generic.base import TemplateView
class MainView(TemplateView):
template_name = 'guestbook/main_page_1.html'
def get_context_data(self, **kwargs):
#I wanna to get value 'user_name' and 'mail' from URL...
name = request.GET.get("user_name") #temp
email = request.GET.get("mail") #temp
context = super(MainView, self).get_context_data(**kwargs)
context['var1'] = name
context['var2'] = email
return context
Here is Urls.py:
from django.conf.urls import patterns, url
from guestbook.views import MainView
urlpatterns = patterns('',
url(r'^$', MainView.as_view(), name='main'),
)
Anybody can help me to do this!
Thanks all!
Request is available in get_context_data() as self.request:
def get_context_data(self, **kwargs):
name = self.request.GET.get("user_name")
email = self.request.GET.get("mail")
...
How does one redirect from one View to another (next-going one):
class FooView(TemplateView):
template_name 'foo.html'
def post(self, *args, **kwargs):
return redirect(BarView)
# return redirect(BarView.as_view()) ???
class BarView(TemplateView):
template_name 'bar.html'
Give the URL pattern itself a name in your urls.py:
url('/bar/', BarView.as_view(), name='bar')
and just pass it to redirect:
return redirect('bar')
You can use the redirect for that, if you've given the view a name in urls.py.
from django.shortcuts import redirect
return redirect('some-view-name')
You need to give the view name "bar" to the path in "myapp/urls.py" as shown below:
# "myapp/urls.py"
from django.urls import path
from . import views
app_name = "myapp"
urlpatterns = [ # This is view name
path('bar/', views.BarView, name="bar")
]
Then, you need the conbination of the app name "myapp", colon ":" and the view name "bar" as shown below. In addition, you don't need to import the view "bar" in "myapp/views.py":
# "myapp/views.py"
from django.shortcuts import redirect
def FooView(request):
# Here
return redirect("myapp:bar")
def BarView(request):
return render(request, 'myapp/index.html', {})