views.py
from django.shortcuts import render_to_response
from models import Post
def getRecentPosts(request):
posts = Post.objects.all()
# sort by chronological order
sorted_posts = posts.order_by('-pub_date')
# display all posts
return render_to_response('posts.html', {'posts': sorted_posts})
posts.html
<html>
<head>
<title>My Django Blog</title>
</head>
<body>
{% for post in posts %}
<h1>{{post.title}}</h1>
<h3>{{post.pub_date}}</h3>
{{ post.text }}
{% endfor %}
</body>
This code works fine & prints the proper data.... However if i change
return render_to_response('posts.html', {'posts': sorted_posts})
to
return render_to_response('posts.html', {'po': sorted_posts})
and
{% for post in posts %} to {% for post in po %}
in posts.html
It fails to generate any data..... So what is the relation between the dictionary name in view and template
Related
Hello Stackoverflow community,
I am having trouble with my form not rendering in Django.
Here's my attempt to render an empty form in views.py.
class SearchSite(forms.Form):
query = forms.CharField(label="New Item",
help_text="Search for any article located on the site.")
def search(request):
form = SearchSite()
context = {
"form": form,
"query_matches": query_matches
}
response = render(request, "encyclopedia/layout.html", context)
return response
Here's what my urls.py file looks like:
urlpatterns = [
path("", views.index, name="index"),
path("wiki/<str:page_title>", views.page, name="wiki"),
path("wiki/", views.search, name="site_search")
]
My layout.html file:
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<title>{% block title %}{% endblock %}</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
<link href="{% static 'encyclopedia/styles.css' %}" rel="stylesheet">
</head>
<body>
<div class="row">
<div class="sidebar col-lg-2 col-md-3">
<h2>Wiki</h2>
<form action="{% url 'site_search' %}" method="get">
{% csrf_token %}
There should be something here
{{ form }}
<input type="submit">
</form>
<div>
Home
</div>
<div>
Create New Page
</div>
<div>
Random Page
</div>
{% block nav %}
{% endblock %}
</div>
<div class="main col-lg-10 col-md-9">
{% block body %}
{% endblock %}
</div>
</div>
</body>
</html>
I have noticed two particular problems in above screenshot. Firstly, my form does not render when inside my index.html webpage, which extends layout.html. Secondly, when I click the submit button, I get routed to a webpage that has my CSRF token in the url ... and then finally renders my form.
How can I fix this? Thanks everyone.
I have noticed two particular problems in above screenshot. Firstly,
my form does not render when inside my index.html webpage, which
extends layout.html.
Yes. You aren't passing form to index.html. Pass that in the view which renders the homepage. Even if it extends from layout.html, you need to pass it in the context for it to work.
def index(request):
# Your code.
return render(request, 'index.html', {'form': SearchSite()})
Secondly, when I click the submit button, I get routed to a webpage
that has my CSRF token in the url ... and then finally renders my
form.
That's because, in index.html, there is a blank form with a csrf_token, with an action set to /wiki, which calls search when the submit button is pressed. And search gives you layout.html, with the form, and as the form method is GET, it shows it in the url. I suggest changing it to POST if there is confidential data (and even otherwise. Why is there a csrf_token if it is not a POST request? Not needed. If you really want a GET request, then remove the csrf_token).
Here's my solution to the problem I had earlier for any future people visiting the post.
I wrote a form called SearchSite and defined a view called search in my views.py.
class SearchSite(forms.Form):
query = forms.CharField(
help_text="Search for any article located on the site.")
def search(request):
form = SearchSite()
is_substring_of_queries = []
if request.method == "GET":
form = SearchSite(request.GET)
if form.is_valid():
for entry in util.list_entries():
existsIdenticalResult = form.cleaned_data["query"].casefold() == entry.casefold()
existsResult = form.cleaned_data["query"].casefold() in entry.casefold()
if existsIdenticalResult:
return HttpResponseRedirect(reverse("wiki",
kwargs={"page_title": entry}))
elif existsResult:
is_substring_of_queries.append(entry)
context = {
"form": SearchSite(),
"is_substring_of_queries": is_substring_of_queries
}
response = render(request, "encyclopedia/search.html", context)
return response
When my view.search is requested, it will send the response of either an empty form (if accessed by index.html or if there are no results with a message saying there are no results) , an empty form and all the queries that are substrings of the markdown entries or route the client to an exact entry if the query matched.
Here's the routing down in my urls.py so far:
urlpatterns = [
path("", views.index, name="index"),
path("wiki/<str:page_title>", views.page, name="wiki"),
path("search/", views.search, name="site_search")
]
In my layout.html, I have the following form:
<form action="{% url 'site_search' %}" method="get">
{{ form }}
<input type="submit">
</form>
as well as in my search.html the queries that are substrings of the markdown entries:
{% if is_substring_of_queries %}
<h1>Search Results</h1>
{% for query in is_substring_of_queries%}
<li> {{ query }} </li>
{% endfor %}
{% else %}
<h1>No Results! Try again.</h1>
{% endif %}
If there are any mistakes, please let me know.
hey im new to django so don't be harsh !.im trying to make a blog in django . i need to map the posts in home page to the post page. for that .i have defined a function called get_absulute_url(self) in models.py but it is not recognized in index.html.
when i click on Links nothing happens...i'm not where did i made the mistake !
model.py
from django.db import models
from django.urls import reverse
import posts
# Create your models here.
class post(models.Model):
title=models.CharField(max_length=500)
content=models.TextField()
timestamp=models.DateTimeField(auto_now=False,auto_now_add=True)
updated= models.DateTimeField(auto_now=False,auto_now_add=True)
def get_absulute_url(self):
return reverse("posts:detail", kwargs={'id': self.id})
# return reverse(viewname=posts.views.posts_list,urlconf=any, kwargs={"id": self.id})
views.py
def posts_list(request):#list items
queryset=post.objects.all()
context={
"objectsList":queryset,
"title":"list"
}
return render(request,"index.html",context)
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{ title }}</title>
</head>
<body>
{% for obj in objectsList %}
Link<br>
{{ obj.title }} <br>
{{ obj.content }} <br>
{{ obj.timestamp }} <br>
{{ obj.updated }} <br>
{{ obj.id }} <br>
{{ obj.pk }} <br>
{% endfor %}
</body>
</html>
url.py
from django.contrib import admin
from django.urls import path
from posts import views as posts_views
urlpatterns = [
path('create/',posts_views.posts_create),
path('<int:id>/', posts_views.posts_detail,name="detail"),
path('',posts_views.posts_list),
path('update/', posts_views.posts_update),
path('delete/', posts_views.posts_delete),
]
Change posts:detail to detail
return reverse("detail", kwargs={'id': self.id})
href="{% url "detail" id=obj.id %}"
Mapping may be the problem but it will throw error before execution.
Still add app_name = 'posts' in urls.py file of your app and try this may work or just use DetailView builtin class still getting error you better add post_detail view to the question above so we can get indepth picture of what you are looking for.
I have created a class in the models.py containing the information of articles I want to insert in a website
from django.db import models
from django.urls import reverse
class Article(models.Model):
"""
Model representing an article.
"""
title = models.CharField(max_length=200)
authors = models.CharField(max_length=200)
summary = models.TextField(max_length=1000, help_text='Enter a brief description of the article')
content = models.TextField(max_length=100000)
def __str__(self):
"""
String for representing the Model object.
"""
return self.title
def get_absolute_url(self):
"""
Returns the url to access a detail record for this article.
"""
return reverse('article-detail', args=[str(self.id)])
After that, I have inserted an article using the admin panel of Django and saved it.
Then, I have created the index.html shown below calling the articles in the database
<!DOCTYPE html>
<html lang="en">
<head>
{% block title %}{% endblock %}
</head>
<body>
{% block sidebar %}<!-- insert default navigation text for every page -->{% endblock %}
{% block content %}<!-- default content text (typically empty) -->
<!-- Articles -->
<div class="articles">
<h1>Titolo: {{ article.title }}</h1>
<p><strong>Autori:</strong> {{ article.authors }}</p>
<p><strong>Riepilogo:</strong> {{ article.summary }}</p>
<p><strong>Testo:</strong> {{ article.content }}</p>
</div>
{% endblock %}
</body>
</html>
But the article is not shown despite being in the database (see prints below)
EDIT1: inserted views.py as requested
from django.shortcuts import render
from .models import Article
# Create your views here.
def index(request):
"""
View function for home page of site.
"""
# Render the HTML template index.html with the data in the context variable
return render(
request,
'index.html',
)
You are not including any articls in your template context:
return render(
request,
'index.html',
)
You could include the articles in the template context with:
articles = Article.objects.all()
return render(
request,
'index.html',
{'articles': articles}
)
Then in the template you need to loop through the articles.
<!-- Articles -->
<div class="articles">
{% for article in articles %}
<h1>Titolo: {{ article.title }}</h1>
<p><strong>Autori:</strong> {{ article.authors }}</p>
<p><strong>Riepilogo:</strong> {{ article.summary }}</p>
<p><strong>Testo:</strong> {{ article.content }}</p>
{% endfor %}
</div>
To make my question clearer, here is a little application that takes a sentence input and outputs that sentence twice.
I have base.html:
<html>
<head>
<title> My site </title>
<body>
{% block content %}{% endblock %}
</body>
</html>
and index.html:
{% extends "base.html" %}
{% block content %}
{{ s }}
<form action="" method="post" name="blah">
{{ form.hidden_tag() }}
{{ form.sentence(size=80) }}
<input type="submit" value="Doubler"></p>
</form>
{% endblock %}
Here is part of views.py:
from forms import DoublerForm
#app.route('/index')
def index():
form = DoublerForm()
if form.validate_on_submit():
s = form.sentence.data
return render_template('index.html', form=form, s=str(s) + str(s))
return render_template('index.html', form=form, s="")
And here is forms.py, without all the imports:
class DoublerForm(Form):
sentence = StringField(u'Text')
This seems to work OK. But what I would like is to have my input form in the base.html template so that this shows up on all pages that extend it, not just the index page. How can I move the form to the base.html and instantiate the form for all views that extend base.html?
You can use the flask.g object and flask.before_request.
from flask import Flask, render_template, g
from flask_wtf import Form
from wtforms import StringField
#app.before_request
def get_default_context():
"""
helper function that returns a default context used by render_template
"""
g.doubler_form = DoublerForm()
g.example_string = "example =D"
#app.route('/', methods=["GET", "POST"])
def index():
form = g.get("doubler_form")
if form.validate_on_submit():
s = form.sentence.data
return render_template('index.html', form=form, s=str(s) + str(s))
return render_template('index.html', form=form, s="")
You can also explicitly define a context function
def get_default_context():
"""
helper function that returns a default context used by render_template
"""
context = {}
context["doubler_form"] = form = DoublerForm()
context["example_string"] = "example =D"
return context
and is used like this
#app.route('/faq/', methods=['GET'])
def faq_page():
"""
returns a static page that answers the most common questions found in limbo
"""
context = controllers.get_default_context()
return render_template('faq.html', **context)
Now, you'll have whatever objects you add to the context dictionary available in all templates that unpack the context dictionary.
index.html
{% extends "base.html" %}
{% block content %}
{{ s }}
{% endblock %}
base.html
<html>
<head>
<title> My site </title>
<body>
{% block content %}{% endblock %}
<form action="" method="post" name="blah">
{{ doubler_form.hidden_tag() }}
{{ doubler_form.sentence(size=80) }}
{{ example_string }}
<input type="submit" value="Doubler"></p>
</form>
</body>
</html>
views.py:
def index(request):
return render_to_response('index.html', {})
def photos(request, artist):
if not artist:
return render_to_response('photos.html', {'error' : 'no artist supplied'})
photos = get_photos_for_artist(artist)
if not photos:
logging.error('Issue while getting photos for artist')
return render_to_response('photos.html', {'error': 'no matching artist found'})
return render_to_response('photos.html', {'photos': photos})
Index.html:
<html>
<head>
<title>find artist photos </title>
</head>
<body>
{% block error %} {% endblock %}
<form action="/photos" method="POST">
{% csrf_token %}
<label for="artist">Artist : </label>
<input type="text" name="artist">
<input type="submit" value="Search">
</form>
{% block content %}{% endblock %}
</body>
</html>
photos.html:
{% extends 'index.html' %}
{% block error %}
{% if error %}
<p> {{ error}} </p>
{% endif %}
{% endblock %}
{% block content %}
{% if photos %}
{% for photo in photos %}
{{ photo }}
{% endfor %}
{% endif %}
{% endblock%}
url.py:
urlpatterns = patterns('',
(r'', index),
(r'^time/$', current_datetime),
(r'^photos/(\w+)$', photos)
)
I even tried by adding {% csrf_token %}, but no luck
Thank you
UPDATE
I see these in the logs
UserWarning: A {% csrf_token %} was used in a template, but the context did not provide the value. This is usually caused by not using RequestContext.
warnings.warn("A {% csrf_token %} was used in a template, but the context did not provide the value. This is usually caused by not using RequestContext.")
This came after adding context_instance=RequestContext(request) **to render_to_response()**
add context_instance=RequestContext(request) to every view that you will use a form inside it:
return render_to_response('index.html', {}, context_instance=RequestContext(request) )
return render_to_response('photos.html', {'photos': photos}, context_instance=RequestContext(request) )
Supposing you are using a fairly recent version of Django (1.3/1.4/dev) you should follow these steps :
In settings.py, Add the middleware django.middleware.csrf.CsrfViewMiddleware to the
MIDDLEWARE_CLASSES list.
In your template, use the {% crsf_token %} in the form.
In your view, ensure that the django.core.context_processors.csrf context processor is used either by :
use RequestContext from django.template
directly import the csrf processor from from django.core.context_processors
Examples
from django.template import RequestContext
from django.shortcuts import render_to_response
def my_view(request):
return render_to_response('my_template.html', {}, context_instance=RequestContext(request))
or
from django.core.context_processors import csrf
from django.shortcuts import render_to_response
def my_view(request):
c = {csrf(request)}
return render_to_response('my_template.html', c)
References
csrf in Django 1.3 or csrf in Django 1.4
RequestContext in Django 1.3 or RequestContext in Django 1.4
(exhaustive post for posterity and future viewers)
A number of things to troubleshoot here:
Please load your "index" page in a web browser, do "View Source", and check if the {% csrf_token %} is being expanded. It should be replaced with an <input> tag. If that's not happening, then you have problems with your index page. If it is being replaced correctly, then you have problems with your photos page.
The POST URL in index.html doesn't match any of the patterns in urls.py. Your urls.py seems to expect the search term to be part of the URL, but it's not - you're sending it as a HTTP POST parameter. You need to access it via request.POST.
Check in the settings, if you have this middleware:
'django.middleware.csrf.CsrfViewMiddleware'
https://docs.djangoproject.com/en/dev/ref/contrib/csrf/
You may need to explicitly pass in a RequestContext instance when you use render_to_response in order to get the CSRF values for that template tag.
http://lincolnloop.com/blog/2008/may/10/getting-requestcontext-your-templates/
Try using the #csrf_protect decorator:
from django.views.decorators.csrf import csrf_protect
from django.shortcuts import render_to_response
#csrf_protect
def photos(request,artist):
if not artist:
return render_to_response('photos.html', {'error' : 'no artist supplied'})
photos = get_photos_for_artist(artist)
if not photos:
logging.error('Issue while getting photos for artist')
return render_to_response('photos.html', {'error': 'no matching artist found'})
return render_to_response('photos.html', {'photos': photos})
This worked for me:
{% csrf_token %}
In the template, there is a {% csrf_token %} template tag inside each POST form that targets an internal URL.
In views.py:
from django.template import RequestContext
...
...
...
return render_to_response("home.html", {}, context_instance=RequestContext(request))