can not render ' / ' in url in Django templates - django

Update :: Problem solved.just follow the guy below.
in my urls.py
path('', store_view, name='store'),
path('category/<str:category_name>/', category_view, name='category'),
in views.py
def store_view(request):
categories = list(Category.objects.all())
context = {
'categories': categories,
}
return render(request, 'store/store.html', context)
def category_view(request, category_name):
category = Category.objects.get(name=category_name)
context = {
'category': category,
}
return render(request, 'store/single-category-view.html', context)
in my template : store.html , that is rendered by store_view >>
{% for item in categories %}
<a href="{% url 'category' item.name %}">
{{item.name}}
</a>
{% endfor %}
Now,the problem is, in the category column in my DB, i have got one category called 'Laptop/MacBook'.when ever this name is passed to the url, it says >>
"Reverse for 'category' with arguments '('Laptop/MacBook',)' not
found. 1 pattern(s) tried: ['category/(?P<category_name>[^/]+)/$']
But when i changed the category name from Laptop/MacBook to Laptop and MacBook , it worked fine and showed no error.
But i want to keep it as it was,'Laptop/MacBook'.How can i do that??and how do you guys deal with that?

Try encoding and decoding your DB values. Assuming its Python 3:
from urllib.parse import quote, unquote
encoded = quote("Laptop/Macbook", safe="")
decoded = unquote(encoded)
print(encoded, decoded)
Output:
Laptop%2FMacbook Laptop/Macbook
With this your route should take in the right param.
from django.http import HttpResponse, request
from django.shortcuts import render
def store_view(request):
name = "Laptop/Macbook"
return render(request, './store.html', context={"name": name})
def category_view(request, category_name):
print(category_name)
return HttpResponse(b"Here we go!")
templatetags/tags.py
from urllib.parse import quote, unquote
from django import template
register = template.Library()
#register.filter(name='encode')
def encode(name):
return quote(name, safe="")
#register.filter(name='decode')
def decode(name):
return unquote(name)
Template:
{% load tags %}
<a href="{% url 'category' name|encode %}">
{{name}}
</a>
Don't forget to add in settings:
'OPTIONS': {
'libraries':{
'tags': 'templatetags.tags',
}
},

When using a "/", django thinks that you are passing more than one parameter. To fix this, replace str by path in your urls like so:
path('', store_view, name='store'),
path('category/<path:category_name>/', category_view, name='category'),
This will make django understand that the / does not mean there are two separate parameters in your url.

Related

How can I print the url to the order id field of my django form?

I am doing a simple form site with Django. This is what my sites url is looks like: mysite.com/register/12345678
I want to print the part after the register (12345678) to the order id field. When someone goes this mysite.com/register/87654321 url then i want to print it.
How can i do that? These are my codes.(Currently using Django 1.11.10)
forms.py
from django import forms
from .models import Customer
from . import views
class CustomerForm(forms.ModelForm):
class Meta:
model = Customer
fields = (
'order_id','full_name','company','email',
'phone_number','note')
widgets = {
'order_id': forms.TextInput(attrs={'class':'orderidcls'}),
'full_name': forms.TextInput(attrs={'class':'fullnamecls'}),
'company': forms.TextInput(attrs={'class':'companycls'}),
'email': forms.TextInput(attrs={'class':'emailcls'}),
'phone_number': forms.TextInput(attrs={'class':'pncls'}),
'note': forms.Textarea(attrs={'class':'notecls'}),
}
views.py
from django.shortcuts import render
from olvapp.models import Customer
from olvapp.forms import CustomerForm
from django.views.generic import CreateView,TemplateView
def guaform(request,pk):
form = CustomerForm()
if request.method == "POST":
form = CustomerForm(request.POST)
if form.is_valid():
form.save(commit=True)
else:
print('ERROR FORM INVALID')
theurl = request.get_full_path()
orderid = theurl[10:]
return render(request,'forms.py',{'form':form,'orderid':orderid})
customer_form.html
{% extends 'base.html' %}
{% block content %}
<h1>REGÄ°STRATÄ°ON</h1>
<form class="registclass" method="POST">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-default">REGISTER</button>
</form>
{% endblock %}
urls.py
from django.conf.urls import url
from django.contrib import admin
from olvapp import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^thanks/$',views.ThankView.as_view(),name='thank'),
url(r'^register/(?P<pk>\d+)',views.guaform,name='custform'),
]
You have passed the value to your view as 'pk' so you can use that to set the the initial value:
views.py
form = CustomerForm(initial={'order_id': pk})
SamSparx is right, here's some additional information to help prevent such errors in advance:
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^thanks/$',views.ThankView.as_view(),name='thank'),
url(r'^register/(?P<pk>\d+)',views.guaform,name='custform'),
]
You are using regex to parse your path. Regex is generally speaking not recommended in this case according to the docs because it might introduce more errors and is harder to debug. (Unoptimized) RegEx also tends to be slower.
For simple use cases such as your path here, consider choosing the default pathing syntax as below:
urlpatterns = [
url('admin/', admin.site.urls),
url('thanks/',views.ThankView.as_view(),name='thank'),
url('register/<int:pk>',views.guaform,name='custform'),
]
You could of course also use string instead of int depending on your usage of pk.
Your paths do not all end with a slash consistently. This might impact your SEO and confuse users. See this and this.
Also your form is not imported .as_view() for some reason which could cause some problems.

Django filtering database items

I am trying to build a project where I have a DB with toys where there are brands, each brand have products, the products have variety of sizes and sizes have colors. What I want to achieve is to have a home page with filtered the brands which I manage to achieve with the views.py below:
def Index(request):
toys = Toys.objects.values('brand').distinct().order_by('brand')
context = {'index': toys }
return render(request, 'index.html', context)
with models.py
class Toys(models.Model):
brand= models.CharField(max_length=255)
product = models.CharField(max_length=255)
size = models.CharField(max_length=255)
color = models.CharField(max_length=255)
Now on the main page I have a list with all the different brans, what I'm trying to do is when I click on any Brand for the home page to redirect me to a result page with list of the Brand's products, product will lead to all available sizes and so on.
How to implement that in the views?
Many approaches are possible. If you do not wish to have better functionality (e.g. all toys from brand 'X' are deleted when the brand is deleted from database), you could do the following.
Write a view function for each "level" of your listing. In the context dictionary, index contains the query result, listing is a heading to be displayed and level is a variable to select how the link is constructed in the template.
from django.shortcuts import render
from toyapp.models import Toys
def Index(request):
toys = Toys.objects.values('brand').distinct().order_by('brand')
context = { 'index': toys,
'listing': 'Toy brands:',
'level': 'brands',
}
return render(request,'toyapp/index.html', context)
def brandview(request, slug):
toys = Toys.objects.filter(brand=slug).order_by('product')
context = {'level': 'products',
'index': toys,
'listing': 'Products from brand ' + slug,
}
return render(request,'toyapp/index.html', context)
def productview(request, slug1, slug2):
toys_set = Toys.objects.filter(brand=slug1)
toys = toys_set.filter(product=slug2).order_by('size')
context = {'level': 'sizes',
'index': toys,
'listing': 'Sizes for product ' + slug2 + ' from brand ' + slug1
}
return render(request,'toyapp/index.html', context)
def sizeview(request, slug1, slug2, slug3):
toys_set = Toys.objects.filter(brand=slug1)
toys = toys_set.filter(product=slug2).order_by('size')
context = {'level': 'colors',
'index': toys,
'listing': 'Colors for size ' + slug3 + ' products ' + slug2 + ' from brand ' + slug1
}
return render(request,'toyapp/index.html', context)
The template index.html is quite simple with a {% for %} loop to go through items and {% if %} tags to select what kind of a link to create and what text to display.
<!DOCTYPE html>
<body>
<h2>{{ listing }}</h2>
{% for item in index %}
<li>
{% if level == 'brands' %}
<a href="{% url 'brandview' slug=item.brand %}" >{{item.brand}}</a>
{% elif level == 'products' %}
<a href="{% url 'productview' slug1=item.brand slug2=item.product %}" >{{item.product}}</a>
{% elif level == 'sizes' %}
<a href="{% url 'sizeview' slug1=item.brand slug2=item.product slug3=item.size %}" >{{item.size}}</a>
{% elif level == 'colors' %}
{{item.color}}
{% endif %}
</li>
{% endfor %}
</body>
Finally, you need to write urls.py with urlpatterns that parses the HTTP request address and passes the arguments to the view.
from django.urls import path, include
from . import views
urlpatterns = [
path('', views.Index, name='index'),
path('<slug:slug>', views.brandview, name='brandview'),
path('<slug:slug1>,<slug:slug2>', views.productview, name='productview'),
path('<slug:slug1>,<slug:slug2>,<slug:slug3>', views.sizeview, name='sizeview'),
]

Reverse error in Django 1.10

I'm new to Django and slowly learning how it works. I just upgraded to 1.10 and part of my app stopped working. I know it is related to the changes made into Reverse. I have been reading and I cannot find exactly what I'm doing wrong. Almost everything works as it should with a couple of exceptions. The behavior is as follows:
1) On my app I load reservations/create, it works perfectly I can create my reservation
2) When I click create, the reservation is actually created and saved into the database, but the browser is sent to the wrong address. It gets sent to reservations/create instead of reservations/reservation number (for example reservations/2 where it shows its details) and shows a Reverse error (included in this post)
3) If I test reservations/2 for example, it shows that it was actually created.
4) Also if a go straight to reservations/ it should show a list of all the ones already create, but instead shows a Reverse error too.
I would really appreciate any help in understanding what I'm doing wrong.
Models.py
class Reservation(models.Model):
res_number = models.AutoField(primary_key=True)
date = models.DateField(default=datetime.date.today())
status = models.CharField(max_length=10,default="Created")
reservation_type = models.CharField(max_length=11,choices=shced_type_choices, default="rental")
aircraft = models.ForeignKey('aircraft.Aircraft')
renter = models.CharField(max_length=30,blank=False,null=False)
instructor = models.CharField(max_length=30,blank=True,null=False)
def get_absolute_url(self):
return reverse("reservations:detail", kwargs={"res_number": self.res_number})
Main urls.py
url(r'^reservations/', include('dispatch.urls', namespace='reservations')),
Dispatch.urls
from django.conf.urls import include, url
from django.contrib import admin
from .views import (
reservations_list,
reservations_detail,
reservations_edit,
reservations_dispatch,
reservations_close,
reservations_cancel,
reservations_create,
reservations_close,
)
urlpatterns = [
url(r'^$', reservations_list),
url(r'^(?P<res_number>\d+)/$', reservations_detail),
url(r'^(?P<res_number>\d+)/edit/$', reservations_edit),
url(r'^(?P<res_number>\d+)/dispatch/$', reservations_dispatch),
url(r'^(?P<res_number>\d+)/close/$', reservations_close),
url(r'^(?P<res_number>\d+)/cancel/$', reservations_cancel),
url(r'^create/$', reservations_create),
url(r'^close/$', reservations_close),
]
Views.py
from django.contrib import messages
from django import forms
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render, get_object_or_404
from .forms import ReservationForm, CloseReservationForm
from .models import Reservation
def reservations_list(request):
queryset = Reservation.objects.all()
context = {
"object_list": queryset,
"title": "List of Reservations:"
}
return render(request, "dispatch/list.html", context)
def reservations_detail(request, res_number=None):
instance = get_object_or_404(Reservation, res_number=res_number)
context = {
"title": instance.renter,
"instance": instance,
}
return render(request, "dispatch/details.html", context)
def reservations_create(request):
form = ReservationForm(request.POST or None)
if form.is_valid():
instance = form.save(commit=False)
print(instance.aircraft.hobbs)
instance.save()
messages.success(request, "Reservation Created")
return HttpResponseRedirect(instance.get_absolute_url())
context = {
"form": form,
}
return render(request, "dispatch/create.html", context)
Details.html
{% extends "dispatch/base.html" %}
{% block head_title %}{{ block.super }} | {{instance.res_number}}{% endblock head_title %}
{% block content %}
<h1>Reservation for {{title}} on {{instance.date}}</h1>
Reservation Number: {{instance.res_number}}</br>
Date: {{instance.date}}</br>
Status: {{instance.status}}</br>
Reservation Type: {{instance.reservation_type}}</br>
Aircraft: {{instance.aircraft}}</br>
Renter's Name: {{instance.renter}}</br>
Instructor's Name: {{instance.instructor}}</br>
Expected Flight Hours: {{instance.expected_hours}} Hrs</br>
Actual Flown Hours: {{instance.flown_hours}} Hrs</br>
Reservation Created on: {{instance.created}}</br>
Last Updated on: {{instance.updated}}</br>
{% endblock content %}
Create.html
{% extends "dispatch/base.html" %}
{% block head_title %}{{ block.super }} | Create{% endblock head_title %}
{% block content %}
<h1>Create Reservation</h1>
<form method='POST' action=''>{% csrf_token %}
{{form.as_p}}
<input type="submit" name="Create Reservation">
</form>
{% endblock content %}
Reverse error screenshot
Your problem is your routes don't have names. So when you are using reverse('some_name'), you have to have such name defined. The name is detail in your case, so you want to do something like this (see the parameter name)
urlpatterns = [
url(r'^(?P<res_number>\d+)/$', reservations_detail, name='detail'),
]
Also please don't insert traceback as a screenshot. You see the link 'switch to copy-and-paste view'? Yeah, use that the next time.

How Django's url template tag works?

How does {"% url 'news_id' %"} work?
I do have a url pattern url(r'^((?:\w|-)+)/$', 'comments.views.home', name='news_id') but I still get NoReverseMatch.
It says
Reverse for 'news_id' with arguments '()' and keyword arguments '{}' not found. 1 pattern(s) tried: ['((?:\w|-)+)/$']
views.py
from django.shortcuts import render
from comments.models import User
from django.http import HttpResponseRedirect, HttpResponse
from django.template import RequestContext, loader, Context
from comments.models import News, User, Comment
from django.core.urlresolvers import resolve
def home(request, url_arg):
print "in Views.py", "and url_arg = ", url_arg
c = Comment.objects.all().filter(news__news_id=url_arg)
n = News.objects.all().get(news_id=url_arg)
cont = Context({'news': n.text, 'cts': c, 'news_id': n.news_id})
rc = RequestContext(request, cont)
t = loader.get_template('home.html')
print 'n = ', n
return HttpResponse(t.render(rc))
return render(request, 'home.html', context_dict, context_instance=RequestContext(request))
def submit(request):
print "request.path_info = ", request.path_info
print "in submit method and url = ", resolve(request.path_info).url_name, " & other try = ", request.resolver_match.url_name
news_id = request.POST.get('news_id')
user_id = request.POST.get('user_id')
comment_text = request.POST.get('comment')
print "news_id =", news_id, "user_id = ", user_id, "comment_text = ", comment_text
n = News(news_id=news_id)
n.save()
u = User(name='random',user_id=user_id)
u.save()
c = Comment(news=n, user=u, text=comment_text)
c.save()
return HttpResponse("Thanks!")
urls.py
from django.conf.urls import include, url
from django.contrib import admin
urlpatterns = [
# Examples:
url(r'^(?:\w|-)+/submit/$','comments.views.submit'),
url(r'^((?:\w|-)+)/$', 'comments.views.home', name='news_id'),
# url(r'^blog/', include('blog.urls')),
url(r'^admin/', include(admin.site.urls)),
]
home.html
<p>
News: {{news}}<br>
</p>
<form action="{% url news_id %}" method="post"> {% csrf_token %}
User Id: <input type="text" name="user_id"> <br>
Comment:<br>
<input type="text" name="comment" placeholder="Express your opinion ...">
<input type="submit" value="Submit"> <br>
{% for ct in cts %}
{{ ct.text }}<br>
{% endfor %}
</form>
You've misunderstood a few things here. In particular, you've mixed up the name of the URL pattern, and the parameters you need to pass to it.
For instance, if you wanted to capture the ID of a post in your blog and pass it to a detail view, you would normally do something like:
url(r'^(?P<post_id>)/$', views.post_detail, name='post_detail')
so the name of the pattern is post_detail and the parameter it takes is called post_id. So you would reverse it by doing:
{% url "post_detail" post_id=my_post.id %}
Also, your regex is very odd. You have a non-capturing group as the only contents of a capturing group. I can't tell what you are actually trying to do with that pattern, but normally a home page wouldn't take any parameters at all - and in fact you are not actually passing any parameters. Just use r'^$'.

django template inheritance and context

I am reading the definitive guide to django and am in Chapter 4 on template inheritance. It seems that I am not doing something as elegant as should be possible as I am having to duplicate some code for the context to appear when calling the child view. Here is the code in views.py:
def homepage(request):
current_date = datetime.datetime.now()
current_section = 'Temporary Home Page'
return render_to_response("base.html", locals())
def contact(request):
current_date = datetime.datetime.now()
current_section = 'Contact page'
return render_to_response("contact.html", locals())
It seems redundant to have to include the current_date line in each function.
Here is the base html file that homepage calls:
<html lang= "en">
<head>
<title>{% block title %}Home Page{% endblock %}</title>
</head>
<body>
<h1>The Site</h1>
{% block content %}
<p> The Current section is {{ current_section }}.</p>
{% endblock %}
{% block footer %}
<p>The current time is {{ current_date }}</p>
{% endblock %}
</body>
</html>
and a child template file:
{% extends "base.html" %}
{% block title %}Contact{% endblock %}
{% block content %}
<p>Contact information goes here...</p>
<p>You are in the section {{ current_section }}</p>
{% endblock %}
If I don't include the current_date line when calling the child file, where that variable should appear is blank.
You can pass a variable to every template by using a Context Processor:
1. Adding the context processor to your settings file
First, you will need to add your custom Context Processor to your settings.py:
# settings.py
TEMPLATE_CONTEXT_PROCESSORS = (
'myapp.context_processors.default', # add this line
'django.core.context_processors.auth',
)
From that you can derive that you will need to create a module called context_processors.py and place it inside your app's folder. You can further see that it will need to declare a function called default (as that's what we included in settings.py), but this is arbitrary. You can choose whichever function name you prefer.
2. Creating the Context Processor
# context_processors.py
from datetime import datetime
from django.conf import settings # this is a good example of extra
# context you might need across templates
def default(request):
# you can declare any variable that you would like and pass
# them as a dictionary to be added to each template's context:
return dict(
example = "This is an example string.",
current_date = datetime.now(),
MEDIA_URL = settings.MEDIA_URL, # just for the sake of example
)
3. Adding the extra context to your views
The final step is to process the additional context using RequestContext() and pass it to the template as a variable. Below is a very simplistic example of the kind of modification to the views.py file that would be required:
# old views.py
def homepage(request):
current_date = datetime.datetime.now()
current_section = 'Temporary Home Page'
return render_to_response("base.html", locals())
def contact(request):
current_date = datetime.datetime.now()
current_section = 'Contact page'
return render_to_response("contact.html", locals())
# new views.py
from django.template import RequestContext
def homepage(request):
current_section = 'Temporary Home Page'
return render_to_response("base.html", locals(),
context_instance=RequestContext(request))
def contact(request):
current_section = 'Contact page'
return render_to_response("contact.html", locals(),
context_instance=RequestContext(request))
So, you can use django.views,generic.simple.direct_to_template instead of render_to_response. It uses RequestContext internaly.
from django.views,generic.simple import direct_to_template
def homepage(request):
return direct_to_template(request,"base.html",{
'current_section':'Temporary Home Page'
})
def contact(request):
return direct_to_template(request,"contact.html",{
'current_section':'Contact Page'
})
Or you can even specify it directly at urls.py such as
urlpatterns = patterns('django.views.generic.simple',
(r'^/home/$','direct_to_template',{
'template':'base.html'
'extra_context':{'current_section':'Temporary Home Page'},
}),
(r'^/contact/$','direct_to_template',{
'template':'contact.html'
'extra_context':{'current_section':'Contact page'},
}),
For django v1.8+ variables returned inside context processor can be accessed.
1. Add the context processor to your TEMPLATES list inside settings.py
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
'your_app.context_processor_file.func_name', # add this line
],
},
},
]
2. Create new file for context processor and define method for context
context_processor_file.py
def func_name(request):
test_var = "hi, this is a variable from context processor"
return {
"var_for_template" : test_var,
}
3. Now you can get the var_for_template in any templates
for example, add this line inside: base.html
<h1>{{ var_for_template }}</h1>
this will render:
<h1>hi, this is a variable from context processor</h1>
for updating templates to django 1.8+ follow this django doc