I created several date-based views in Django, and while views for year and month function as expected, the view to display days is not detected. For instance, if I try to get /balance/2018/, or /balance/2018/04/ the views will be displayed, while /balance/2018/04/02 will fail. I understand that the problem must be with urls.py configuration, but I just cannot find it in documentation. I also tried passing day_format='%d' to as_view method, without any results.
my urls.py file
from django.urls import path, re_path
from .views import ArticleYearArchiveView, ArticleMonthArchiveView, ArticleDayArchiveView
from . import views
urlpatterns = [
path('', views.index, name='index'),
path(r'<int:year>/<int:month:>/<int:day>/', views.ArticleDayArchiveView.as_view(day_format='%d'), name='show_day'),
path(r'<int:year>/<int:month>/', views.ArticleMonthArchiveView.as_view(month_format='%m'), name='show_month'),
path(r'<int:year>/', views.ArticleYearArchiveView.as_view(), name='show_year'),
]
my views.py file
from django.shortcuts import render
from django.views.generic.dates import YearArchiveView, MonthArchiveView, DayArchiveView
from django.http import HttpResponse
from django.db.models import Sum
from .models import Category, Article
import datetime
# Create your views here.
def index(request):
num_of_articles = Article.objects.all().count()
num_of_categories = Category.objects.all().count()
return render(request, 'index.html', context = {
'num_of_articles':num_of_articles,
'num_of_categories':num_of_categories})
class ArticleYearArchiveView(YearArchiveView):
queryset = Article.objects.all()
date_field = 'financial_day'
make_object_list = True
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['summation'] = Article.objects.all().filter(financial_day__year=kwargs['year'].year).aggregate(Sum('amount_of_money'))['amount_of_money__sum']
return context
class ArticleMonthArchiveView(MonthArchiveView):
queryset = Article.objects.all()
date_field = 'financial_day'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['summation'] = Article.objects.all().filter(financial_day__year=kwargs['month'].year).filter(financial_day__month=kwargs['month'].month).aggregate(Sum('amount_of_money'))['amount_of_money__sum']
return context
class ArticleDayArchiveView(DayArchiveView):
queryset = Article.objects.all()
date_field = 'financial_day'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['summation'] = Article.objects.all().filter(financial_day__year=kwargs['day'].year).filter(financial_day__month=kwargs['day'].month).filter(financial_day__day=kwargs['day'].day).aggregate(Sum('amount_of_money'))['amount_of_money__sum']
return context
#Here it'll show ARTICLE DETAILS for a given SLUG url
def show_article(request, article_slug):
response = "You are looking at the article %s."
return HttpResponse(response % article_slug)
Error text is:
Page not found (404)
Request Method: GET
Request URL: http://localhost:8000/balance/2018/04/02
Using the URLconf defined in spendings_calculator.urls, Django tried these URL patterns, in this order:
admin/
balance/ [name='index']
balance/ <int:year>/<int:month:>/<int:day>/ [name='show_day']
balance/ <int:year>/<int:month>/ [name='show_month']
balance/ <int:year>/ [name='show_year']
The current path, balance/2018/04/02, didn't match any of these.
You have a stray : after month - <int:month:>. Remove it:
path(r'<int:year>/<int:month>/<int:day>/', views.ArticleDayArchiveView.as_view(day_format='%d'), name='show_day'),
Also, note that you are defining the URL for balance/2018/04/02/ (with a trailing slash) but you are going to http://localhost:8000/balance/2018/04/02 (without a trailing slash). Once you have fixed the typo above, Django should redirect you to the URL with the trailing slash.
Related
Although the original question is cleared out, there's a new related question which is quite interesting: (please let me know if my theory is remotely correct...)
Please checkout my urlpatterns below:
from django.contrib.auth import views as auth_views
from boutique.models import Category
from django.urls import path, include
from . import views
app_name = 'users'
urlpatterns = [
# to customise login view
path('login/', auth_views.LoginView.as_view(extra_context = {'categories': Category.objects.get_categories_with_item()})),
# path('login/', views.NewLoginView.as_view()),
# to customise default logout view
path('logout/', auth_views.LogoutView.as_view(), {'categories': Category.objects.get_categories_with_item()}),
# include django authentication urls
path('', include('django.contrib.auth.urls')),
As you probably noticed that there are two different ways to pass in extra_context, the interesting thing is: The method used on LogoutView can not be used on LoginView!! However, The method used on LoginView does work on LogoutView.
I think the possible explanation and yet to be confirmed by you lot is that they inherit different views:
LoginView:
class LoginView(SuccessURLAllowedHostsMixin, FormView):
"""
Display the login form and handle the login action.
"""
form_class = AuthenticationForm
authentication_form = None
redirect_field_name = REDIRECT_FIELD_NAME
template_name = 'registration/login.html'
redirect_authenticated_user = False
extra_context = None
...
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
current_site = get_current_site(self.request)
context.update({
self.redirect_field_name: self.get_redirect_url(),
'site': current_site,
'site_name': current_site.name,
**(self.extra_context or {})
})
return context
LogoutView:
class LogoutView(SuccessURLAllowedHostsMixin, TemplateView):
"""
Log out the user and display the 'You are logged out' message.
"""
next_page = None
redirect_field_name = REDIRECT_FIELD_NAME
template_name = 'registration/logged_out.html'
extra_context = None
...
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
current_site = get_current_site(self.request)
context.update({
'site': current_site,
'site_name': current_site.name,
'title': _('Logged out'),
**(self.extra_context or {})
})
return context
I think the reason that LoginView has to pass the extra_context as a positional argument into .as_view() is that it doesn't inherit from TemplateView:
class TemplateView(TemplateResponseMixin, ContextMixin, View):
"""
Render a template. Pass keyword arguments from the URLconf to the context.
"""
def get(self, request, *args, **kwargs):
context = self.get_context_data(**kwargs)
return self.render_to_response(context)
which has a get method to get context data... if i'm not mistaken.
Could anyone confirm this?
I'm quite new to python and django framework. Thanks a lot!!!
The Original question has been answered
Please checkout the answers in the comments session --
I'm fairly new to Django and in order to pass in more context to logout view I tried 2 methods to customise the logout view:
Method 1:
from django.contrib.auth import views as auth_views
from boutique.models import Category
app_name = 'users'
urlpatterns = [
...
path('logout/', auth_views.LogoutView.as_view(), {'categories': Category.objects.all()}),
# I also tried this:
# path('logout/', auth_views.LogoutView.as_view({'categories': Category.objects.all()}),
# I also tried this:
# path('logout-customised-url/', auth_views.LogoutView.as_view(), {'categories': Category.objects.all()}),
# This is working tho it wouldn't be automatically redirect to this path when logged out
Method 2:
...
path('logout/', views.NewLogoutView.as_view()),
# NewLogoutView code below:
views.py
from boutique.models import Category
from django.contrib.auth.views import LogoutView
class NewLogoutView(LogoutView):
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['categories'] = Category.objects.all()
return context
Still not working, and the outcome is exactly the same: if a customised url is in use such as 'logged-out/' instead of 'logout/', and you type out the url, it renders the correct page with the extra context. However, wouldn't go to the page when users log out normally...
Is there any workaround? Thanks!
You need to pass extra_context in your urls.py inorder to send extra context to logout view. read more about passing extra context to a view from in url definition.
path(
'logout/',
auth_views.LogoutView.as_view(),
{'extra_context':{'categories': Category.objects.all()}}
),
Got it!! The problem was in the order of my urlpatterns, originally it was like this:
urlpatterns = [
# include django authentication urls
path('', include('django.contrib.auth.urls')),
# to customise default logout view
path('logout/', auth_views.LogoutView.as_view(), {'categories': Category.objects.get_categories_with_item()}),
Based on official doc: Authentication Views, django.contrib.auth.urls includes many url patterns, such as:
accounts/login/ [name='login']
accounts/logout/ [name='logout']
accounts/password_change/ [name='password_change']
accounts/password_change/done/ [name='password_change_done']
accounts/password_reset/ [name='password_reset']
accounts/password_reset/done/ [name='password_reset_done']
accounts/reset/<uidb64>/<token>/ [name='password_reset_confirm']
accounts/reset/done/ [name='password_reset_complete']
Therefore, they take precedence if they were declared before the customised. So:
urlpatterns = [
# to customise default logout view
path('logout/', auth_views.LogoutView.as_view(), {'categories': Category.objects.get_categories_with_item()}),
# include django authentication urls
path('', include('django.contrib.auth.urls')),
To swap the order, it works.
To the roockies like me:
Method 1 does work. Just pass in the additional context/argument like it states in the official doc after the view.
Also, I checked django.contrib.auth.views.LogoutView:
class LogoutView(SuccessURLAllowedHostsMixin, TemplateView):
"""
Log out the user and display the 'You are logged out' message.
"""
next_page = None
redirect_field_name = REDIRECT_FIELD_NAME
template_name = 'registration/logged_out.html'
extra_context = None
...
The extra_context is set to None for you to add extra context. Easy to customise if were to subclass it or simply pass in a positional argument into .as_view() -- which means:
urlpatterns = [
# to customise login view
path('login/', auth_views.LoginView.as_view(extra_context = {'categories': Category.objects.get_categories_with_item()})),
]
`Loginview` has the same the same convenient settings...
I have a Django app using djangorestframework. I want to return an empty response or nothing if the root URL is called. Below is my code.
url(r'^$', HttpResponse(''), name="redirect_to_somepage")
Expected output: [] or {}
Write a get function in your view.
view.py
from django.views.generic import View
from django.http import JsonResponse
class MyView(View):
def get(self, request, *args, **kwargs):
return JsonResponse({}, status=204)
urls.py
url(regex=r'^$', view=MyView.as_view(), name='index'),
After the user logs in i want to redirect to the view ('profile:profile_view')
settings.py
LOGIN_REDIRECT_URL = 'profile:profile_view'
I tried the above code but was not getting the result that i needed because iam passing slug into the url
urls.py
url(r'^(?P<slug>[-\w\d]+)/$', ProfileView.as_view(), name='view_profile'),
from here i tried the following.
settings.py
LOGIN_REDIRECT_URL = 'login_redirect'
urls.py
#login_required
def login_redirect(request):
return redirect('profile:profile_view', pk=request.user.pk, name=request.user.username)
Now i do get the username in the terminal but how do i use the username for the following 'localhost:8000/username'
views.py
class ProfileView(DetailView):
template_name = "profile/profile_view.html"
queryset = User.objects.all()
context_object_name = 'profile'
What am i doing wrong here? is there a better way?
Your profile URL accepts only one parameter called slug but you're passing it two parameters called pk and name.
First, change your URL like so:
url(r'^(?P<username>[-\w\d]+)/$', ProfileView.as_view(), name='view_profile'),
Now, correct the login_redirect view to make it look like this:
#login_required
def login_redirect(request):
return redirect('profile:profile_view', username=request.user.username)
You can also come in login in views.py and check and after that use httpresponseredirect to redirect user:
For examplele:
In urls.py :
From . Import views
Url(r'$login/', views.login, name="login"),
Url(r'$profile/', viesm.profile, name="profile"),
In views.py:
From django.shortcuts import get_object_or_404, render
From django.http import HttpResponseRedirect
Def login(request):
*** place to check if exist in your database***
If ***exist***:
User=request.post["username"]
Request.session["username"]=user
Return httpresponseredirect("../profile")
Else:
Return httpresponseredirect("../login")
Def profile(request):
If "user" in request.session:
Return render(request," **path to your template ", { "username" : request.session["username"] })
else:
Return httpresponseredirect("../login")
It should be better i think
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 have a good many class based views that use reverse(name, args) to find urls and pass this to templates. However, the problem is class based views must be instantiated before urlpatterns can be defined. This means the class is instantiated while urlpatterns is empty leading to reverse throwing errors. I've been working around this by passing lambda: reverse(name, args) to my templates but surely there is a better solution.
As a simple example the following fails with exception:
ImproperlyConfigured at xxxx
The included urlconf mysite.urls doesn't have any patterns in it
mysite.urls
from mysite.views import MyClassView
urlpatterns = patterns('',
url(r'^$' MyClassView.as_view(), name='home')
)
views.py
class MyClassView(View):
def get(self, request):
home_url = reverse('home')
return render(request, 'home.html', {'home_url':home_url})
home.html
<p><a href={{ home_url }}>Home</a></p>
I'm currently working around the problem by forcing reverse to run on template rendering by changing views.py to
class MyClassView(View):
def get(self, request):
home_url = lambda: reverse('home')
return render(request, 'home.html', {'home_url':home_url})
and it works, but this is really ugly and surely there is a better way. So is there a way to use reverse in class based views but avoid the cyclic dependency of urlpatterns requiring view requiring reverse requiring urlpatterns...
EDIT:
I'm using this as so:
views.py
def sidebar_activeusers(cls):
sidebar_dict = {'items' = []}
qs = models.random.filter.on.users
for user in qs:
item = {
'value': user.name,
'href': reverse('user_profile', args=[hash_id(user.id)])}
sidebar = loader.get_template('sidebar.html')
cls.base_dict['sidebar_html'] = sidebar.render(Context(sidebar_dict))
return cls
#sidebar_activeusers
class MyView1(View):
base_dict = {}
...
#other_sidebar_that_uses_same_sidebar_template
class MyView2(View):
basically I'd like to use the same sidebar template for a few different content types. Although the models displayed in the sidebar will be arbitrary the format will always be the same.
For your example MyClassView, it's ok to use reverse
class MyClassView(View):
def get(self, request):
home_url = reverse_lazy('home')
return render(request, 'home.html', {'home_url': home_url},
The reverse method is not called when the class is defined -- It is only called when the request is processed and the get method is called, so there shouldn't be an error. I have tested the example above and it works fine.
However, When you use your sidebar_activeusers decorator, the reverse call occurs before the url conf is loaded. In cases like these, you can use reverse_lazy. Here's an example of reverse_lazy in action:
from django.core.urlresolvers import reverse_lazy
class MyOtherClassView(View):
home_url = reverse_lazy('home')
def get(self, request):
return render(request, 'home.html', {'home_url':self.home_url})
This time, home_url is set when the class is defined, so reverse_lazy is required instead of reverse, because the url conf hasn't loaded yet.
Your home url can be accessed directly in your template by using declaring {% url 'home' %}. It's a standard way to access your named urls in your urls.py file.
You do not have to send the home_url variable to your template explicitly in your class-based view function.
In other words, in your home.html file:-
<p>Home</p>
will do.