When I click the categories link in the menu, I get the following error.
Page not found (404)
Request Method: GET
Request URL: http://127.0.0.1:8000/post/categorylist/
Raised by: post.views.post_detail
No Post matches the given query.
models.py
def get_categorylist_url(self):
return reverse('post:categorylist', kwargs={'slug': self.slug})
views.py
def post_categorylist(request, slug):
if not request.user.is_superuser:
raise Http404()
post = get_object_or_404(Post, slug=slug)
post.categorylist()
return redirect('post:categorylist')
urls.py
path('categorylist/',views.post_categorylist, name='categorylist'),
header.html
<li>Kategoriler</li>
categorylist.html
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>Test</title>
</head>
<body>
Test message.
</body>
</html>
If your root urls.py is as posted you should be going to http://127.0.0.1:8000/categorylist/ because that is the path the URL is linked to.
However, you've got a slug in your views but it isn't handled by your URLs so you might have a problem there as well. Because your view expects a slug, try changing your view to look for it;
path('categorylist/<slug:slug>/',views.post_categorylist, name='categorylist'),
Your error raised by: post.views.post_detail so your url is wrong.
You want get slug argument but your url hasn't any slug parameter. Firstly you should fix your url path.
Than, If you want when user click to x category link and get products in x category, let's make example:
Firstly create this view:
views.py:
def category_list(request):
# Category loops on index page.
category_list = Category.objects.filter()
context = {
"category_list": category_list,
}
return context
Than, we should add this context to our context processor for accessing everywhere (because it is navbar, so navbar will be top of every page, right?)
settings.py:
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': ["templates"],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
************************************,
'YOURMODELNAME.views.category_list',
],
},
},
]
Finally, you will access all categories on your project, just add this code on your template:
navbar.html:
{% for category in category_list %}
<a href="{% url 'categories' slug=category.slug %}">
{{ category.name }} <!--You can use ul-li for displaying them-->
</a>
{% endfor %}
Ok, we displayed our categories, but when user click any link, should redirect to filtered list in clicked category. So we should create page and link for this page:
views.py:
def category_list(request, slug):
category = Category.objects.get(slug=slug)
posts = Post.objects.filter(category=category)
context = {
"posts": posts, #filtered products
}
return render(request, "posts_in_category.html", context)
urls.py:
path('category/<slug:slug>', views.category_list, name="category_list")
posts_in_category.html:
{% for post in posts_in_category %}
{{ post.name }}
{% endfor %}
If you miss anything, I can explain in Turkish ;)
I'm using this codes. How do I add links?
views.py
def categorylist(request):
# Category loops on index page.
categorylist = Category.objects.filter()
context = {
"categorylist": categorylist,
}
return render(request, "post/categories.html", context)
categories.html
{% for post in categorylist %}
{{ post.name }}
{% endfor %}
Related
When I render blogpost.html page I can't see any content in my page.
My urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='Blog_home'),
path('<slug:slug>', views.blogpost, name='blogpost'),
]
my views.py
When I print blogpost function's query I got null value
from django.shortcuts import render
from django.http import HttpResponse
from blog.models import Post
# Create your views here.
def index(request):
post = Post.objects.all()
context = {'post':post}
return render(request, 'blog/bloghome.html', context)
def blogpost(request, post_id):
post = Post.objects.filter(slug=slug)
print(post)
context = {'post':post}
return render(request, 'blog/blogpost.html', context)
Template Name:- blogpost.html
{% extends 'basic.html' %}
{% block title %}Blog{% endblock title %}
{% block body %}
<div class="contaier">
<div class="row">
<div class="col-md-8 py-4">
<h2 class=" blog-post-title">{{post.title}}</h2>
</div>
</div>
</div>
{% endblock body %}
If I write like this my blogpost.html template it works.
{% extends 'basic.html' %}
{% block title %}Blog{% endblock title %}
{% block body %}
<div class="contaier">
<div class="row">
<div class="col-md-8 py-4">
<h2 class=" blog-post-title">Django</h2>
</div>
</div>
</div>
{% endblock body %}
You're passing a queryset as a context. Your post object contains a queryset of Post objects, so you can't retrieve post.title, you need either to pass only one Post object to your template, or loop through all of your objects and then display post.title for each of them.
You probably need the first option, so you need to change several things.
In your urls.py, you defined your blogpost view by blogpost(request, post_id) whereas in your urls.py you defined your url as
path('<slug:slug>', views.blogpost, name='blogpost')
If you want to get an id from your url, you should define it as
path('<int:post_id>', views.blogpost, name='blogpost')
And in your blogpost view, you do
post = Post.objects.filter(slug=slug)
but your slug isn't defined because your named it post_id.
Once again, if you want to retrieve only a post_id, you should use
post = Post.objects.get(pk=post_id)
The problem is that you are not retrieving a post with this:
post = Post.objects.filter(slug=slug)
It's a queryset, which returns zero, one, or possibly >1 objects (the latter if the slugfield isn't specified unique)
Try:
post = Post.objects.get(slug=slug)
or to better handle failure
post = get_object_or_404( Post, slug=slug)
Django template language fails quietly. If something in {{ }} fails, you get a null string substituted, not a runtime error.
Using Django I am trying to pass the title of the current page into a dynamic URL but I keep getting errors, the title of the page is also produced dynamically from other views.py functions.
Error
exception type: TypeError
exception value: edit_page() got an unexpected keyword argument 'title'
urls.py
path("wiki/edit/<str:title>", views.edit_page, name="edit")
HTML file
{% block title %} {{ title }} {% endblock %}
{% block body %}
<a class="page-link" href="{% url 'wiki:edit' page=title %}">edit page</a>
{% endblock %}
views.py
def edit_page(request, page):
page_request = page
if request.method == "GET":
return render(request, "encyclopedia/edit_page.html", {
"form": form,
"page": page_request
})
Update your parameter of edit_page(...) function to
def edit_page(request, title):
page_request = title
# rest of your code
I want to add data through form and see it queried in my template
blog url:
urlpatterns = [
url(r'^admin/',admin.site.urls),
url(r'^blog/',include('content.urls',)),
]
content url:
urlpatterns = [
url(r'^add/$', views.add_content, name='content'),
]
models.py
from django.db import models
class AddContent(models.Model):
content_name = models.CharField(max_length=100, default='', blank=False, unique=True)
def __str__(self):
return self.content_name
forms.py
from django import forms
from .models import AddContent
class AddContentForm(forms.ModelForm):
class Meta:
model = AddContentModel
fields = [
"content_name",
]
views.py
def add_content(request):
form = AddContentForm(request.POST or None)
if form.is_valid():
instance = form.save(commit=False)
instance.save()
return redirect("/blog/content/")
content_data = AddContent.objects.all()
context = {
"form":form,
"content":content_data,
}
return render(request, "add_content.html", context)
def view_content(request):
view_data = AddContent.objects.all()
context = {
"show_content":view_data,
}
return render(request, 'show_content.html', context)
templates:
add_content.html
{% extends 'base.html' %}
{% block content %}
<form method='POST' action="/blog/content/">
{% csrf_token %}
{{ form.as_p }}
<input type='submit' value='Add Content'/>
<h3>Recent content</h3>
{% for show in show_content %}
<p>{{ show.content_name }}</p>
{% endfor %}
{% endblock %}
The form data is not being saved, when I add it through admin interface it gives the result but form fails.
(this is just some useless content that I am writing in the bracket, stackoverflow didn't allow me posting as it looks like my post is mostly code; please add more details it said but i think the code has lot of details and i cant write anything just for the sake of length)
Your model form should look like this
from django import forms
from .models import AddContent
class AddContentForm(forms.ModelForm):
class Meta:
model = AddContent
fields = [
"content_name",
]
You've defined the wrong model name in the Meta class of model form. It should be AddContent not AddContentModel
I'm new to django too, but don't you need to specify the request inside the functions in views.py like :
def add_content(request):
if(request.method == 'POST'):
# rest of code here
Your form does not post to the view that saves the data; it posts directly to the view_content view, which ignores the data completely.
You can set the form action to "." to get it to post back to the same view that rendered it.
(As an additional point, you should avoid hard-coding URLs. Use the {% url %} tag in templates, and the reverse() function in views, to output URLs based on view names.)
First :
Correct the redirect() in your form.
return redirect("add_content", request.POST= None)
Second : you need to specify a URL for the content view : view_content
url(r'^content/$', views.view_content, name='content'),
And You need a template to render content (show_content.html :
{% extends 'base.html' %}
{% block content %}
<h3>Recent content</h3>
{% for show in show_content %}
<p>{{ show.content_name }}</p>
{% endfor %}
{% endblock %}
Edit :
Your form is not well defined. I edit my answer to make it complete :
You have to correct the model in your form (AddContent not AddContentModel) :
class Meta:
model = **AddContent**
fields = [
"content_name",
]
I am trying to create a simple django website where any user can rate and create posts. As displayed in this django tutorial (https://docs.djangoproject.com/en/1.7/topics/templates/), you can display all the model objects in html using a for loop. In my case, each object is going to be displayed with a Like and a Dislike button, so people can rate the post. My problem is: How do I know which object belongs to which like/dislike button so that the corresponding model field can be changed for that particular object? Thank You for answers!
models.py
from django.db import models
# Create your models here.
class Post(models.Model):
post_text = models.CharField(max_length=500)
pub_date = models.DateTimeField("date published")
likes = models.IntegerField(default=0)
dislikes = models.IntegerField(default=0)
def __str__(self):
return self.post_text
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>AllPosts</title>
</head>
<body>
{% if post_list %}
<ul>
{% for post in post_list %}
<li>{{post.post_text}}</li>
<p>This post has {{post.likes}} likes and {{post.dislikes}} dislikes.</p>
<br>Leave a <button type="button" method="LIKE">Like</button> or a <button type="button" method="DISLIKE">Dislike</button>!</p>
{% endfor %}
</ul>
<h2>If you want to create a post yourself, click here.</h2>
{% else %}
<h1>There are no posts yet...</h1>
{% endif %}
</body>
</html>
views.py
from django.http import HttpResponse
from django.template import loader
from django.shortcuts import render
from django.utils import timezone
from .models import Post
# Create your views here.
def index(request):
post_list = Post.objects.order_by('-pub_date')
template = loader.get_template('post/index.html')
context = {'post_list': post_list, }
#if request.method == "LIKE":
# post = Post.objects.get(id=) How do I find out the id?
# return HttpResponse(template.render(context, request))
#else:
return HttpResponse(template.render(context, request))
def create(request):
template = 'post/create.html'
if request.method == 'POST':
post = Post()
post.post_text = request.POST.get("post_text")
post.pub_date = timezone.now()
post.save()
return render(request, template)
else:
return render(request, template)
In order for the buttons to work, they need to be inside a form element and be of type="submit" otherwise they won't do anything when clicked. To identify which button was clicked, you can then replace the method attributes with name="like" and name="dislike". The buttons can then be referenced to the related post by setting their value to the post ID.
Below is an example of the code that should do this. I've clipped out some of the unrelated parts of the code. (Note: I haven't tested this, so it may not work perfectly)
index.html UL element:
<ul>
{% for post in post_list %}
<li>
<span>{{post.post_text}}</span><br>
<p>This post has {{post.likes}} likes and {{post.dislikes}} dislikes.</p>
<form method="post">
<p>
Leave a <button type="submit" name="like" value="{{post.id}}">Like</button>
or a <button type="submit" name="dislike" value="{{post.id}}">Dislike</button>!
</p>
</form>
</li>
{% endfor %}
</ul>
views.py index:
def index(request):
if request.method == 'POST':
like = request.POST.get('like')
dislike = request.POST.get('dislike')
if like:
# Handle liked post
# `like` is equal to the post ID
else if dislike:
# Handle disliked post
# `dislike` is equal to the post ID
else:
# No action requested
else:
post_list = Post.objects.order_by('-pub_date')
template = loader.get_template('post/index.html')
context = {'post_list': post_list, }
return HttpResponse(template.render(context, request))
I hope this helps :)
I have a table in my MySQL database named mysite_categories, there are 4 columns but for my purposes I just need two (name, base_url).
I currently have a template '*base_categories.html*' that I use to load the categories manually.
base_categories.html (trimmed down)
{% block content %}
<div class="section" style="float: right;">
<h4 class="gradient">Category List</h4>
<ul>
<li>Art</li>
<li>Biography</li>
<li>Science</li>
</ul>
</div>
{% endblock %}
What I'd like to do is pull the data from the db and use it in a for loop. Something like:
{% block content %}
<div class="section" style="float: right;">
<h4 class="gradient">Category List</h4>
<ul>
{% for category in mysite_categories %}
<li>{{ category.name }}</li>
{% endfor %}
</ul>
</div>
{% endblock %}
This is probably a newbie question but is it possible to something like this without creating an app?
*EDIT 1*
These are my app files, I'll admit this is probably junk, I have tried so many edits from so many different posts I'm sure I've broke it somewhere :P. I was going to remove it and start fresh but I figure I might as well post it to see where I might have gone wrong?
views.py
from django.shortcuts import render_to_response
from categories.models import categoryList
def index(request):
categories = categoryList.objects.all()
extra_context = {"categories": categories}
return render_to_response("myapp/index.html", extra_context)
models.py
from django.db import models
class categoryList(models.Model):
#id = models.IntegerField(unique=True, db_column='ID') # Field name made lowercase.
name = models.CharField(max_length=255L, unique=True)
base_url = models.CharField(max_length=255L, unique=True)
thumb = models.CharField(max_length=1L, unique=True, blank=True)
class Meta:
db_table = 'mysite_categories'
index.html
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
<div class="section" style="float: right;">
<h4 class="gradient">Category List</h4>
<ul>
{% for category in categories %}
<li>{{ category.title }}</li>
{% endfor %}
</ul>
</div>
As mentioned, it's probably junk at this point, if any of you can help me straighten this out it would be appreciated!
*EDIT 2*
base_right_panel.html
{% block content %}
<div style="float: right;">
<div id="base_categories" style="margin: 10px; padding-bottom: 10px;">
{% block base_categories %}
{% include "base_categories.html" %}
{% endblock %}
</div>
</div>
{% endblock %}
*Edit 3*
base_categories.html
{% block content %}
<div class="section" style="float: right;">
<h4 class="gradient">Category List</h4>
<ul>
{% if categories %}
{% for category in categories %}
<li>{{ category.title }}</li>
{% endfor %}
{% else %}
<p>no data! {{ categories|length }}</p>
{% endif %}
</ul>
</div>
{% endblock %}
*EDIT 4*
(Application name was changed to CategoryList)
CategoryList/views.py
from django.views.generic import TemplateView
from CategoryList.models import CategorylistCategorylist #<-- Changed to match inspectdb result
class IndexView(TemplateView):
template_name="categorylist.html" #<-- Changed name from index.html for clarity
def get_context_data(self, **kwargs):
context = super(IndexView, self).get_context_data(**kwargs)
context["categories"] = CategorylistCategorylist.objects.all()
return context
CategoryList/models.py
from django.db import models
class CategorylistCategorylist(models.Model): #<-- Changed to match inspectdb
id = models.IntegerField(primary_key=True)
name = models.CharField(max_length=255L, unique=True)
base_url = models.CharField(max_length=255L, unique=True)
thumb = models.ImageField(upload_to="dummy", blank=True) #<-- Ignored inspectdb's suggestion for CharField
def __unicode__(self):
return self.name
# Re-added Meta to match inspectdb
class Meta:
db_table = 'categorylist_categorylist'
CategoryList/urls.py
from django.conf.urls.defaults import patterns, url, include
from django.contrib import admin
from django.conf import settings
from CategoryList import views
admin.autodiscover()
urlpatterns = patterns('',
url(r'^$', views.IndexView.as_view(), name='categorylist'),
)
if settings.DEBUG:
urlpatterns = patterns('',
url(r'^media/(?P<path>.*)$', 'django.views.static.serve',
{'document_root': settings.MEDIA_ROOT, 'show_indexes': True}),
url(r'', include('django.contrib.staticfiles.urls')),
) + urlpatterns
MySite/urls.py
from django.conf.urls import patterns, include, url
from django.contrib import admin
from django.conf import settings
from home import views as home_view
from CategoryList import views as index_view
admin.autodiscover()
urlpatterns = patterns('',
url(r'^$', home_view.HomeView.as_view(), name="home"),
url(r'^categories/$', index_view.IndexView.as_view(), name='categorylist'),#include('CategoryList.urls')),
url(r'^admin/', include(admin.site.urls)),
#url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
)
if settings.DEBUG:
urlpatterns = patterns('',
url(r'^media/(?P<path>.*)$', 'django.views.static.serve',
{'document_root': settings.MEDIA_ROOT, 'show_indexes': True}),
url(r'', include('django.contrib.staticfiles.urls')),
) + urlpatterns
So far I can load the url "localhost:8000/categories" and I will see the list of category names appear on the right side of the screen as expected, but there is no template formatting applied. Inside my "*base_right_panel.html*" file I've tried "{% include "categorylist.html %}" to link directly to the application, which displays the correct template formatting, but displays the "{% else %}" response from "{% if categories %}" instead of the categories? I have tried changing the include to point to "categories/", which works in the browser, but it tells me it cannot find the template?
I'm sooo stumped right now..?
This answer is not meant to disagree with Alasdair's - it's just to add some more information on working with templates.
The core handler of an HTTP request to a Django application is the view. The view receives the HTTP request, as well as any arguments captured from the URL, and is responsible for returning an HttpResponse instance (or an instance of one of its subclasses) which will be returned to the browser.
The view is not bound to use any particular method to create the HttpResponse. Rendering a template to include information derived from the database and from request information or URL arguments is sufficiently common that there's code to support it, like the render shortcut or its mostly obsolete antecedent render_to_response, but this is by no means required. It's perfectly legitimate to have a view directly construct the HttpResponse:
def index(request):
return HttpResponse('This is an index page.')
Or, for very simple HTML:
def index(request):
return HttpResponse('<html><head><title>example</title></head><body>This is an index page.</body></html>')
In practice, I have often created HttpResponse instances directly to return json data or a dynamically created PDF or Excel file.
A simple way to slot information retrieved from the database into your response would be to use Python's built-in string interpolation:
def index(request):
return HttpResponse('Hello, %s' % request.user.email)
Or you could use the advanced string formatting options:
def index(request):
user_names = {}
user_names['first_name'] = request.user.first_name
user_names['last_name'] = request.user.last_name
return HttpResponse('Hello, %(first_name)s %(last_name)s' % user_names)
All this is building up to the point that it doesn't matter how you generate the text contents of your HttpResponse. All that matters is that you return one.
The template system is a powerful and extensible tool for generating text content, but that's all it does. If you look at the template docs about rendering a template, you'll see some examples that are almost exactly the same as the the string interpolation above.
render_to_response was a shortcut that would accept a template and a context and return an HttpResponse with the rendered contents of that template and context. Skipping over its context_instance and content_type parameters for the sake of demonstration, these two code blocks are identical in effect:
def index(request):
t = Template('Hello, {{ first_name }} {{ last_name }}')
c = Context({'first_name': request.user.first_name, 'last_name': request.user.last_name})
response_text = t.render(c)
return HttpResponse(response_text)
Assume a template index.txt exists as defined below, at the top level of an entry in the setting's TEMPLATE_DIRS tuple.
index.txt
Hello, {{ first_name}} {{ last_name}}
Then the view above could be replaced with:
def index(request):
t = get_template('index.html')
c = Context({'first_name': request.user.first_name, 'last_name': request.user.last_name})
response_text = t.render(c)
return HttpResponse(response_text)
Alternatively, you can skip the explicit creation of the context object and rendering of the template into a string thus:
def index(request):
return render_to_response('index.html', {'first_name': request.user.first_name, 'last_name': request.user.last_name})
On more recent versions of Django you should generally use the render shortcut rather than render_to_response - the details are a bit too much to go into if you're still struggling with getting context into your templates.
def index(request):
return render('index.html', {'first_name': request.user.first_name, 'last_name': request.user.last_name})
Of course, part of what makes templates useful is that the rendering engine can perform certain kinds of logic and lookup. I don't actually need to explictly keep looking up first_name and last_name - I can just pass in request as part of my context and look up its attributes in the templates:
index_showing_context.html
Hello, {{ request.user.first_name }} {{ request.user.last_name }}
def index_showing_context(request):
return render('index_showing_context.html', {'request': request})
Even passing in request isn't strictly necessary in that example, because one of the differences between render and render_to_response that I alluded to above is that request is always part of the context for render. But, again, that's an advanced subject.
So for your particular problem, it really doesn't matter where in your templates you render the data you want, as long as you have provided it to your view's context and are rendering the correct template. The template is in effect just a file name used to find and build a string, into which your context will be interpolated.
The {% include %} template tag is one way to mix template fragments into other templates. If I wanted to, I could set mine up like this:
header.html:
<head>
<title>This is a sample title.</title>
</head>
index.html:
<html>
{% include "header.html" %}
<body><p>This is my template body, {{ request.user.first_name }} {{ request.user.last_name }}.</p></body>
</html>
detail.html:
<html>
{% include "header.html" %}
<body><p>This is a detail page, probably for something selected in the context and given the context key 'object'.</p>
<p>{{ object }}</p>
</body>
</html>
That works fine, but it's not the only option. From your question, I see that you're using blocks and template inheritance. A common idiom is to define a base template that all or almost all other templates will inherit from:
base.html
<html>
<head>
<title>{% block title %}Default title{% endblock %}</title>
{% block extra_head_elements %}{% endblock %}
</title>
<body>
{% block body_header %}Standard page header here {% endblock %}
{% block body_content %}{% endblock %}
{% block body_footer %}Standard page footer here {% endblock %}
</body>
</html>
index.html
{% extends "base.html" %}
{% block title %}index {% endblock %}
{% block body_content %}<p>This is my template body, {{ request.user.first_name }} {{ request.user.last_name }}.</p>{% endblock %}
detail.html
{% extends "base.html" %}
{% block title %}detail{% endblock %}
{% block body_content %}<p>This is a detail page, probably for something selected in the context and given the context key 'object'.</p>
<p>{{ object }}</p>
{% endblock %}
So ultimately, I am not quite sure how you should best stitch together your right panel concept because it depends on the way you want your pages to work. If it's going to be present everywhere or almost everywhere, I would recommend putting it into a base template that the rest of your templates will extend. If you want it on exactly one page, just literally include it in that template. If you want it on some but not all pages, a template fragment that you can {% include %} is probably best.
The main thing is to understand how the template engine will compose your {% include %} and {% extends %} tags, and to provide the necessary data to the template's context in your view.
Edit:
If I wanted to have a view and template pair that just retrieved the categories, this is a simple way to lay it out using your example model code and rendering. There are other options.
index.html
<html>
<head><title>Simple category listing</title></head>
<body><p>The categories are:</p>
<ul>
{% for category in categories %}
<li>{{ category.name }}</li>
{% endfor %}
</ul>
</body>
</html>
view:
def index(request):
categories = categoryList.objects.all()
extra_context = {"categories": categories}
return render_to_response("index.html", extra_context)
If I wanted to reuse the category listing on multiple pages, that gets back into the include vs. extends discussion above. Either way, the template will always require your view to pass in categories as a context variable.
You could execute custom SQL directly to fetch categories in your view, and loop through the output in your template. This would not require an app.
If you create a model, you will be able to use the Django queryset api, which is very convenient, e.g.
mysite_categories = Category.objects.all()
This does require you to create an app. However, creating an app is really easy, just use the startapp command.
python manage.py startapp myapp
Once you've created your app, you can use the inspectdb command to inspect your database, and create a model for your mysite_categories table.