Django - Reusing views in different templates - python

It's probably a stupid question but its really late here and my brain died after my 6th coffee.
I'm building (or trying to) a simple blogging application that would display an article index on the homepage - aka. recent articles - and on the main blog page. To do so I've managed to scribble out a following view:
def index(request):
'''Article index'''
archive_dates = Article.objects.datetimes('date_publish','month', order='DESC')
categories = Category.objects.all()
page = request.GET.get('page')
article_queryset = Article.objects.all()
paginator = Paginator(article_queryset, 5)
try:
articles = paginator.page(page)
except PageNotAnInteger:
#If page requested is not an integer, return first page.
articles = paginator.page(1)
except EmptyPage:
#If page requested is out of range, deliver last page of results.
articles = paginator.page(paginator.num_pages)
return render(
request,
'blog/article/index.html',
{
'articles': articles,
'archive_dates': archive_dates,
'categories': categories
}
)
However to display the index within two different URLs I've copied the code changing only few variables, ie. name and template to render.
What could I do to render this view within both URLs yet not duplicate it in my views.py?
Am I right in thinking that I'd have to have 3 views, a main one and two sub ones that would import the code from the main one?
Or should I be using a custom template tag instead?
EDIT
As requested, adding urls.py
from django.conf.urls import *
from django.contrib import admin
from settings import MEDIA_ROOT
from django.views.generic import TemplateView
from blog.views import *
admin.autodiscover()
urlpatterns = patterns('',
#Blog URLs
url('^$', home_index, name='blog-preview'),
url('^blog/archive/(?P<year>[\d]+)/(?P<month>[\d]+)/$', date_archive, name='blog-date-archive'),
url('^blog/archive/(?P<slug>[-\w]+)/$', category_archive, name='blog-category-archive'),
url('^blog/categories/', category_list, name='blog-category-list' ),
url('^blog/(?P<slug>[-\w]+)/$', single, name='blog-article-single'),
url('^blog/$', index, name='blog-article-index'),
url(r'^contact/', include("contact_form.urls", namespace="contact_form")),
url(r'^admin/', include(admin.site.urls)),
)

It's very simple: map two urls in your conf to the view like this:
urlpatterns = patterns('',
url(r'first_expression', index, name='first'),
url(r'second_expression', index, name='second'),
)
Also, a little advise on your code: try to avoid wildcard imports. They are dangerous...
Insead use:
from package import MyClass, my_function, my_etc

Related

How to get limited results per page in django using pagination?

I am following a udemy course where I am making a real estate website using Django. I have come so far and have been fighting with the errors but I am stuck with the pagination error that I am facing right now.
I see everything is working fine in the video but when I follow it exactly it does not work. The issue is that when I set a limit on items per page, it does not seem to be working as I see all the results on the same page.
Here is my views.py
from django.shortcuts import render
from django.core.paginator import Paginator
from .models import Listing
def index(request):
listings = Listing.objects.all().order_by('-id')
paginator = Paginator(listings, 3)
page_number = request.GET.get('page')
page_obj = paginator.get_page(page_number)
context = {
'listings': listings
}
return render(request, 'listings/listings.html', context)
It's my Urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='listings'),
path('<int:listings_id>', views.listing, name='listing'),
path('search', views.search, name='search')
As you can see, I have set maximum 3 listings per page but I am getting all of them on a single page which is not what I want. It would be great if anyone could help. Thanks for your time and efforts.
You are returning whole listings instead of Paginator page inside of context
context = {
'listings': page_obj
}
More regarding pagination you can check also in documentation

Django unexpected characters in URL

I am making a blog and trying to make pagination operations on post listing page. When I run my app, my URL contains unexpected characters. For example ;
http://127.0.0.1:8000/blog/%5E$
I couldn't understand why %5E$ is there.
Here my urls.py (this is in blogapp):
from django.urls import path,include
from django.contrib import admin
from . import views
urlpatterns = [
path(r'^$',views.getPosts,name="bloghome"),
path(r'^(?P<selected_page>\d+)/?$',views.getPosts,name="bloghome"),
path('<slug>',views.postDetailPage,name="post_detail")
]
getPost function in views.py
def getPosts(request,selected_page=1):
# latest_post = Posts.objects.get(id=1)
posts = Posts.objects.all().order_by('-pub_date')
pages = Paginator(posts,5) #Show 5 post per page
try:
returned_page = pages.page(selected_page)
except EmptyPage:
returned_page = pages.page(pages.num_pages)
#content = pages.page(selected_page)
return render(request,'blog.html',{'page':returned_page,
'posts':returned_page.object_list
})
And finally, this bloglist page is being entered from homepage with <a> tag. Here it's one line of code:
Blog
Based upon https://docs.djangoproject.com/en/dev/ref/urls/#django.urls.path, you need to use re_path() instead of path(), as it is interpreting ^$ literally, per zvadym's prior comment. This is new in Django 2.0, so it depends on your version.

Page not found with "empty slug" pattern on Django

In my application, I want to show a list of items based on certain url. For example, when I type mysite.com/restaurants/chinese/, I want to show all the Chinese restaurants. If I type mysite.com/restaurants/american/, I want to show all the American restaurants and so on. But when I type mysite.com/restaurants/ I want to show all the restaurants, so I wrote this code:
urls.py
from django.conf.urls import url, include
from django.contrib import admin
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^restaurants/', include('restaurants.urls')),
]
restaurants/urls.py
from django.conf.urls import url
from django.views.generic import ListView
from .views import RestaurantLocationListView
urlpatterns = [
url(r'^(?P<slug>\w+)/$', RestaurantLocationListView.as_view()),
]
restaurants/views.py
from django.db.models import Q
from django.shortcuts import render
from django.views.generic import ListView
from .models import RestaurantLocation
class RestaurantLocationListView(ListView):
def get_queryset(self):
slug = self.kwargs.get('slug')
if slug:
queryset = RestaurantLocation.objects.filter(
Q(category__iexact=slug) | Q(category__icontains=slug)
)
else:
queryset = RestaurantLocation.objects.all()
return queryset
It's everything working well, except when I put only mysite.com/restaurants/. This gives me an 404 error instead the list of all restaurants and I don't know why. Can you guys help me?
Seems like a url issue. In your restaraunts/url.py you need to add a url for it.
urlpatterns = [
url(r'^$', RestaurantLocationListView.as_view()), # add it before
url(r'^(?P<slug>\w+)/$', RestaurantLocationListView.as_view()),
]

Add context to every Django Admin page

How do I add extra context to all admin webpages?
I use default Django Admin for my admin part of a site.
Here is an url entry for admin:
urlpatterns = [
url(r'^admin/', admin.site.urls),
]
And my apps register their standard view models using:
admin.site.register(Tag, TagAdmin)
My problem, is that I want to display an extra field in admin template header bar and I have no idea how to add this extra context.
My first bet was adding it in url patterns like below:
urlpatterns = [
url(r'^admin/', admin.site.urls, {'mycontext': '123'}),
]
But that gives an error:
TypeError at /admin/tickets/event/4/change/
change_view() got an unexpected keyword argument 'mycontext'
Can you give any suggestion? I really do not want to modify every AdminModel class I have to insert this context, as I need it on every admin page.
Thanks.
Found the solution, url registration has to be:
urlpatterns = [
url(r'^admin/', admin.site.urls, {'extra_context': {'mycontext': '123'}}),
]
Its a context dictionary inside of a dictionary with 'extra_context' as a key.
Another technique, more complex but allows different context per request (probably unavailable at OP time):
my_project/admin.py (create if missing)
from django.contrib import admin
from django.contrib.admin.apps import AdminConfig
class MyAdminConfig(AdminConfig):
default_site = 'my_project.admin.MyAdminSite'
class MyAdminSite(admin.AdminSite):
def each_context(self, request):
context = super().each_context(request)
context.update({
"whatever": "this is",
"just a": "dict",
})
return context
settings.py
INSTALLED_APPS = [
...
'my_project.admin.MyAdminConfig', # replaces 'django.contrib.admin'
...
The replace / extend admin class code is taken from the official docs except this is all in one file.

Django; Will not make the correct request

I am just beginning to learn how to use django. I have set up my views.py, urls.py, settings.py, and relative HTML pages. I am able to get the index page to come up but not the about page (only outputs some text) or my category page. I am assuming that the problem is affecting them both.
Views.py:
from django.http import HttpResponse
from django.template import RequestContext
from django.shortcuts import render_to_response
from rango.models import Category
from rango.models import Page
def index(request):
# Obtain the context from the HTTP request.
context = RequestContext(request)
category_list = Category.objects.order_by('id')[:5]
context_dict = {'categories': category_list}
# Render the response and send it back!
return render_to_response('index.html', context_dict, context)
def about(request):
# Request the context of the request.
# The context contains information such as the client's machine details, for example.
context = RequestContext(request)
context_dict = {'boldmessage': "I am from the context"}
return render_to_response('/about.html', context_dict, context)
def category(request, category_name_url):
# Request our context from the request passed to us.
context = RequestContext(request)
category_name = category_name_url.replace('_', ' ')
context_dict = {'category_name': category_name}
try:
category = Category.objects.get(name=category_name)
pages = Page.objects.filter(category=category)
# Adds our results list to the template context under name pages.
context_dict['pages'] = pages
context_dict['category'] = category
except Category.DoesNotExist:
# Go render the response and return it to the client.
return render_to_response('rango/category.html', context_dict, context)
urls.py:
from django.conf.urls import patterns, url
from rango import views
# At the top of your urls.py file, add the following line:
from django.conf import settings
urlpatterns = patterns('',
url(r'$', views.index,name='index'),
url(r'about/$', views.about,name='about'))
#url(r'category/$', views.category,name='category'))
# UNDERNEATH your urlpatterns definition, add the following two lines:
if settings.DEBUG:
urlpatterns += patterns(
'django.views.static',
(r'media/(?P<path>.*)','serve',{'document_root': settings.MEDIA_ROOT}), )
My template directory has been hard coded so it really shouldn't be a problem
TEMPLATE_DIRS = ('C:/Users/aharon/Desktop/TEMP',)
Keep in mind that I am very noob so please be easy on me and I would like as much explanation as possible. Thank You!
You have not anchored your regexes with ^ at the start. Without that, your first pattern will match every single URL. You should makes sure they all start with ^.

Categories