this is my views.py
def createpost(request, id=None):
form = PostForm(request.POST or None, request.FILES or None)
if form.is_valid() and request.method == 'POST':
instance = form.save(commit=False)
instance.user = request.user
instance.save()
messages.success(request, "successfully create!")
return HttpResponseRedirect('/post')
else:
context ={
'form': form
}
return render_to_response('createPost.html', context)
and createPost.html code that i want show the post page with errors
{% 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 %}
{% if request.user.is_authenticated %}\
<form method="POST" name="PostForm" action="/post/createpost/" enctype="multipart/form-data"> {% csrf_token %}
{{form|as_bootstrap_inline}}
<input type="hidden" name="user_id" value="{{ user.id }}" />
<button type="submit" class="btn btn-primary">Save AD</button>
{% else %}
<div>Please Register First!</div>
{% endif %}
</form>
{% endblock content %}
But when the error happens, it redirects and logs me out . How can I post the authenticated user to my post page ?
You should probably use render with request
rewrite your else part in views.py
e.g -
else:
context ={
'form': form,
}
return render(request, 'createPost.htm', context)
You shoud use render instead, render_to_response does not make request available see documentation:
This function preceded the introduction of render() and works similarly except that it doesn’t make the request available in the response. It’s not recommended and is likely to be deprecated in the future.
That is why {% if request.user.is_authenticated %} validation in template not passed.
Related
after redirect adding form.errors to messages if form not valid , form.errors doesn't appear in template
#login_required(login_url="login")
#user_passes_test(user_is_patient_check, login_url='login')
def changePasswordPatient(request):
if request.method == "POST":
form = PasswordChangeForm(request.user,request.POST)
if form.is_valid():
user=form.save()
update_session_auth_hash(request, user)
messages.success(request,'Şifreniz başarıyla güncellendi!')
return redirect("changePasswordPatient")
else:
messages.error(request,form.errors,extra_tags="invalidchangepassword")
return redirect("changePasswordPatient") # this part
form=PasswordChangeForm(request.user)
context={
"form":form,
"which_active":"passwordchange"
}
return render(request,"change-password.html",context)
but when I changed if form not valid part like using this(render method).Form errors showing in template.But in this method when I refresh page errors messages still showing.Can anyone help me to fix that?
if form.is_valid():
user=form.save()
update_session_auth_hash(request, user) # Important!
messages.success(request,'Şifreniz başarıyla güncellendi!')
return redirect("changePasswordPatient")
else:
messages.error(request,form.errors,extra_tags="invalidchangepassword")
return render(request,"change-password.html",{"form":form,"which_active":"passwordchange"})
change-password.html
{% if form.errors %}
{% for field in form %}
{% for error in field.errors %}
<div class="alert alert-danger">
<center><strong>{{ error|escape }}</strong></center>
</div>
{% endfor %}
{% endfor %}
{% for error in form.non_field_errors %}
<div class="alert alert-danger">
<center><strong>{{ error|escape }}</strong></center>
</div>
{% endfor %}
{% endif %}
You may edit your redirect into the following:
messages.error(request,form.errors,extra_tags="invalidchangepassword")
form=PasswordChangeForm(request.user)
return redirect("changePasswordPatient", {"form":form}) # this part
enter code hereI have a group_edit.html which permit to update info of a group and delete it.
Upade(save) works great but button for delete is doing nothing.
Thanks for help:
My group_edit.html:
{% block page %}
<form method="POST">
{% csrf_token %}
<div class="col-lg-4 col-md-4 col-sm-4 content">
{% bootstrap_form form %}
<button type="submit" class="btn btn-pink pull-right">Save</button>
<button type="reset" class="btn btn-warning pull-left">Delete</button>
</div>
Back to list
</form>
{% endblock %}
My confirm_delete.html template:
{% block title %}Delete{% endblock %}
{% block heading %}<h3 class="page-header-center">Object Delete</h3> {% endblock %}
{% block page %}
<form method="post">{% csrf_token %}
<p>Are you sure you want to delete "{{ obj }}"?</p>
<input type="submit" value="Confirm" class="btn btn-warning">
Cancel
</form>
{% endblock %}
my views.py:
def group_edit(request, group_id):
form = GroupForm(instance=Group.objects.get(group_id=group_id))
if request.method == "POST":
form = GroupForm(request.POST, instance=Group.objects.get(group_id=group_id))
if form.is_valid():
form.save()
messages.success(request, 'Group saved') # message for inform user of success - See messages in html file
return redirect(group_list)
return render(request, 'imports/group_edit.html', {
"group_id": group_id,
"form": form,
})
def confirm_delete(request, group_id):
obj = GroupForm(instance=Group.objects.get(group_id=group_id))
if request.method == "POST":
obj.delete()
messages.success(request, 'Deleted') # message for inform user of success - See messages in html file
return render(request, 'imports/group_list.html')
context = {
"obj": obj
}
return render(request, "imports/confirm_delete.html", context)
and my urls.py:
path('group_edit/<int:group_id>/', views.group_edit, name='group-edit'),
path('confirm_delete/<int:group_id>/', views.confirm_delete, name='confirm-delete'),
In your link, the span of <a> is empty. So instead of
Delete
it should be:
Delete
Probably it is better to specify the {% url ... %} parameters with named parameters:
Delete
I am using this exact code in another project, the only difference is that I have changed the model names, urls patterns, and template names since it is a different project. However, I am getting this error and I have no idea why. I am trying to bring the user to a detail page that has both the post and any comments on the post, as well as a link that takes to a page that allows the user to add a comment to the post.
app Views.py:
#login_required
def add_comment_to_post(request,pk):
post = get_object_or_404(UserPost,pk=pk)
if request.method == 'POST':
form = CommentForm(request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.post = post
comment.save()
return redirect('feed:post_detail', pk=userpost.pk)
else:
form = CommentForm()
return render(request,'feed/comment_form.html',{'form':form})
userpost_detail.html (post_detail in urls)
{% extends 'base.html' %}
{% block content %}
<h1 class="posttitle">{{ userpost.title }}</h1>
<p class="postcontent">{{ userpost.post_body }}</p>
{% if request.user.is_authenticated and request.user == post.author %}
<a class="link" href="{% url 'feed:edit_post' post.id %}">Edit Post</a>
{% endif %}
<hr>
Add Comment
<div class="container">
{% for comment in post.comments.all %}
<br>
{% if user.is_authenticated or comment.approved_comment %}
{{ comment.create_date }}
<a class="btn btn-warning" href="{% url 'comment_remove' pk=comment.pk %}">
<span class="glyphicon glyphicon-remove"></span>
</a>
<p>{{ comment.comment_body }}</p>
<p>Posted By: {{ comment.author }}</p>
{% endif %}
{% empty %}
<p>No Comments</p>
{% endfor %}
</div>
{% endblock %}
comment_form.html:
{% extends 'base.html' %}
{% block content %}
<h1>New Comment</h1>
<form class="post-form" method="POST">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="save btn btn-default">Add Comment</button>
</form>
{% endblock %}
Traceback and error:
Traceback (most recent call last):
File "/anaconda/envs/test/lib/python3.6/site-packages/django/core/handlers/exception.py", line 41, in inner
response = get_response(request)
File "/anaconda/envs/test/lib/python3.6/site-packages/django/core/handlers/base.py", line 198, in _get_response
"returned None instead." % (callback.__module__, view_name)
ValueError: The view feed.views.add_comment_to_post didn't return an HttpResponse object. It returned None instead.
Your view does not return anything if the request is not a POST.
The problem is one of indentation. The last three lines - from else onwards - need to be moved back one level.
I'm trying to have a form post redirect back to the page it was posted from. So my app has a detail page that displays information about a place, /arena/123, and on the same page there is a form that a user can enter some comments or ratings about the current place they are looking at. These are my view functions.
class DetailView(LoginRequiredMixin, generic.DetailView):
model = Arena
template_name = 'arenas/detail.html'
def get_context_data(self, **kwargs):
context = super(DetailView, self).get_context_data(**kwargs)
if 'form' not in context:
print 'no form in context'
context['form'] = RatingForm
return context
def rate(request):
if request.method == 'POST':
form = RatingForm(request.POST)
if form.is_valid():
# post was valid. go back to page and display data
return DetailView.as_view()(request(), form=RatingForm)
else:
# post was unsuccessful. go back to the page and display errors
print form.errors
return DetailView.as_view()(request(), form=form)
and my template
{% extends "base.html" %}
{% block content %}
<h1>{{ arena.address }}</h1>
<h1>{{ arena.address_2 }}</h1>
<h1>{{ arena.phone }}</h1>
{% if form.errors %}
{% for field in form %}
{% for error in field.errors %}
<div class="alert alert-error">
<strong>{{ error|escape }}</strong>
</div>
{% endfor %}
{% endfor %}
{% for error in form.non_field_errors %}
<div class="alert alert-error">
<strong>{{ error|escape }}</strong>
</div>
{% endfor %}
{% endif %}
<form action="/arenas/rate/" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit" />
</form>
<div>
{{comments}}
</div>
{% endblock %}
So what I'd like to do is after a user submits the form on the page I'd like to go back to the same detail page I was on and either have the data that user posted there shown in the comments section if it was successful or redirect back to the same page but with the form errors if it was unsuccessful. My problem is right now I don't know how to retain the url and form errors to display the detail page again. I don't think I can use return DetailView.as_view()(context(), form=form) because my DetailView doesn't have a post so I get a 405. Every example I see doesn't cover redirecting back to the same page. They usually just show a HttpResponseRedirect(/thanks) or something similar.
Also note. I don't want to post to /arena/123 because eventually that will be another feature to update information about the place so I didn't want to put the comments post on that url.
So I dug into some more Django examples and stumbled across SingleObjectMixin. This combined with a FormView seems to be what I want. The Django docs had an example that was 99.9 percent what I wanted here. Just be sure to read down to the better solution section.
I changed my views to this
class DetailView(LoginRequiredMixin, generic.DetailView):
model = Arena
template_name = 'arenas/detail.html'
def get_context_data(self, **kwargs):
print kwargs
context = super(DetailView, self).get_context_data(**kwargs)
context['form'] = RatingForm
return context
class RatingView(LoginRequiredMixin, detail.SingleObjectMixin, generic.FormView):
model = Arena
template_name = 'arenas/detail.html'
form_class = RatingForm
def post(self, request, *args, **kwargs):
self.object = self.get_object()
return super(RatingView, self).post(request, *args, **kwargs)
def get_success_url(self):
print "successfully posted"
return reverse('arenas:detail', kwargs={'pk': self.object.pk})
Added a route for posting the form with /rate
urlpatterns = patterns('',
url(r'^$', views.IndexView.as_view(), name='index'),
url(r'^(?P<pk>\d+)/$',
views.DetailView.as_view(), name='detail'),
url(r'^(?P<pk>\d+)/rate/$', views.RatingView.as_view(), name='rate')
)
and modified my template a bit to pass the id of the object to my route in the form post action
{% extends "base.html" %}
{% block content %}
<h1>{{ arena.address }}</h1>
<h1>{{ arena.address_2 }}</h1>
<h1>{{ arena.phone }}</h1>
{% if form.errors %}
{% for field in form %}
{% for error in field.errors %}
<div class="alert alert-error">
<strong>{{ error|escape }}</strong>
</div>
{% endfor %}
{% endfor %}
{% for error in form.non_field_errors %}
<div class="alert alert-error">
<strong>{{ error|escape }}</strong>
</div>
{% endfor %}
{% endif %}
<form action="/arenas/{{ arena.id }}/rate/" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit" />
</form>
<div>
{{comments}}
</div>
{% endblock %}
Now on an error the context is kept and the SingleObjectMixin/FormView combination keeps me on the same page to display the form errors and on a successful post it redirects to the detail page I want using the get_success_url to load the page again with the new information that was posted.
I am writing a very simple navigation bar. For example I have my login view down below. When I open the login page I can see my the results of my base.html but for some reason I can not see the results of my login.html, meaning I cant see the form I wrote only the top links bar.
view.py -- login view
def login(request):
if request.method == 'POST':
form = UserLoginForm(request.POST)
if form.is_valid():
m = UserLogin.objects.get(user_name=request.POST['user_name'])
if m.password == request.POST['password']:
request.session['member_id'] = m.id
return HttpResponseRedirect('/game')
else:
c = {'form': form,
'error_message': "Your username and password didn't match."}
c.update(csrf(request))
return render_to_respons('game/login.html', c)
else:
form = UserLoginForm()
c = {'form': form}
c.update(csrf(request))
return render_to_response('game/login.html', c)
base.html
<div id="navigation">
Home
Upload
Register
Login
</div>
login.html
{% extends "base.html" %}
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
<form action="/game/login/" method="post">
{% csrf_token %}
<table border='0'>
<div class="fieldWrapper"><tr><td>
{{ form.user_name.errors }}</td><td></td></tr><tr><td>
<label for="id_user_name">User Name:</label></td><td>
{{ form.user_name }}</td></tr>
</div>
<div class="fieldWrapper"><tr><td>
{{ form.password.errors }}</td><td></td><tr><td>
<label for="id_password">Password:</label></td><td>
{{ form.password }}</td></tr>
</div>
</table>
<input type="submit" value="Login" />
</form>
You need to define blocks to use template inheritance. For example, change your base.html to:
<div id="navigation">
Home
Upload
Register
Login
</div>
{% block content %}{% endblock %}
then place your login code into the content block:
{% extends "base.html" %}
{% block content %}
...login.html content goes here
{% endblock %}
Check out the docs for more detail.