can anyone help?
I want to print some counts from the DB (total records where the complete field = true and another when it equals false.
What have I done wrong in the below?
Thanks
VIEWS
def task_count(request):
completetasks = Todo.objects.filter(complete=True).count()
incompletetasks = Todo.objects.filter(complete=False).count()
return render(request, 'counts.html')
URLS
urlpatterns = [
url(r'^$', views.todo, name='index'),
url(r'^create/$', views.create_task, name='create'),
url(r'^counts/$', views.task_count, name='counts'),
COUNTS.HTML
{% extends 'base.html' %}
{% block content %}
<br><br><br>
{% if user.is_authenticated %}
<div class="container">
{% filter upper %}
<h3>Notes for task</h3>
{% endfilter %}
</div>
{{ completetasks }}
{% else %}
<h2>Login</h2>
{% endif %}
{% endblock %}
In your views file change like this
def task_count(request):
completetasks = Todo.objects.filter(complete=True).count()
incompletetasks = Todo.objects.filter(complete=False).count()
context = {
'completetasks': completetasks,
'incompletetasks': incompletetasks
}
return render(request, 'counts.html', context)
Then in counts.html
{{ completetasks }}
{{ incompletetasks }}
Related
What is the easiest / fastest way to override Django admin form to display grid of elements instead of list? My model includes a field for a 100x100px pic, and it would be easier to see them as a grid of pictures, not a list.
This is not terribly difficult, but it requires you to copy several large chunks of code from the Django library and incorporate them into your own application. Here's the overview:
You'll need to copy and then modify several template tags from django.contrib.admin.templatetags.admin_list:
django.contrib.admin.templatetags.admin_list.items_for_result
django.contrib.admin.templatetags.admin_list.result_list
django.contrib.admin.templatetags.admin_list.results
django.contrib.admin.templatetags.admin_list.result_list_tag
You'll need to copy and then modify a couple of templates:
django/contrib/admin/templates/admin/change_list.html
django/contrib/admin/templates/admin/change_list_results.html
For purposes of illustrating the solution, I have created an app called spam and a model called SpamPhoto, along with a model admin that is customized to display the image tag. I am using Bootstrap 4 for the grid. There are still some issues you might need to track down and figure out, like getting rid of the checkbox that shows up for each item. But this code should get about 90% of the way there.
Here's an overview of the files that I created/modified, and which you'll find below:
spam/models.py: contains the SpamPhoto model
spam/admin.py: contains the SpamPhotoAdmin
spam/templatetags/spamphoto_admin_list.py: contains the template tag / functions that will render the customized change list
spam/templates/admin/spam/spamphoto/change_list.html: this is the main changelist template, and only has a few small changes: it loads our custom template tags, it includes Bootstrap CSS, and it calls a customized template tag (defined below)
spam/templates/admin/spam/spamphoto/change_list_results.html: heavy modifications here, getting rid of the table elements and replacing with divs.
So again, this is a LOT of code, and most of it is lifted directly without very many changes. Here we go:
# spam/models.py
from django.db import models
class SpamPhoto(models.Model):
name = models.CharField(max_length=100)
image = models.ImageField()
# spam/admin.py
from django.contrib import admin
from django.utils.html import mark_safe
class SpamPhotoAdmin(admin.ModelAdmin):
list_display = ('name', 'image_tag')
list_display_links = ('name', 'image_tag')
def image_tag(self, obj):
return mark_safe(f'<img class="img-fluid" src="{obj.image.url}" />')
# spam/templatetags/spamphoto_admin_list.py
from django import template
# Note: you should import these from their "correct" locations! This is cheap/dirty:
from django.contrib.admin.templatetags.admin_list import (ResultList, result_headers, result_hidden_fields,
_coerce_field_name, lookup_field, ObjectDoesNotExist,
display_for_field, datetime, display_for_value, models,
mark_safe, NoReverseMatch, add_preserved_filters, format_html)
from django.contrib.admin.templatetags.base import InclusionAdminNode
register = template.Library()
def spamphoto_items_for_result(cl, result, form):
"""
Cloned from django.contrib.admin.templatetags.admin_list.items_for_result
The only modification is found at the very end of this function, where the HTML
tags are changed from `td` to `div`
"""
def link_in_col(is_first, field_name, cl):
if cl.list_display_links is None:
return False
if is_first and not cl.list_display_links:
return True
return field_name in cl.list_display_links
first = True
pk = cl.lookup_opts.pk.attname
for field_index, field_name in enumerate(cl.list_display):
empty_value_display = cl.model_admin.get_empty_value_display()
row_classes = ['field-%s' % _coerce_field_name(field_name, field_index)]
try:
f, attr, value = lookup_field(field_name, result, cl.model_admin)
except ObjectDoesNotExist:
result_repr = empty_value_display
else:
empty_value_display = getattr(attr, 'empty_value_display', empty_value_display)
if f is None or f.auto_created:
if field_name == 'action_checkbox':
row_classes = ['action-checkbox']
boolean = getattr(attr, 'boolean', False)
result_repr = display_for_value(value, empty_value_display, boolean)
if isinstance(value, (datetime.date, datetime.time)):
row_classes.append('nowrap')
else:
if isinstance(f.remote_field, models.ManyToOneRel):
field_val = getattr(result, f.name)
if field_val is None:
result_repr = empty_value_display
else:
result_repr = field_val
else:
result_repr = display_for_field(value, f, empty_value_display)
if isinstance(f, (models.DateField, models.TimeField, models.ForeignKey)):
row_classes.append('nowrap')
row_class = mark_safe(' class="%s"' % ' '.join(row_classes))
# If list_display_links not defined, add the link tag to the first field
if link_in_col(first, field_name, cl):
table_tag = 'th' if first else 'td'
first = False
# Display link to the result's change_view if the url exists, else
# display just the result's representation.
try:
url = cl.url_for_result(result)
except NoReverseMatch:
link_or_text = result_repr
else:
url = add_preserved_filters({'preserved_filters': cl.preserved_filters, 'opts': cl.opts}, url)
# Convert the pk to something that can be used in Javascript.
# Problem cases are non-ASCII strings.
if cl.to_field:
attr = str(cl.to_field)
else:
attr = pk
value = result.serializable_value(attr)
link_or_text = format_html(
'<a href="{}"{}>{}</a>',
url,
format_html(
' data-popup-opener="{}"', value
) if cl.is_popup else '',
result_repr)
yield format_html('<{}{}>{}</{}>', table_tag, row_class, link_or_text, table_tag)
else:
# By default the fields come from ModelAdmin.list_editable, but if we pull
# the fields out of the form instead of list_editable custom admins
# can provide fields on a per request basis
if (form and field_name in form.fields and not (
field_name == cl.model._meta.pk.name and
form[cl.model._meta.pk.name].is_hidden)):
bf = form[field_name]
result_repr = mark_safe(str(bf.errors) + str(bf))
# THIS LINE HAS BEEN CHANGED:
yield format_html('<div{}>{}</div>', row_class, result_repr)
if form and not form[cl.model._meta.pk.name].is_hidden:
# THIS LINE HAS BEEN CHANGED:
yield format_html('<div>{}</div>', form[cl.model._meta.pk.name])
def spamphoto_result_list(cl):
"""
Cloned from django.contrib.admin.templatetags.admin_list.result_list
The only change is to the `results` value in the returned dict, where we call `spamphoto_results`
"""
headers = list(result_headers(cl))
num_sorted_fields = 0
for h in headers:
if h['sortable'] and h['sorted']:
num_sorted_fields += 1
return {
'cl': cl,
'result_hidden_fields': list(result_hidden_fields(cl)),
'result_headers': headers,
'num_sorted_fields': num_sorted_fields,
# THIS LINE HAS BEEN CHANGED:
'results': list(spamphoto_results(cl)),
}
def spamphoto_results(cl):
"""
Cloned from django.contrib.admin.templatetags.admin_list.results
The only changes are where we call `spamphoto_items_for_result` instead of `items_for_result`
"""
if cl.formset:
for res, form in zip(cl.result_list, cl.formset.forms):
# THIS LINE HAS BEEN CHANGED:
yield ResultList(form, spamphoto_items_for_result(cl, res, form))
else:
for res in cl.result_list:
# THIS LINE HAS BEEN CHANGED:
yield ResultList(None, spamphoto_items_for_result(cl, res, None))
#register.tag(name='spamphoto_result_list')
def spamphoto_result_list_tag(parser, token):
"""
Cloned from django.contrib.admin.templatetags.admin_list.result_list_tag
The only change is to the `func` param, which now uses out custom `spamphoto_result_list` function
"""
return InclusionAdminNode(
parser, token,
# THIS LINE HAS BEEN CHANGED:
func=spamphoto_result_list,
template_name='change_list_results.html',
takes_context=False,
)
# spam/templates/admin/spam/spamphoto/change_list.html
{% extends "admin/base_site.html" %}
{% load i18n admin_urls static admin_list %}
<!-- ADDED THIS LINE / INCLUDING OUR CUSTOM TEMPLATE TAGS -->
{% load spamphoto_admin_list %}
{% block extrastyle %}
{{ block.super }}
<link rel="stylesheet" type="text/css" href="{% static "admin/css/changelists.css" %}">
{% if cl.formset %}
<link rel="stylesheet" type="text/css" href="{% static "admin/css/forms.css" %}">
{% endif %}
{% if cl.formset or action_form %}
<script src="{% url 'admin:jsi18n' %}"></script>
{% endif %}
{{ media.css }}
{% if not actions_on_top and not actions_on_bottom %}
<style>
#changelist table thead th:first-child {width: inherit}
</style>
{% endif %}
<!-- ADDED THIS LINE / INCLUDING BOOTSTRAP -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap#4.6.2/dist/css/bootstrap.min.css">
{% endblock %}
{% block extrahead %}
{{ block.super }}
{{ media.js }}
{% endblock %}
{% block bodyclass %}{{ block.super }} app-{{ opts.app_label }} model-{{ opts.model_name }} change-list{% endblock %}
{% if not is_popup %}
{% block breadcrumbs %}
<div class="breadcrumbs">
{% translate 'Home' %}
› {{ cl.opts.app_config.verbose_name }}
› {{ cl.opts.verbose_name_plural|capfirst }}
</div>
{% endblock %}
{% endif %}
{% block coltype %}{% endblock %}
{% block content %}
<div id="content-main">
{% block object-tools %}
<ul class="object-tools">
{% block object-tools-items %}
{% change_list_object_tools %}
{% endblock %}
</ul>
{% endblock %}
{% if cl.formset and cl.formset.errors %}
<p class="errornote">
{% if cl.formset.total_error_count == 1 %}{% translate "Please correct the error below." %}{% else %}{% translate "Please correct the errors below." %}{% endif %}
</p>
{{ cl.formset.non_form_errors }}
{% endif %}
<div class="module{% if cl.has_filters %} filtered{% endif %}" id="changelist">
<div class="changelist-form-container">
{% block search %}{% search_form cl %}{% endblock %}
{% block date_hierarchy %}{% if cl.date_hierarchy %}{% date_hierarchy cl %}{% endif %}{% endblock %}
<form id="changelist-form" method="post"{% if cl.formset and cl.formset.is_multipart %} enctype="multipart/form-data"{% endif %} novalidate>{% csrf_token %}
{% if cl.formset %}
<div>{{ cl.formset.management_form }}</div>
{% endif %}
{% block result_list %}
{% if action_form and actions_on_top and cl.show_admin_actions %}{% admin_actions %}{% endif %}
<!-- THIS LINE HAS BEEN CHANGED: -->
{% spamphoto_result_list cl %}
{% if action_form and actions_on_bottom and cl.show_admin_actions %}{% admin_actions %}{% endif %}
{% endblock %}
{% block pagination %}{% pagination cl %}{% endblock %}
</form>
</div>
{% block filters %}
{% if cl.has_filters %}
<div id="changelist-filter">
<h2>{% translate 'Filter' %}</h2>
{% if cl.has_active_filters %}<h3 id="changelist-filter-clear">
✖ {% translate "Clear all filters" %}
</h3>{% endif %}
{% for spec in cl.filter_specs %}{% admin_list_filter cl spec %}{% endfor %}
</div>
{% endif %}
{% endblock %}
</div>
</div>
{% endblock %}
# spam/templates/admin/spam/spamphoto/change_list_results.html
{% load i18n static %}
{% if result_hidden_fields %}
<div class="hiddenfields">{# DIV for HTML validation #}
{% for item in result_hidden_fields %}{{ item }}{% endfor %}
</div>
{% endif %}
{% if results %}
<div class="container">
<div class="row">
{% for result in results %}
{% if result.form and result.form.non_field_errors %}
<div>{{ result.form.non_field_errors }}</div>
{% endif %}
<div class="col-sm-2">{% for item in result %}{{ item }}{% endfor %}</div>
{% endfor %}
</div>
</div>
{% endif %}
What's happening. I still have trouble displaying the title list. Where did I make a mistake?
views.py
def dashboard(request):
bookmarks = Text_field.objects.order_by('created')
return render(request, 'Site/dashboard.html', {'bookmarks': bookmarks})
def about_me(request, pk):
about = get_object_or_404(Text_field, pk=pk)
return render(request, 'Site/about_me.html', {'about': about})
dashboard.html
{% extends "Site/base.html" %}
{% load static %}
{% block content %}
{% for bookmark in bookmarks %}
<div>
<p>Stworzono dn. {{ bookmark.created }}</p>
<h1>{{ bookmark.title }}</h1>
<p>{{ bookmark.text|linebreaksbr }}</p>
</div>
{% endfor %}
{% endblock %}
urls.py
path('', views.dashboard, name='dashboard'),
path('about/<int:pk>/', views.about_me, name='about_me'),
In your comment you say you defined an app_name in your urls.py, you need to include that app_name in your {% url ... %} name:
{% url 'Site:about_me' pk=bookmark.pk %}
I am using Django version 2.
I am working on a blog web app using PostgreSQL database.
I am trying to add a search feature to the web app but when I open the url (http://localhost:8000/search/) to make a search, I get the error below.
Page not found (404)
Request Method: GET
Request URL: http://localhost:8000/search/
Raised by: blog.views.post_detail
No Post matches the given query.
here is the blog/urls.py
from django.contrib.postgres.search import SearchVector
from .forms import CommentForm, SearchForm
from .models import Post, Comment
from django.shortcuts import render, get_object_or_404
from django.urls import path
from . import views
urlpatterns = [
path('', views.PostListView.as_view(), name='home'),
path('<slug:post>/', views.post_detail, name='post_detail'),
path('<int:post_id>/share', views.post_share, name='share'),
path('search/', views.post_search, name='post_search'),
]
here is the views.py
def post_detail(request, post):
post = get_object_or_404(Post, slug=post)
comments = post.comments.filter(active=True)
new_comment = None
if request.method == 'POST':
comment_form = CommentForm(data=request.POST)
if comment_form.is_valid():
new_comment = comment_form.save(commit=False)
new_comment.post = post
new_comment.save()
else:
comment_form = CommentForm()
return render(request, 'detail.html', {'post': post,
'comments': comments, 'new_comment':
new_comment,'comment_form': comment_form})
def post_search(request):
form = SearchForm()
query = None
results = []
if 'query' in request.GET:
form = SearchForm(request.GET)
if form.is_valid():
query = form.cleaned_data['query']
results = Post.objects.annotate(
search=SearchVector('title','body'),
).filter(search=query)
return render(request, 'search.html',
{'form':form,'query':query,'results':results})
Here are the templates files.
For search.html -(page to make query)
{% extends 'base.html' %}
{% block title %}Search{% endblock title %}
{% block page_title %}Search Posts{% endblock page_title %}
{% block content %}
{% if query %}
<h1>Posts containing "{{ query }}"</h1>
<h3>
{% with results.count as total_results %}
Found {{ total_results }} result{{ total_results|pluralize }}
{% endwith %}
</h3>
{% for post in results %}
<h4>{{ post.title }}</h4>
{{ post.body|truncatewords:5 }}
{% empty %}
<p>There is no results for your query.</p>
{% endfor %}
<p>Search again</p>
{% else %}
<h1>Search for posts</h1>
<form action="." method="GET">
{{ form.as_p }}
<input type="submit" value="Search">
</form>
{% endif %}
{% endblock content %}
For the html for post_detail
{% extends 'base.html' %}
{% load blog_tags %}
{% load crispy_forms_tags %}
{% load profanity %}
{% block title %}{{post.title}}{% endblock title %}
{% block navlink %}
<nav>
<ul>
<li class="current">Home</li>
<li>About</li>
<li >Services</li>
</ul>
</nav>
{% endblock navlink %}
{% block page_title %}{{post.title}}{% endblock page_title %}
{% block content %}
{{post.body|markdown}}
<p>Share this post via email</p>
{% with comments.count as total_comments %}
<h2>{{ total_comments }} comment{{ total_comments|pluralize }} </h2>
{% endwith %}
<div class="container">
{% for comment in comments %}
<div class="comment">
<p>Comment {{ forloop.counter }} by <em>{{ comment.name }}</em> - {{comment.created}} </p>
{{ comment.body|censor|linebreaks }}
</div>
{% empty %}
<p>There are no comments yet.</p>
{% endfor %}
{% if new_comment %}
<h2>Your comment has been added</h2>
{% else %}
<h2>Add a new comment</h2>
<form method="post">{% csrf_token %}
{{comment_form|crispy}}
<input class="button_1" type="submit" value="Add comment">
</form>
{% endif %}
</div>
{% endblock content %}
This is probably for one of the strange reason search is here actually matches with slug:post. One of easiest solution for your problem is to re-order urls and make sure /search place before. Like following
urlpatterns = [
path('', views.PostListView.as_view(), name='home'),
path('search/', views.post_search, name='post_search'),
path('<slug:post>/', views.post_detail, name='post_detail'),
path('<int:post_id>/share', views.post_share, name='share')
]
My suggestion for further developement whenever its need to add slug in url we need to make sure there is some prefix before it.
I have a page that shows a list of objects and I want to add a button beside each one to enable the user to delete it. I've found a few questions about similar scenarios online but for some reason I keep getting errors when I try to replicate the solutions.
Here is the delete function in views.py:
def delete_dish(request, pk):
query = Dish.objects.get_object_or_404(pk)
supermenu = query['supermenu'].pk
query.delete()
return redirect('foodmenu:menu', supermenu)
Here is the form in the HTML template:
{% if not supermenu.dish_set.count == 0 %}
<ul>
{% for dish in supermenu.dish_set.all %}
<li>
{{ dish.name }} - {{ dish.description }}
<form action="{% url 'foodmenu:delete_dish' dish.id %}" method="POST">
{% csrf_token %}
<button type="submit">X</button>
</form>
</li>
{% if not dish.price_set.count == 0 %}
<ul>
{% for price in dish.price_set.all %}
{% if price.label %}
<li>{{ price.label }}: {{ price.cost }}</li>
{% else %}
<li>{{ price.cost }}</li>
{% endif %}
{% endfor %}
</ul>
{% endif %}
{% endfor %}
</ul>
{% else %}
<p>No dishes on this menu!</p>
{% endif %}
And here is the urls.py:
app_name = 'foodmenu'
urlpatterns = [
...
path('dish/delete/<int:dish.id>', views.delete_dish, name="delete_dish")
]
When I click the button, the browser goes to ./dish/delete/1 (1 being the pk of the object), but Django returns a 404 error.
Instead of query = Dish.objects.get_object_or_404(pk) you should use get_object_or_404 shortcut:
from django.shortcuts import get_object_or_404
from django.views.decorators.http import require_POST
#require_POST
def delete_dish(request, pk):
if request.method
query = get_object_or_404(Dish, pk=pk)
supermenu = query.supermenu.pk
query.delete()
return redirect('foodmenu:menu', supermenu)
Also change your url pattern to this:
path('dish/delete/<int:pk>/', views.delete_dish, name="delete_dish")
UPD
As #daniherrera mentioned in his comment, you probably want to check request's method, to prevent accidental deletions. For this you can use require_POST decorator.
I was really confused why I was receiving Http404 error. To be more clear heres my code:
My app named books
views.py
from django.shortcuts import render_to_response
from django.http import Http404
from django.template import RequestContext
from books.models import *
def index(request):
title = 'Book Gallery'
books = Book.objects.all().order_by('-id')
lang_list = Lang.objects.all().order_by('-lang')
template = 'books/index.djhtml'
context = {'books': books, 'title': title, 'lang_list': lang_list}
return render_to_response( template, context, context_instance=RequestContext(request) )
def by_book_slug(request, bookslug):
slug = bookslug
try:
book = Book.objects.get(slug=slug)
except:
raise Http404
title = book.name
template = 'books/singlebook.djhtml'
context = {'book': book, 'title': title}
return render_to_response( template, context, context_instance=RequestContext(request) )
def by_lang_slug(request, langslug):
filter = langslug
try:
language = Lang.objects.get(slug=filter)
except:
raise Http404
lang_list = Lang.objects.all().order_by('-lang')
books = Book.objects.filter(lang=language).order_by('-id')
title = language
template = 'books/by_language.djhtml'
context = {'books': books, 'title': title, 'filter': filter, 'lang_list': lang_list}
return render_to_response( template, context, context_instance=RequestContext(request) )
urls.py inside my book app folder
from django.conf.urls import patterns, include, url
from books import views
urlpatterns = patterns('',
url(r'(?P<langslug>.*)/$', views.by_lang_slug, name='by_lang'),
url(r'(?P<bookslug>.*)/$', views.by_book_slug, name='by_book'),
url(r'^$', views.index, name='book_gallery'),
)
link that pertains to langslug url conf works but those links for bookslug url conf does not work. When I try to switch them down and up, one of them work and the other one is not.
I really don't know what is happening here. Any help will be a great help. Thanks.
the index template of my books app
{% extends 'base.djhtml' %}
{% block title %} | Gallery{% endblock %}
{% block stylesheets %}
<link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}css/style.css" />
{% endblock %}
{% block content_header %}
{% endblock %}
{% block content_body %}
<div class="row">
<div class="span3">
<strong>filtered by >
{% if filter %}
{{ filter }}
{% else %}
All
{% endif %}
</strong>
<ul class="nav nav-list">
<li class="nav-header">Filter</li>
<li class="nav-header
{% if not filter %}
active
{% endif %}
">All</li>
{% for list in lang_list %}
<li class="nav-header
{% if filter == list.slug %}
active
{% endif %}
">
{{ list.lang }}
</li>
{% endfor %}
</ul>
</div>
<div class="span9">
{% for book in books %}
<div class="span3">
<a href="{{ book.book_cover.url }}">
<img alt="{{book.name}}" src="{{ book.thumbnail.url }}" />
</a>
<h4>{{book.name}}</h4>
<p>{{book.desc|truncatewords:15}}</p>
View more...
</div>
{% endfor %}
</div>
</div>
{% endblock %}
The by_language template for my book app
{% extends 'base.djhtml' %}
{% block title %} | Gallery{% endblock %}
{% block stylesheets %}
<link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}css/style.css" />
{% endblock %}
{% block content_header %}
{% endblock %}
{% block content_body %}
<div class="row">
<div class="span3">
<strong>filtered by >
{% if filter %}
{{ filter }}
{% else %}
All
{% endif %}
</strong>
<ul class="nav nav-list">
<li class="nav-header">Filter</li>
<li class="nav-header
{% if not filter %}
active
{% endif %}
">All</li>
{% for list in lang_list %}
<li class="nav-header
{% if filter == list.slug %}
active
{% endif %}
">
{{ list.lang }}
</li>
{% endfor %}
</ul>
</div>
<div class="span9">
{% for book in books %}
<div class="span3">
<a href="{{ book.book_cover.url }}">
<img alt="{{book.name}}" src="{{ book.thumbnail.url }}" />
</a>
<h4>{{book.name}}</h4>
<p>{{book.desc|truncatewords:15}}</p>
View more...
</div>
{% endfor %}
</div>
</div>
{% endblock %}
I have included a raise Http404 method when specified slug does not match to any query in the database. The thing I was confused about is, when I try to switch langslug and bookslug urlconf, links that are associated to one of these url works and the other is not.
Based on your url, if I put value on it even though they have different view, the result would be:
urlpatterns = patterns('',
# http://localhost:8000/English/
url(r'(?P<langslug>.*)/$', views.by_lang_slug, name='by_lang'),
# http://localhost:8000/YourBook/
url(r'(?P<bookslug>.*)/$', views.by_book_slug, name='by_book'),
# http://localhost:8000/
url(r'^$', views.index, name='book_gallery'),
)
Have you notice it, they have the same pattern so the first view execute is the by_lang_slug. So if you change the order the other one will be executed first. The best thing to do about it is to have a unique url name.
urlpatterns = patterns('',
# http://localhost:8000/lang/English/
url(r'lang/(?P<langslug>.*)/$', views.by_lang_slug, name='by_lang'),
# http://localhost:8000/book/YourBook/
url(r'book/(?P<bookslug>.*)/$', views.by_book_slug, name='by_book'),
# http://localhost:8000/
url(r'^$', views.index, name='book_gallery'),
)
Now they are different....