How to make Django form field blank after submit? - python

I've created a django subscription form. I want to show a 'Thank You' message below the form after submitting but if I submit the form, email field is still showing the value. I've tried HttpResponseRedirect('/') but doing so doesn't show 'Thank You' message.
#Views.py
global categories
categories = ['Development','Technology','Science','Lifestyle','Other']
class IndexView(TemplateView):
model = Post
template_name = 'blog/index.html'
def post(self,request,*args,**kwargs):
context = self.get_context_data()
if request.method == 'POST':
form = SubscriberForm(request.POST)
if context["form"].is_valid():
context["email"] = request.POST.get('email')
form.save()
form = SubscriberForm()
return render(request, 'blog/index.html', context=context)
else:
form = SubscriberForm()
def get_context_data(self, **kwargs):
# Call the base implementation first to get a context
context = super(IndexView,self).get_context_data(**kwargs)
# Add in a QuerySet of all the books
context['post_list'] = Post.objects.all()
context["categories"] = categories
form = SubscriberForm(self.request.POST or None) # instance= None
context["form"] = form
return context
#sidebar.html
<div class="subscribe">
<form class="" action="" method="post">
{% csrf_token %}
{{ form.as_p }}
<button id="subscribe-button" type="submit" name="button"><i class="fa fa-paper-plane" aria-hidden="true"></i></button>
</form>
{% if email %}
<h6>Thank you for Subscribing!</h6>
{% endif %}
<!-- <i class="fa fa-paper-plane" aria-hidden="true"></i> -->
</div>
#models.py
class Subscribe(models.Model):
email = models.EmailField()
subscribed_on = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ('-subscribed_on',)
def __str__(self):
return 'Subscribed by {} on {}'.format(self.email, self.subscribed_on)
#forms.py
class Subscribe(models.Model):
email = models.EmailField()
subscribed_on = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ('-subscribed_on',)
def __str__(self):
return 'Subscribed by {} on {}'.format(self.email, self.subscribed_on)

Instead of rendering the template you can redirect() after saving the form.
And to render the success message you can use the django messaging framework.
def post(self,request,*args,**kwargs):
context = self.get_context_data()
if request.method == 'POST':
form = SubscriberForm(request.POST)
if context["form"].is_valid():
context["email"] = request.POST.get('email')
form.save()
messages.success(request, 'Thank you for subscribing')
return redirect('/')
else:
form = SubscriberForm()
return render(request, 'blog/index.html', context=context)
Now in the template you can render the messages like this.
<div class="subscribe">
<form class="" action="" method="post">
{% csrf_token %}
{{ form.as_p }}
<button id="subscribe-button" type="submit" name="button"><i class="fa fa-paper-plane" aria-hidden="true"></i></button>
</form>
{% if messages %}
<ul class="messages">
{% for message in messages %}
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
<!-- <i class="fa fa-paper-plane" aria-hidden="true"></i> -->
</div>

Related

django form validation error not showing in DetailView

What am i trying to do is show comment form in Detailview.
it can add comment, but when user write noting in the form it doesn't show error message.
I think i need to return error form somehow, i can not find how
this is my code
forms.py
class CommentForm(forms.ModelForm):
comment_text = forms.CharField(max_length=300,
error_messages={'required':'need comment!!!'},
)
class Meta:
model = Comment
fields= ('comment_text',)
views.py
#login_required
def add_comment(request, pk):
parent_photo = get_object_or_404(Photo, pk=pk)
if request.method == 'POST':
form = CommentForm(request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.parent_photo = parent_photo
comment.user = request.user
comment.save()
return redirect(parent_photo.get_absolute_url())
else:
######## this part??? ########
return redirect(parent_photo.get_absolute_url(), {'comment_form': form })
return redirect(parent_photo.get_absolute_url())
class PhotoDetailView(DetailView):
model = Photo
template_name = 'photo_detail.html'
def get_context_data(self, *args, **kwargs):
context = super().get_context_data()
object = self.get_object()
total_likes = object.total_likes()
context['comment_form'] = CommentForm
context['total_likes'] = total_likes
return context
urls.py
urlpatterns = [
path('<int:pk>/', views.PhotoDetailView.as_view(), name = 'detail'),
path('<int:pk>/add_comment/', views.add_comment, name='add_comment'),
]
templates
{% if user.is_authenticated%}
<div class=" my-3">
<p class='mb-0 ml-2'>Leave a comment ! </p>
<form class="input-group" id='comment_form' method="POST"
action="{{ photo.get_absolute_url }}add_comment/">
{% csrf_token %}
{% for field in comment_form %}
<input type="{{ field.field.widget.input_type }}" class="form-control" id="{{ field.id_for_label }}"
name="{{ field.name }}">
{% if field.errors %}
<small class='text-danger'>{{ field.errors }}</samll>
{% endif %}
<div class="input-group-append">
<button type="submit" class="btn btn-primary btn-sm">ADD</button>
</div>
{%endfor%}
</form>
</div>
{% endif %}
i put 'required' in input
<input type="{{ field.field.widget.input_type }}" class="form-control" id="{{ field.id_for_label }}"
name="{{ field.name }}">
and in add_comment view, only consider is_valid() case.
#login_required
def add_comment(request, pk):
parent_photo = get_object_or_404(Photo, pk=pk)
if request.method == 'POST':
form = CommentForm(request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.parent_photo = parent_photo
comment.user = request.user
comment.save()
return redirect(parent_photo.get_absolute_url())
return redirect(parent_photo.get_absolute_url())
it is not the answer for my question,
but works as i intended.

Django Model Form not showing errors after validation in clean()

Can you help me out with this. I hava a model form and I need to raise an error after validate two datetime objects in the clean method of the model form. This is what I have.
Forms
class HorariosDisponibles(forms.ModelForm):
tutor = forms.ModelChoiceField(queryset=Tutor.objects.all(),widget=forms.Select(attrs= {'class': 'input is-small is-rounded ' }),label='TUTOR',)
dia_hor_inicio =forms.DateTimeField(widget=forms.DateTimeInput(attrs= {'class': 'input is-small is-rounded ',}),label='Horario de Inicio', initial=datetime.date.today )
dia_hor_fin= forms.DateTimeField(widget=forms.DateTimeInput(attrs= {'class': 'input is-small is-rounded ' }),label='Horario de FinalizaciĆ³n', initial=datetime.date.today)
class Meta:
model = horarios_disp
fields = '__all__'
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields["dia_hor_inicio"].widget = DateTimeInput()
self.fields["dia_hor_inicio"].input_formats = ["%Y-%m-%dT%H:%M", "%Y-%m-%d %H:%M"]
self.fields["dia_hor_fin"].widget = DateTimeInput()
self.fields["dia_hor_fin"].input_formats = ["%Y-%m-%dT%H:%M", "%Y-%m-%d %H:%M"]
def clean(self):
cleaned_data = super(HorariosDisponibles, self).clean()
tutor = cleaned_data.get("tutor")
dia_hor_inicio = cleaned_data.get("dia_hor_inicio")
dia_hor_fin = cleaned_data.get("dia_hor_fin")
if dia_hor_inicio and dia_hor_fin:
if dia_hor_inicio.day != dia_hor_fin.day :
msg = 'Las fechas no pueden ser distintas'
self.add_error("dia_hor_inicio", msg)
raise forms.ValidationError("Las fechas no pueden ser distintas")
#NEITHER OF THIS APPROACHES WORKED
return cleaned_data
VIEWS
#login_required
def horario_tutor(request):
context = {
}
if request.method == 'POST':
print(request.POST)
form = HorariosDisponibles(request.POST)
if form.is_valid():
tutor = form.cleaned_data['tutor']
print("adentro")
dia_hor_inicio = form.cleaned_data['dia_hor_inicio']
dia_hor_fin = form.cleaned_data['dia_hor_fin']
tutor_horario = horarios_disp(
tutor=tutor, dia_hor_inicio=dia_hor_inicio, dia_hor_fin=dia_hor_fin)
tutor_horario.save()
context = {
'form': form
}
return redirect("home")
return render(request,"horarios_disponibles.html", context)
else:
form = HorariosDisponibles()
context['form'] = form
return render(request, "horarios_disponibles.html", context)
TEMPLATES
{% extends 'base.html' %}
{% block body %}
<section class="section">
<div class="columns is-vcentered">
<div class="column is-centered is-4 is-offset-2">
<form method="post">
{% csrf_token %}
{% for field in form %}
<div class="field">
{% for error in field.errors %}
<p class="help is-danger">{{ error }}</p>
{% endfor %}
<label for="{{field.id_for_label}}" class="label">{{ field.label }}</label>
{{ field }}
{% for non_field_error in form.non_field_errors %}
<p class="help is-danger">{{ non_field_error }}</p>
{% endfor %}
{% if field.help_text %}
<p class="help is-danger">{{ field.help_text|safe }}</p>
{% endif %}
</div>
{% endfor %}
<p class="control">
<button class="button is-link" type="submit">
Enviar
</button>
</p>
</form>
</section>
It validates if I put two different dates in the form, but it doesn't enter to is_valid() (because ther form is not valid). Render just the button of the template.
Try this:
if form.is_valid():
tutor = form.cleaned_data['tutor']
dia_hor_inicio = form.cleaned_data['dia_hor_inicio']
dia_hor_fin = form.cleaned_data['dia_hor_fin']
tutor_horario = horarios_disp(
tutor=tutor, dia_hor_inicio=dia_hor_inicio, dia_hor_fin=dia_hor_fin
)
tutor_horario.save()
context = {'form': form}
return redirect("home")
else:
context = {'error': 'whatever error you want to show here'}
return render(request, "horarios_disponibles.html", context)
# and probably some extra handling at the end in case there are errors
As a matter of fact, you won't need to declare the context = {} at the beginning of your code before if request.method == 'POST' because you're going to declare one on in the if-else statement anyways.

redirecting to comment section after login is not working in django

it saves and displays comments on the options.html page if the user is already logged in but when the user logs in after comment section redirects to the login page it displays the value error as this:
NoReverseMatch at /rank/best-trekking-destination-in-nepal/comment/
Reverse for 'comment' with arguments '('',)' not found. 1 pattern(s) tried: ['rank/(?P[^/]+)/comment/$']
Request Method: GET
Request URL: http://127.0.0.1:8000/rank/best-trekking-destination-in-nepal/comment/
Django Version: 2.1.5
Exception Type: NoReverseMatch
Exception Value:
Reverse for 'comment' with arguments '('',)' not found. 1 pattern(s) tried: ['rank/(?P[^/]+)/comment/$']
urls.py
path('<slug>/',views.options,name='options'),
path('<slug>/comment/',views.comment,name='comment'),
views.py
def options(request,slug):
category = Category.objects.get(slug=slug)
category.views += 1
category.save()
options = category.option_set.all().order_by('-votes')
try:
for option in options:
option.has_voted = option.vote_set.filter(voter=request.user).exists()
except:
options = category.option_set.all().order_by('-votes')
form = CommentForm()
return render(request, 'rank/options.html', {'options': options,'form':form,'title': 'options','category':category})
#login_required(redirect_field_name='next',login_url='rank:login')
def comment(request,slug):
if request.method == "POST":
form = CommentForm(request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.category = Category.objects.get(slug=slug)
comment.user = request.user
comment.save()
messages.success(request, 'Comment Posted.')
return redirect('rank:options', slug)
else:
form = CommentForm()
return render(request, 'rank/options.html', {'form': form})
def my_login(request):
if request.method == "POST":
form = LoginForm(request.POST)
username = form['username'].value()
password = form['password'].value()
user = authenticate(username=username,password=password)
if user:
login(request,user)
redirect_url = request.GET.get('next','rank:home')
return redirect(redirect_url)
else:
messages.error(request,'Invaid Username or Password')
else:
form = LoginForm()
return render(request,'rank/login.html',{'form':form})
options.html
{% extends "rank/base.html" %}
<title>{% block title %}{{title}}{% endblock title%}</title>
{% load bootstrap4 %}
{% block content %}
<center><br>
<ol type="1">
<center>{% bootstrap_messages %}</center>
{% for option in options %}
<div class="col-lg-6 col-md-6 mb-6">
<div class="card h-100">
<div class="card-body">
<b><li>
<img src="/media/{{option.image}}" width="400" height="300">
<h4>{{option.name}}
</h4>
<h5 class="card-text">{{ option.details}}</h5>
<h5>{{ option.votes }} votes</h5>
{% if option.has_voted %}
<p class="btn btn-success">Voted</p>
{% else %}
<form action="{% url 'rank:vote' option.slug %}" method="post">
{% csrf_token %}
<input type="submit" class="btn btn-success" value="Vote" >
</form>
{% endif %}
</li></b>
</div>
<div class="card-footer">
<small class="text-muted"></small>
</div>
</div>
</div>
{% empty %}
<div class="card w-100">
<div class="card-body">
<h4>Item not available</h4>
</div>
</div>
{% endfor %}
</ol>
<h3>{{ category.comment_set.all|length}} comments</h3>
<hr>
{% for c in category.comment_set.all %}
<div class="col-lg-6 col-md-6 mb-6">
<div class="card-footer text-muted">
<b>{{ c.user.username}} </b>&nbsp {{c.created|timesince}} ago
</div>
<div class="card-body">
<p class="card-text">{{ c.comment}}</p>
</div>
</div>
{% endfor %}
<hr>
<div class="col-lg-6 col-md-6 mb-6">
<form method="post" action="{% url 'rank:comment' category.slug %}">
{% csrf_token %}
{% bootstrap_form form %}
<input type="submit" class="btn btn-success" value="Post Comment">
</form>
</div>
</center>
{% endblock content%}
you comment function in views.py is incomplete. you don't handle GET and other types of request in there:
#login_required(redirect_field_name='next',login_url='rank:login')
def comment(request,slug):
if request.method == "POST":
form = CommentForm(request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.category = Category.objects.get(slug=slug)
comment.user = request.user
comment.save()
messages.success(request, 'Comment Posted.')
return redirect('rank:options',slug)
else:
form = CommentForm()
return render(request,'...some_template',{'form':form})
UPDATE: your next error NoReverseMatch is occured because vairable category (and also options) not send from views to the options.html template and therefor it is null in the template (arguments '('',)' not found). you can fix that like this:
#login_required(redirect_field_name='next',login_url='rank:login')
def comment(request,slug):
if request.method == "POST":
form = CommentForm(request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.category = Category.objects.get(slug=slug)
comment.user = request.user
comment.save()
messages.success(request, 'Comment Posted.')
return redirect('rank:options', slug)
else:
form = CommentForm()
category = Category.objects.get(slug=slug)
options = category.option_set.all().order_by('-votes')
return render(request, 'rank/options.html', {'options': options,'form':form,'title': 'options','category':category})
#login_required(redirect_field_name='next',login_url='rank:login')
def comment(request,slug):
if request.method == "POST":
form = CommentForm(request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.category = Category.objects.get(slug=slug)
comment.user = request.user
comment.save()
messages.success(request, 'Comment Posted.')
return redirect('rank:options',slug)
return redirect('some default view')
You need to add a view to each branch of computation if your POST request view fails or the form is not valid then a view is not returned. I put a line of code you need to finish off.

how to implement search form and post create form in single class based view

I'm trying to implement both searching posts and create a post in single view.
views.py
class HomeView(TemplateView):
template_name = 'home/home.html'
def get(self, request):
post_list = None
form = HomeForm(self.request.GET or None)
form1 = CommentForm(self.request.GET or None)
posts = Post.objects.filter(user = request.user).order_by('-created')
comments = Comment.objects.all()
users = User.objects.exclude(id=request.user.id)
query = request.GET.get('q')
if query:
post_list = Post.objects.filter(
Q(post__icontains=query)
)
context = {
'posts_list': post_list, }
print(post_list)
args = {
'form': form, 'posts': posts, 'users': users, 'form1':form1,
'comments':comments,'post_list':post_list,
}
return render(request, self.template_name, args)
def post(self, request):
form1 = CommentForm()
text = ''
if request.method=='GET' and 'btn1' in request.POST:
post_list = Post.published.all()
query = request.GET.get('q')
if query:
post_list = Post.objects.filter(
Q(post__icontains=query)
)
context = {
'posts_list': posts_list,
}
return redirect('home:home')
if request.method=='POST' and 'btn' in request.POST:
form = HomeForm(request.POST,request.FILES)
if form.is_valid():
post = form.save(commit=False)
post.user = request.user
post.save()
text = form.cleaned_data['post']
form = HomeForm()
form1 = CommentForm()
return redirect('home:home')
html code
<form enctype="multipart/form-data" class="form-inline my-2 my-lg-0" action=".">
<input class="form-control mr-sm-2" type="search" placeholder="Search" aria-label="Search" name='q'>
<button class="btn btn-outline-success my-2 my-sm-0" name="btn1" type="submit">Search</button>
{% block body %}
<div class="container">
<div class="col-md-8">
<h2>Home</h2>
<form method="POST" enctype="multipart/form-data" type = 'file'>
{% csrf_token %}
{{ form.post }}
{{ form.image }}
<br>
<button name="btn" type="submit">Submit</button>
</form>
<h2>{{ text }}</h2>
{% for post in posts %}
<h1>{{post.id}}.{{ post.post }}</h1>
<br>
<img src="{{ post.image.url }}" width = 240 >
<p>Posted by {{ post.user.get_full_name }} on {{ post.created }}</p>
<!-- <form action="{% url 'home:cmnt' pk=post.id %}" method="POST" enctype="multipart/form-data" type = 'file'>
{% csrf_token %}
{{ form1.content }}
<br>
<button type="submit">Submit</button>
</form> -->
{{comments.count}} comment{{comments|pluralize}}<br>
{% for comment in post.comment_set.all %}
<small><b>{{ comment.comment }}</b></small>
<p>commented by {{ comment.user.get_full_name }} on {{ comment.created }}</p>
{% endfor %}
{% endfor %}
</div>
</div>
{% endblock %}
from this code I get the query value entered by the user.
when I implement this code I need to fill both the forms post create and search form but, I need to submit only one form at a time
when I fill both the forms and submit I get URL like this
http://127.0.0.1:8000/home/?q=django+&csrfmiddlewaretoken=OsNRlkvRjSHHuNYMxhZS9MFushCzCTZtjFvgEb5qFFybovBhWI3X0uufvd8bO8WS&post=asdsad&image=7653_1792089421024273_590924154993413545_n.jpg&btn=
I need a code which implements:
when submitted post create form create the post and return
when submitted search form load the respective results from database

Django - Form is not saving the modifications

I'm creating a page where my users can edit their articles but there is one problem, my form is not saving the modifications when I submit my form. Let's have a look:
views.py
def edit(request, id=None, template_name='article_edit.html'):
if id:
article = get_object_or_404(Article, id=id)
if article.user != request.user:
return HttpResponseForbidden()
else:
article = Article(user=request.user)
if request.POST:
form = ArticleForm(request.POST, instance=article)
if form.is_valid():
save_it = form.save()
save_it.save()
form.save_m2m()
return HttpResponseRedirect("/")
else:
form = ArticleForm(instance=article)
context = {'form': form}
populateContext(request, context)
return render(request, template_name, context)
line 3 to 8 : Is to check if it's your own articles there is no problem with that.
line 10 to 18 : There is a problem between these lines, my form is not saving when I submit my form
forms.py (ModelForm)
class ArticleForm(forms.ModelForm):
class Meta:
model = Article
exclude = ['date', 'rating', 'user']
form = ArticleForm()
(Line 4 : I'm excluding the date, the ratings and the username when saved so that the user can not change these informations.)
I don't have any problem in my template.html and the urls.py don't bother with that I checked over 10 times :)
Any help would be great, I'm blocked on this problem since over 1 month...
******* EDIT *******
Models.py
class Article(models.Model):
user = models.ForeignKey(User)
titre = models.CharField(max_length=100, unique=True)
summary = RichTextField(null=True, max_length=140)
contenu = RichTextField(null=True)
date = models.DateTimeField(auto_now_add=True, auto_now=False, verbose_name="Date de parution")
image = models.ImageField(upload_to='article', default='article/amazarashi.jpeg')
rating = RatingField(can_change_vote=True)
tags = TaggableManager(through=TaggedItem, blank=True)
def __str__(self):
return self.titre
Template.html
{% block body %}
{% if user.is_authenticated %}
<p>Authentificated as <strong>{{ user.username }}</strong></p>
{% else %}
<p>NOT Authentificated</p>
{% endif %}
<h1>Edit this {{ article.titre }}</h1>
<br>
<div class="col-xs-12 col-sm-8 col-md-8 col-lg-8">
<form enctype='multipart/form-data' action="{% url "article.views.index" %}" method="post" class="form" autocomplete="off" autocorrect="off">
{% csrf_token %}
<div class="form-group">TITRE
{{ form.titre.errors }}
{{ form.titre }}
</div>
<div class="form-group">SUMMARY
{{ form.media }}
{{ form.summary.errors }}
{{ form.summary }}
</div>
<div class="form-group">CONTENU
{{ form.media }}
{{ form.contenu.errors }}
{{ form.contenu }}
</div>
<div class="form-group">
{{ form.image.errors }}
{{ form.image }}
</div>
<div class="form-group">TAGS
{{ form.tags.errors }}
{{ form.tags }}
</div>
<input type="submit" class="btn btn-default" value="Submit"/>
</div>
</form>
{% endblock %}
According to your error message.. Modify your form in templates:
<form enctype='multipart/form-data' ...>
Add request.FILES to your Form creation:
if request.POST:
form = ArticleForm(request.POST, request.FILES, instance=article)
UPDATE:
You have strange url tag parameter. Are you sure you have defined your url like: ('...', your_view, name='article.views.index')? I am in doubt cause url tag takes url name as parameter but not view path and nobody usually uses url names like this.

Categories

Resources