I'm aware my issue may be to lack of Django knowledge, but I'm trying to pass user input from one form in a view, to another view which will then render that view's HTML page with the given input.
I'm redirected fine, but the data is not being displayed. I believe it has something to do with the contexts not being passed properly, but I do not understand what is wrong or how to fix it.
views.py
def home_view(request, *args, **kwargs):
print(args, kwargs)
print(request.user)
if request.method == 'POST':
form2 = PostForm(request.POST)
if form2.is_valid():
post = form2.save(commit=False)
post.poster = request.user
post.content = form2.cleaned_data.get('content')
post.title = form2.cleaned_data.get('title')
post.syntax = form2.cleaned_data.get('syntax')
post.public = form2.cleaned_data.get('public')
rand = str(uuid.uuid4())[:6]
while Paste.objects.filter(generated_url=rand):
rand = str(uuid.uuid4())[:6]
post.generated_url = rand
form2.save()
context = {
"poster_name": post.poster,
"paste_contents": post.content,
"paste_title": post.title,
"paste_syntax": post.syntax,
"paste_visible": post.public
}
return HttpResponseRedirect(reverse('details', args=(post.generated_url,)), context)
else:
form2 = PostForm()
return render(request, "home.html", {'form2': form2})
def detail_view(request, *args, **kwargs):
if request.user.is_authenticated:
if request.method=='POST':
form3 = PostForm(request.POST)
url = form3.generated_url
your_posts = Paste.objects.get(url)
context = {
'form3': form3
}
return render(request, "paste_detail.html", context)
return render(request, "paste_detail.html", {'form3': form3})
home.html
{% extends "base.html" %}
{% block content %}
<h1>Your user is {{ request.user }}</h1>
<div class="submit_form">
<form action="" method="POST">
{% csrf_token %}
{{ form2.as_p }}<br>
<input type="submit" name="submit" value="Paste" id="submit">
</div>
{% endblock content %}
And paste_detail.html
{% extends "base.html" %}
{% block content %}
<!--<h1>Name of post: {{ post.title }}</h1>-->
<p>Content of post:</p>
I AM REDIRECTED
<h1>Name of post: {{ form2.title }}</h1>
<p>Content of post:</p>
<p>{{form3.content|linebreaks}}</p>
{{ form3.poster }}
{{ form3.contents }}
{{ form3.title }}
{{ form3.syntax }}
{{ form3.visible }}
{% endblock %}
edit:
views.py
def home_view(request, *args, **kwargs):
if request.method == 'POST':
form2 = PostForm(request.POST)
if form2.is_valid():
post = form2.save(commit=False)
post.poster = request.user
post.save()
rand = str(uuid.uuid4())[:6]
while Paste.objects.filter(generated_url=rand):
rand = str(uuid.uuid4())[:6]
post.generated_url = rand
# return HttpResponseRedirect(reverse('details', args=(post.generated_url,)), context)
return redirect('detail', rand)
else:
form2 = PostForm()
return render(request, "home.html", {'form2': form2})
def detail_view(request, custom_uuid):
post = get_object_or_404(Paste, pk=pk)
return render(request, "paste_detail.html", {'post': post})
#return render(request, "paste_detail.html", {'form3': form3})
paste_detail.html
{% extends "base.html" %}
{% block content %}
<p>Content of post:</p>
I AM REDIRECTED
<h1>Name of post: {{ post.title }}</h1>
<p>Creator of post:</p> {{ post.poster }}
<p>Content of post:</p> {{ post.content }}
<p>Title of post:</p> {{ post.title }}
{{ post.syntax }}
{{ post.visible }}
{% endblock %}
And urls.py
...
urlpatterns = [
path('home/', home_view, name='home'),
path('contact/', contact_view, name='contact'),
path('admin/', admin.site.urls, name='admin'),
path('about/', about_view, name='about'),
url(r'^signup/$', views.signup, name='signup'),
path('paste_list/', paste_list_view, name='paste_list'),
url(r'^$', home_view),
#url(r'^(?P<rand_url>\S{6})/$', detail_view, name='details'),
path('detail/<str:custom_uuid>/', detail_view, name='detail'),
path('accounts/', include('django.contrib.auth.urls')),
]
There are several problems in your code. Lets fix them one by one(Please check the code comments for explanation):
In home_view you are doing some redundant codes, you can simplify like this:
from django.shortcuts import redirect
...
if request.method == 'POST':
form2 = PostForm(request.POST)
if form2.is_valid():
post = form2.save(commit=False) # it is not saved in db
post.poster = request.user
rand = str(uuid.uuid4())[:6]
while Paste.objects.filter(generated_url=rand).exists():
rand = str(uuid.uuid4())[:6]
post.generated_url = rand
post.save() # it will save all information to DB, so you don't need to call form2.cleaned_data.get(..)
return redirect('details', custom_uuid=rand) # I am redirecting to `detail_view`. here `rand` is the random uuid of the post which is saved in db
else:
form2 = PostForm()
return render(request, "home.html", {'form2': form2}) # rendering form for GET request
Now lets update detail view to catch the redirection:
from django.shortcuts import get_object_or_404
def detail_view(request, custom_uuid):
post = get_object_or_404(Post, generated_url=custom_uuid) # getting the post object from database using model.
return render(request, "post_detail.html", {'post': post}) # sending data in context to template
# url
path('detail/<str:custom_uuid>/', detail_view, name='detail') # here <str:custom_uuid> will catch the uuid sent in the url
# HTML
{% extends "base.html" %}
{% block content %}
<p>Content of post:</p>
I AM REDIRECTED
<h1>Name of post: {{ post.title }}</h1> // <-- getting this context from view
<p>Content of post:</p>
<p>{{post.content|linebreaks}}</p>
{{ post.poster }}
{{ post.contents }}
{{ post.title }}
{{ post.syntax }}
{{ post.visible }}
{% endblock %}
Here get_object_or_404 gets the entry for model Post, if its not found then throws 404 error.
Contexts are per-request. Once your view has returned, the context no longer exists. When you do a redirect, you are finishing that request/response cycle and starting another one with your detail view. None of the context will carry over.
Instead, you need a way to store pertinent information between requests. One fairly simple way to do this is storing data in the session.
For example, you might store title in a session like this in home_view:
request.session['title'] = post.title
And then in your detail_view view, you could add it to your context:
context = {
'title': request.session.get('title')
}
Check out the Django documentation on sessions for more info: https://docs.djangoproject.com/en/2.1/topics/http/sessions/
Related
Im currently following a Django tutorial to learn views and URLs. I have watched the tutorial over and over and cant see what I am doing wrong.
I receive the error:
Exception Value:
Reverse for 'list-events' not found. 'list-events' is not a valid view function or pattern name.
Views.py
from django.shortcuts import render, redirect
import calendar
from calendar import HTMLCalendar
from datetime import datetime
from .models import Event, Venue
from .forms import VenueForm, EventForm
from django.http import HttpResponseRedirect
# Create your views here.
# all events is listed in the urls.py hence why the function is named all_events
def update_event(request, event_id):
event = Event.objects.get(pk=event_id)
form = EventForm(request.POST, instance=event)
if form.is_valid():
form.save()
return redirect('list-events')
return render(request, 'events/update_event.html',
{'event': event,
'form':form})
def add_event(request):
submitted = False
if request.method == 'POST':
form = EventForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect('/add_event?submitted=True')
else:
form = EventForm
if 'submitted' in request.GET:
submitted = True
return render(request, 'events/add_event.html', {'form': form, 'submitted': submitted})
def update_venue(request, venue_id):
venue = Venue.objects.get(pk=venue_id)
form = VenueForm(request.POST, instance=venue)
if form.is_valid():
form.save()
return redirect('list-venues')
return render(request, 'events/update_venue.html',
{'venue': venue,
'form': form})
def search_venues(request):
if request.method == "POST":
searched = request.POST['searched']
venues = Venue.objects.filter(name__contains=searched)
return render(request,
'events/search_venues.html',
{'searched': searched,
'venues': venues})
else:
return render(request,
'events/search_venues.html',
{})
def show_venue(request, venue_id):
venue = Venue.objects.get(pk=venue_id)
return render(request, 'events/show_venue.html',
{'venue': venue})
def list_venues(request):
venue_list = Venue.objects.all()
return render(request, 'events/venue.html',
{'venue_list': venue_list})
URLS.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.home, name="home"),
path('<int:year>/<str:month>/', views.home, name="home"),
path('events', views.all_events, name='list_events'),
path('add_venue', views.add_venue, name='add-venue'),
path('list_venues', views.list_venues, name='list-venues'),
path('show_venue/<venue_id>', views.show_venue, name='show-venue'),
path('search_venues', views.search_venues, name='search-venues'),
path('update_venue/<venue_id>', views.update_venue, name='update-venue'),
path('add_event', views.add_event, name='add-event'),
path('update_event/<event_id>', views.update_event, name='update-event'),
event_list.html:
{% extends 'events/base.html' %}
{% block content %}
<h1>Event </h1>
<br />
{% for event in event_list %}
<div class="card">
<div class="card-header">
{{Event}}
</div>
<div class="card-body">
<h5 class="card-title">Venue: {{ event.venue }}</h5>
<p class="card-text">
<ul>
<li>Date: {{ event.event_date }}</li>
<li>Event Venue: {{ event.venue.web }}</li>
<li>Manager: {{ event.manager }}</li>
<li>Desc: {{ event.description }}</li>
<li>Attendees:<br />
{% for user in event.attendees.all %}
{{ user }}<br/>
{% endfor %}
</li>
</ul>
</p>
</div>
<div class="card-footer text-muted">
Update Event
</div>
</div>
<br /><br />
{% endfor %}
{% endblock %}
You have defined your url in the "urls.py" file with the name of "list_events" (note the underscore). In the views you have used it as "list-events" (note the hyphen).
You can fix that by following one of these options:
1.You can change that in the views (by using underscore instead of hyphen):
return redirect('list_events')
2.Or changing it in the url (by using hyphen instead of underscore):
path('events', views.all_events, name='list-events'),
I am trying to update my homepage whenever a new "article" is added, however it is giving me this error whenever I try to update the page using my updateHomepage view it doesn't work and I get the error
TemplateSyntaxError at /
Could not parse the remainder: ' 'update_homepage'' from 'url 'update_homepage''
I am very new to django so any help with this would be amazing.
My Views.py
def index(request):
articles = Article.objects.all()
context = {'articles': articles}
return render(request, 'able/homepage.html', context)
def updateHomepage(request, pk):
form = EditorForm(instance=task)
context = {'form': form}
article = Editor.objects.get(id=pk)
return render(request, 'able/update_homepage.html', context)
if request.method == 'POST':
form = EditorForm(request.POST, instance=task)
if form.is_valid():
form.save()
return redirect('/')
def editorview(request):
editor = EditorForm
context = {'editor': editor}
return render(request, 'able/editor.html', context)
if request.method == 'POST':
form = EditorForm(request.POST)
if form.is_valid():
form.save()
return redirect('/')
urls.py
urlpatterns = [
path('', views.index, name='homepage'),
path('editor/', views.editorview),
path('update_homepage/<str:pk>/', views.updateHomepage, name='update_homepage')
]
homepage.html
<h1>My Blog</h1>
{% for article in articles %}
<div class="article">
{% csrf_token %}
<h1>{{ article.title }}</h1>
<h3>{{ article.text }}</h3>
</div>
{% endfor %}
Update
update_homepage.html
<h3>Update Homepage</h3>
<form action="" method="POST">
{% csrf_token %}
{{form}}
<input type="submit">
</form>
This is the error I get when clicking on Edit post under any one of the posts. Would appreciate any help as all this django stuff is confusing me but trying my best to learn. My new post function works and clicking blog/posts to go to the overview page for the blog or to look at all the posts works as well.
NoReverseMatch at /edit_post/1/
Reverse for 'posts' with arguments '(1,)' not found. 1 pattern(s) tried: ['posts/$']
Error during template rendering
In template C:\Users\seng\Desktop\Python projects\c19\nineteen_one\blogs\templates\blogs\base.html, error at line 0
urls.py
"""Defines url paterns for blogs"""
from django.urls import path
from . import views
app_name = 'blogs'
urlpatterns =[
#Home page
path('', views.index, name='index'),
# Page that shows all posts/
path('posts/', views.posts, name='posts'),
#Page for adding a new blogpost
path('new_post/', views.new_post, name='new_post'),
#Page for editing a post
#maybe remove the id?
path('edit_post/<int:post_id>/', views.edit_post, name='edit_post'),
]
views.py
from django.shortcuts import render, redirect
from .models import BlogPost
from .forms import BlogPostForm
# Create your views here.
def index(request):
"""The home page for blogs"""
return render(request, 'blogs/index.html')
def posts(request):
"""Show all blogposts"""
posts = BlogPost.objects.order_by('date_added')
context = {'posts': posts}
return render(request, 'blogs/posts.html', context)
def new_post(request):
"""Add a new blogpost"""
if request.method != 'POST':
#No data submitted; create a blank form.
form = BlogPostForm()
else:
#POST data submitted, process data
form = BlogPostForm(data=request.POST)
if form.is_valid():
form.save()
return redirect('blogs:posts')
#Display a blank or invalid form
context = {'form': form}
return render(request, 'blogs/new_post.html', context)
def edit_post(request, post_id):
"""Edit existing post"""
post = BlogPost.objects.get(id=post_id)
if request.method != "POST":
#Initial request, pre-fill form with the current post
form = BlogPostForm(instance=post)
else:
#Post data submitted, process data
form = BlogPostForm(instance=post, data=request.POST)
if form.is_valid():
form.save()
return redirect('blogs:posts', post_id=post.id)
context = {'post':post, 'form':form}
return render(request, 'blogs/edit_post.html', context)
forms.py
from django import forms
from .models import BlogPost
class BlogPostForm(forms.ModelForm):
class Meta:
model = BlogPost
fields = ['text', 'title']
labels = {'text':'This is the text box', 'title' :"Title here"}
edit_post.html
{% extends "blogs/base.html" %}
{% block content %}
<p>{{ post }}</p>
<p>Edit post:</p>
<form action="{% url 'blogs:edit_post' post.id %}" method='post'>
{% csrf_token %}
{{ form.as_p }}
<button name="submit">Save changes</button>
</form>
{% endblock content %}
posts.html
{% extends "blogs/base.html" %}
{% block content %}
<p>Posts</p>
<ul>
{% for post in posts %}
<li>
<p>{{ post }}</p>
<p>
Edit post
</p>
</li>
{% empty %}
<li>No posts have been added yet.</li>
{% endfor %}
</ul>
Add a new post
{% endblock content %}
new_post.html
{% extends "blogs/base.html" %}
{% block content %}
<p>Add a new post:</p>
<form action="{% url 'blogs:new_post' %}" method='post'>
{% csrf_token %}
{{ form.as_p }}
<button name="submit">Add post</button>
</form>
{% endblock content %}
The issue is with this line in edit_post.html:
<p>{{ post }}</p>
If you are editing the post with id 1, then this link is to the url /posts/1. But that has no match in your urls.py file.
Either you need to remove the post.id parameter from the link, or create a view and a corresponding path in urls.py for this link.
I'm trying to make a website that lets visitors search for books using another search engine. I have a script that takes a query, and returns some HTML with the results of the search, but I'm struggling to make a front end for this. I am using django because it seemed like the best option when I started, but now I am going in circles and I can't figure out how to make this thing - I'm just getting overwhelmed because the different tutorials and documentation that I'm reading all go into the advanced stuff before I can get the basic thing working.
Do I need separate search and results templates? Right now I'm getting the error The view book_search.views.search didn't return an HttpResponse object. It returned None instead.
How can I fix this error and/or design this whole thing better?
Here's what I have so far (the script that returns the results in html is pull.py):
The views and urls are from inside the book_search app.
views.py:
from django.shortcuts import render
from django.http import HttpResponse
from . import pull
from .forms import SearchForm
def index(request):
return HttpResponse("Welcome to the index page")
def test_search(request):
context = {'query': 'test query'}
return render(request, 'book_search/search.html', context)
def search(request):
if request.method == "GET":
form = SearchForm(request.GET)
if form.is_valid():
query = form.cleaned_data['query']
results = pull.main(query)
context = {'query': query, 'form': form, 'results': results}
return render(request, 'book_search/results.html', context)
apps.py:
from django.apps import AppConfig
class BookSearchConfig(AppConfig):
name = 'book_search'
urls.py:
from django.urls import path
from . import views
urlpatterns = [
path('index', views.index, name='index'),
path('test', views.test_search, name='test_search'),
path('', views.search, name='search'),
]
forms.py:
class SearchForm(forms.Form):
query = forms.CharField(label='Search', max_length=200)
template base.html:
<html>
<head>
</head>
<body>
<form method="GET" action="/search/">
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit">
</form>
{% block content %}{% endblock %}
</body>
</html>
template results.html:
{% block content %}
{% results %}
{% endblock content %}
Since we guessed that form isn't valid (because no POST handler - you do not send anything to the form) and wrong indentation gives None response, now you can fix reference before assignment:
def search(request):
if request.method == "GET":
form = SearchForm()
context = {'form': form}
elif request.method == "POST":
form = SearchForm(request.POST)
if form.is_valid():
query = form.cleaned_data['query']
results = pull.main(query)
context = {'query': query, 'form': form, 'results': results}
return render(request, 'book_search/results.html', context)
and render errors in results.html template by putting this:
{% if form.errors %}
{% for field in form %}
{% for error in field.errors %}
<div class="alert alert-danger">
<strong>{{ error|escape }}</strong>
</div>
{% endfor %}
{% endfor %}
{% for error in form.non_field_errors %}
<div class="alert alert-danger">
<strong>{{ error|escape }}</strong>
</div>
{% endfor %}
{% endif %}
Hi i try add comment to my django blog procject and i get OSError: [Errno 22] Invalid argument: "C:\Users\marci\PycharmProjects\08.04\blog\templates\"
so my urls
path('<int:a_id>/addcomment', views.addcomment, name='addcomment'),
views.py
def addcomment(request, a_id):
article = get_object_or_404(Articles,id=a_id)
if request.method == 'POST':
form = CommentForm(request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.article = article
comment.save()
return HttpResponseRedirect('/article/%s' % a_id)
else:
form = CommentForm()
template = 'addcomment.html'
context = {'form': form}
return render_to_response(request,template,context)
addcomment.html
{% extends 'main.html' %}
{% block article %}
<form action="/article/{{ article.id }}/addcomment/" method="post" class="form-horizontal well">{% csrf_token %}
{{ form.as_p }}
<input type="submit" class="btn btn-inverse" name="submit" value="Dodaj komentarz" />
</form>
{% endblock %}
thx
You should be using render instead of render_to_response. You should also include article in the template context if you use it. Deindent the template and contect lines, so that the view works for invalid post requests.
def addcomment(request, a_id):
article = get_object_or_404(Articles,id=a_id)
if request.method == 'POST':
...
else:
form = CommentForm()
template = 'addcomment.html'
context = {'form': form, 'article': article}
return render(request, template, context)