I'm working on Django model forms. I have created forms.py and added the following:
from django import forms
from .models import Product
class ProductForm(forms.ModelForm):
class Meta:
model = Product
fields = [
'title',
'description',
'price'
]
And I have rendered this out in my views.py as it follows:
def product_create_view(request):
form = ProductForm(request.POST or None)
if form.is_valid():
form.save()
context = {
'form': form
}
return render(request, "products/product_create.html", context)
and I have added urls.py:
from django.contrib import admin
from django.urls import path
from pages.views import home_view , contact_view, about_view, social_view
from products.views import product_detail_view, product_create_view
urlpatterns = [
path('', home_view, name='home'),
path('contact/', contact_view),
path('admin/', admin.site.urls),
path('about/', about_view),
path('create/', product_create_view),
path('product/', product_detail_view),
path('social/', social_view),
]
I have migrated everything and saved all files, but when I want to go to my create URL, I get this error:
TemplateDoesNotExist at /create/
products/product_create.html
Request Method: GET
Request URL: http://127.0.0.1:8000/create/
Django Version: 3.2.4
Exception Type: TemplateDoesNotExist
Exception Value:
products/product_create.html
Exception Location: C:\Users\Invoker\dev\trydjango\env\lib\site-packages\django\template\loader.py, line 19, in get_template
Python Executable: C:\Users\Invoker\dev\trydjango\env\Scripts\python.exe
Python Version: 3.9.5
Python Path:
['C:\\Users\\Invoker\\dev\\trydjango\\src\\sadra',
'C:\\Program Files\\Python39\\python39.zip',
'C:\\Program Files\\Python39\\DLLs',
'C:\\Program Files\\Python39\\lib',
'C:\\Program Files\\Python39',
'C:\\Users\\Invoker\\dev\\trydjango\\env',
'C:\\Users\\Invoker\\dev\\trydjango\\env\\lib\\site-packages']
Server time: Wed, 23 Jun 2021 08:20:29 +0000
I have created a template as well:
{% extends 'base.html' %}
{% block content %}
<form>
{{ form.as_p }}
<input type='submit' value='Save' />
</form>
{% endblock %}
Templates in settings.py would be like this:
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, "templates")],
'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',
],
},
},
]
I have my templates in a folder called templates in the root directory. In there I have another folder called products which includes detail.html and product_create.html
What should I do?
I'm a little unclear as to your dir structure as you say "another directory", not a sub directory.
Good practice in Django is to nest dirs under a templates dir using the appname, so in our case
project/templates/products/product_create.html
Should do the trick.
You can have the templates folder in the project root, or you can have it in an app dir for dev (since you have set APP_DIRS to True), but you need to keep the same nesting structure.
As it stands, your project is simply not finding the correct template. Your view has the right path, but the template is in the wrong place.
Related
I have a simple blog code in Django , I write the error and my codes:
there is my codes
models.py
from django.db import models
class Post(models.Model):
title = models.CharField(max_length=200)
author = models.ForeignKey(
'auth.User',
on_delete=models.CASCADE,
)
body = models.TextField()
def __str__(self):
return self.title
views.py
from django.views.generic import ListView
from .models import Post
class BlogListView(ListView):
model = Post
template_name = 'home.html'
urls.py
from django.urls import path
from .views import BlogListView
urlpatterns = [
path('', BlogListView.as_view(), name= 'home')
]
and home.html
{% extends 'base.html' %}
{% block content %}
{% for post in object_list %}
<div class="post-entry">
<h2>{{ post.title }}</h2>
<p>{{ post.body }}</p>
</div>
{% endfor %}
{% endblock content %}
There is Error message after running code:
AttributeError at /admin/blog/post
'list' object has no attribute 'lower'
Request Method: GET
Request URL: http://127.0.0.1:8000/admin/blog/post
Django Version: 3.1.5
Exception Type: AttributeError
Exception Value:
'list' object has no attribute 'lower'
Exception Location: C:\Users\nilaroz\.virtualenvs\blog-Keg_c4F1\lib\site-packages\django\utils\http.py, line 295, in is_same_domain
Python Executable: C:\Users\nilaroz\.virtualenvs\blog-Keg_c4F1\Scripts\python.exe
Python Version: 3.8.6
Python Path:
['D:\\MyDjangoProject\\blog',
'c:\\program files (x86)\\python38-32\\python38.zip',
'c:\\program files (x86)\\python38-32\\DLLs',
'c:\\program files (x86)\\python38-32\\lib',
'c:\\program files (x86)\\python38-32',
'C:\\Users\\nilaroz\\.virtualenvs\\blog-Keg_c4F1',
'C:\\Users\\nilaroz\\.virtualenvs\\blog-Keg_c4F1\\lib\\site-packages']
Server time: Sun, 31 Jan 2021 19:53:08 +0000
why? I don't make any list!
what's mean "'list' object has no attribute 'lower'"?
I think maybe Django makes a list when call for loop!
{% for post in object_list %}
how I do solve this problem?
I find the solve:
I by mistake write
'DIRS': [str(BASE_DIR.joinpath('templates'))],
in the
ALLOWED_HOSTS = []
while should write it in the settings.py in "TEMPLATES"
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',
],
},
'DIRS': [str(BASE_DIR.joinpath('templates'))],
},
]
I recommend that do not code when are very tired. Sleep!
Right now I have a Django project with three apps. In my last app, the index.html loaded by my views.py is the index.html in another app's templates folder. Note this is how it is actually loading it, but not how I intend it load. The index.html in templates where the corresponding views.py is defined is not used. What I am wondering is how I define my settings so that the templates folder for the current application directory is used. This is my settings.py with respect to templates:
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')],
'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',
],
},
},
]
This is the call to index.html
def indexView(request):
form = FriendForm()
friends = Friend.objects.all()
return render(request, "index1.html", {"form": form, "friends": friends})
A good practice is that from the inside of your urls.py from your app, you add :
app_name = 'your_app_name' # Now, you can call this app from the {% url tag %}
And your template structure should contain app directories, and when you want to render to a different template you can use :
return render(request, 'myApp1/index.html')
return render(request, 'myApp2/index.html')
But remember, in your main templates folder, you need to add 2 directories,
templates/myApp1/index.html,
and
templates/myApp2/index.html
And finally, did you added app_name to your apps URLs? And after that try with the first one, or with the full path.
{% url 'myApp1:post_friend' %} or full path {% url 'myApp1/index.html' %}
I have this pieces of code:
# newspaper_project/urls.py
from django.contrib import admin
from django.urls import path, include
from django.views.generic.base import TemplateView
urlpatterns = [
path('', TemplateView.as_view(template_name='home.html'), name='home'),
path('admin/', admin.site.urls),
path('users/', include('users.urls'))
path('users/', include('django.contrib.auth.urls')),
]
# users/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('signup/', views.SignUp.as_view(), name='signup'),
]
# users/views.py
from django.urls import reverse_lazy
from django.views import generic
from .forms import CustomUserCreationForm
class SignUp(generic.CreateView):
form_class = CustomUserCreationForm
success_url = reverse_lazy('login')
template_name = 'signup.html'
<!-- templates/home.html -->
{% block title %}Home{% endblock %}
{% block content %}
{% if user.is_authenticated %}
Hi {{ user.username }}!
<p>logout</p>
{% else %}
<p>You are not logged in</p>
login |
signup
{% endif %}
{% endblock %}
And my question is:
How Django know what model is used in home.html template? (how Django know about "username"?)
In TemplateView i don't specify Model (in this case CustomUser). When we want to access and render database data, we need specify Model class (or in this case Form) in view. And from here Django accesses for template variable. Isn't it?
In your TEMPLATES setting, you have the auth context processor enabled.
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',
],
},
},
]
This adds user (the currently logged-in user or an anonymous user if not logged in) and perms (which stores the user's permissions) to the template context.
To setup a URL by doing path('', TemplateView.as_view(template_name='home.html'), name='home') is just about the simplest way to configure a view.
You wouldn't really do anything complicated with that, but you can specify some context variables using extra_context, for example;
path(
'',
TemplateView.as_view(
template_name='home.html',
extra_context={
'page_title': 'Home Page',
}
),
name='home'
)
To keep the urls.py clean you'd likely create another view for your home page and add your context variables that way;
class HomePageView(TemplateView):
template_name = "home.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['page_title'] = 'Home Page'
context['user'] = CustomUser.objects.first() # Filter for user here
return context
<!-- templates/home.html -->
{% block title %}{{ page_title }}{% endblock %}
{% block content %}
{% if request.user.is_authenticated %}
Hi {{ request.user.username }}!
The user you were interested in is {{ user.username }}
<p>logout</p>
{% else %}
<p>You are not logged in</p>
login |
signup
{% endif %}
{% endblock %}
You can access the logged in user from the request object like this providing you have the request context processor in your settings;
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
...
'django.template.context_processors.request',
...
],
},
},
]
EDIT: Updated now that I've narrowed down the problem to the context processor variable not being available to a template that I'm loading with a custom tag.
I'm using Django 1.11 and this is my first time trying to use a custom context processor.
The problem is that the context variable I'm supposed to be adding from the context processor does not return anything from within a template loaded from a custom tag. I don't receive any errors.
So below {{ testcontext }} should return "IT WORKED!" and does so in my base.html template, but returns nothing in the template loaded with #register.inclusion_tag().
settings.py:
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')],
'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',
'appname.context_processors.test_context',
],
},
},
]
context_processors.py:
def test_context(request):
return {'testcontext': 'TEST WORKED!'}
tags.py
from django import template
from appname.models import Category
register = template.Library()
#register.inclusion_tag('template.html')
def load_category(selected_slug=None):
return {
'categories': Category.objects.all(),
'selected':selected_slug,
}
views.py:
from django.views.generic import ListView
from appname.models import MyModel
class MyView(ListView):
model = MyModel
urls.py
from django.conf.urls import url
from appname.views import MyView
urlpatterns = [
url(r'^$', MyView.as_view(), name="home"),
]
template.html
{{ testcontext }}
So the problem was in my custom tag not carrying over the context when loading template.html. So the below code fixes it and my variable from the context processor is now working as expected.
tags.py
from django import template
from appname.models import Category
register = template.Library()
#register.inclusion_tag('template.html', takes_context=True)
def load_category(context,selected_slug=None):
return {
'categories': Category.objects.all(),
'selected': selected_slug,
'testcontext': context['testcontext']
}
urls.py
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^$', views.people),
]
views.py
def people(request):
return render(request, 'people.html', {'people': models.Person.objects.all()})
models.py
class Person(models.Model):
name = CharField(verbose_name="full name", max_length=10)
people.html
{% load render_table from django_tables2 %}
{% load static %}
{% render_table people %}
When I run it, it told me TemplateDoesNotExist at /django_tables2/table.html, I don't understand why.
First, make sure that django_tables2 is included in your INSTALLED_APPS setting.
Then, make sure that you have APP_DIRS set to True in your TEMPLATES setting.
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [...],
'APP_DIRS': True,
...
},
]