i have a problem with Django clean method because clean method of form doesn`t load error in template. Could someone help me ?
template.html
{% extends "index.html" %}
{% block header %}
<div id="container-register">
<div class="logo-register">Zarejestruj się</div>
<div class="register-form">
<form method="post">
{% csrf_token %}
{% for field in form %}
{{ field }} {{ field.errors }} <br>
{% endfor %}
<input type="submit" value="Zarejestruj">
</form>
</div>
</div>
{% endblock %}
view.py
class AddUserView(View):
template_name = 'add_user.html'
def get(self,request):
return render(request, self.template_name,{
'form': AddUserForm()
})
def post(self,request):
form = AddUserForm(request.POST)
if form.is_valid():
User.objects.create_user(
username=form.cleaned_data.get('username'),
email=form.cleaned_data.get('email'),
password=form.cleaned_data.get('password'),
first_name=form.cleaned_data.get('first_name'),
last_name=form.cleaned_data.get('last_name')
)
return redirect('/login')
else:
return render(request, self.template_name, context={
'form': AddUserForm()
})
forms.py
class AddUserForm(forms.Form):
username = forms.CharField(widget=forms.TextInput(attrs={'placeholder': 'Nazwa użytkownika'}), max_length=100)
password = forms.CharField(widget=forms.PasswordInput(attrs={'placeholder': 'Hasło'}), max_length=100)
password_repeat = forms.CharField(widget=forms.PasswordInput(attrs={'placeholder': 'Powtórz hasło'}),
max_length=100)
first_name = forms.CharField(widget=forms.TextInput(attrs={'placeholder': 'Imię'}), max_length=100)
last_name = forms.CharField(widget=forms.TextInput(attrs={'placeholder': 'Nazwisko'}), max_length=100)
email = forms.EmailField(widget=forms.TextInput(attrs={'placeholder': 'Email'}), max_length=100)
def clean_username(self):
if User.objects.filter(username=self.cleaned_data.get('username')).exists():
raise ValidationError('Ten login jest już zajęty')
return self.cleaned_data.get('username')
def clean_password_repeat(self):
if self.cleaned_data.get('password') != self.cleaned_data.get('password_repeat'):
raise ValidationError('Podane hasła różnią się od siebie!')
return self.cleaned_data.get('password_repeat')
I checked the page source to see if the errors class was added in the html file.
In your post method, you create a new form in the template context instead of reuse the existing with data and errors :
return render(request, self.template_name, context={
'form': form
})
Related
I need to have users send me an email through my website with the front and back of their ID for verification. Why is my form returning "This field is required." when everything is filled in? What did I do wrong?
views.py
def market(request):
if request.method == 'GET':
form = ContactForm()
else:
form = ContactForm(request.POST)
if form.is_valid():
from_email = form.cleaned_data['from_email']
subject = form.cleaned_data['subject']
address = form.cleaned_data['address']
id_front = form.cleaned_data['id_front']
additional_details = form.cleaned_data['additional_details']
try:
send_mail(from_email, subject, id_front, address, additional_details, ['admin#example.com'])
except BadHeaderError:
return HttpResponse('Invalid header found.')
return redirect('market_success')
return render(request, "market.html", {'form': form})
def market_success(request):
return HttpResponse('Success! We have received your request and will get back to you soon.')
forms.py
class ContactForm(forms.Form):
from_email = forms.EmailField(required=True)
subject = forms.CharField(required=True)
address = forms.CharField(required=True)
id_front = forms.ImageField(required=True)
additional_details = forms.CharField(widget=forms.Textarea, required=True)
html
{% extends 'base.html' %}
{% block title %}Market{% endblock %}
{% block content %}
<p>To request to market your property with us, please fill out the form below.</p>
<form method="post" enctype="multipart/form-data" class="post-form">
{% csrf_token %}
{{ form.as_p }}
<div class="form-actions">
<button type="submit">Send</button>
</div>
</form>
{% endblock %}
I am trying to build a social network in django. In this code I am trying to enter comments to a post through the template box in my template. But the comment is not getting fetched in my database. My code is as below:
My forms.py creates a model form for comments
forms.py
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ('ctext',)
Models has a seperate comment model which has foreign keys from post model and user model.
models.py
class Post(models.Model):
author = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
title = models.CharField(max_length=200)
text = models.TextField()
created_date = models.DateTimeField(default=timezone.now)
published_date = models.DateTimeField(blank=True, null=True)
imgfile = models.ImageField(upload_to='posts/', blank=True, null=True)
def publish(self):
self.published_date=timezone.now()
self.save()
def __str__(self):
return self.title
class Comment(models.Model):
comment_auth = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
title = models.ForeignKey(Post, on_delete=models.CASCADE)
ctext = models.TextField(blank=True, null=True, max_length=200)
created_date = models.DateTimeField(default=timezone.now)
published_date = models.DateTimeField(blank=True, null=True)
def publish(self):
self.published_date=timezone.now()
self.save()
def __str__(self):
return self.ctext
I guess the logic in views is going wrong somewhere as it been shown while debugging
views.py
def post_list(request):
posts = Post.objects.filter(published_date__lte=timezone.now()).order_by('published_date')
post = get_object_or_404(Post, title=title)
cform = CommentForm()
comments = Comment.objects.all()
if request.method == "POST":
comment_form = CommentForm(data=request.POST)
if comment_form.is_valid():
new_comment = comment_form.save(commit=False)
new_comment.post = post
new_comment.save()
#cform = CommentForm(request.GET)
#data = {}
#Comment.ctext(**data)
#if cform.is_valid():
#comment={}
#comment['ctext'] = request.POST['ctext']
#cform.changed_data['comment_auth'] = request.user
#cform['comment_auth'] = request.user
#cform['comment_auth_id_id'] = request.user
#cform.save()
return render(request, 'users/post_list.html', {'posts': posts, 'comments': comments, 'form': cform})
else:
form = CommentForm()
return render(request, 'users/post_list.html', {'posts': posts, 'comments': comments, 'form': cform})
Template
<div>
<h2>{{ post.title }}</h2>
<p>{{ post.text|linebreaksbr }}</p>
{{image.imgfile.url}}
{% if post.imgfile %}
<img src="{{ post.imgfile.url }}" alt="{{ post.imgfile.url }}">
{% endif %}
<p>By:- {{ post.author }}</p>
<p>published: {{ post.published_date }}</p>
<form method="POST" class="post-form" action="/users/post/list">{% csrf_token %}
{{ form }}
{% for comment in post.comment_set.all %}
<p><b>Comments: </b></p>
<p><b>{{ comment.comment_auth }}: </b>{{ comment.ctext }}</p>
{% endfor %}
<button type="submit" class="save btn btn-default">Comment</button>
</form>
</div>
i am assuming that you have post and comment entries already trough /admin and that you are able to fetch your posts, according to your question here would be the simpliest way to fetch your post-related comments:
{% for post in posts %}
<div>
{{ post.title }}
By - {{ post.author }}
{% for comment in post.comment_set.all %}
<-- is now looking up for all comment entries, where this post is the set foreignkey -->
<p><b>Comments: </b></p>
<p><b>{{ comment.comment_auth }}: </b>{{ comment.ctext }}</p>
{% endfor %}
</div>
{% endfor %}
views.py:
def post_list(request):
posts = Post.objects.filter(published_date__lte=timezone.now()).order_by('published_date')
context = {'posts': posts}
return render(request, 'users/post_list.html', context)
See django docs
change views.py as follows:
def post_list(request):
posts = Post.objects.filter(published_date__lte=timezone.now()).order_by('published_date')
comment_form = CommentForm()
comments = Comment.objects.all()
if request.method == "POST":
data = {
'ctext': request.POST['ctext'],
'comment_auth_id': request.user.id,
'title_id': request.POST['title_id']
}
comment_form = CommentForm(data=data)
if comment_form.is_valid():
Comment.objects.create(**data)
return render(request, 'users/post_list.html', {
'posts': posts,
'comments': comments,
'form': comment_form
})
else:
return render(request, 'users/post_list.html', {
'posts': posts,
'comments': comments,
'form': comment_form
})
As I can understand you are trying to post a new comment and your way of doing it is totally wrong and that is the reason why you are not able to show comments. This is the right way to do:
html:
<p>{{ err_msg }}</p>
{% for post in posts %}
<div>
<!-- Other elements -->
<form method="POST" action="/users/post/list">{% csrf_token %}
{{ form }}
<!-- Sending id of post you are commenting on -->
<input type="hidden" name="post_id" value="{{post.id}}">
<button type="submit">Comment</button>
</form>
<p><b>Comments: </b></p>
{% for comment in post.comment_set.all %}
<p><b>{{ comment.comment_auth }}: </b>{{ comment.ctext }}</p>
{% endfor %}
</div>
{% endfor %}
views.py:
def post_list(request):
posts = Post.objects.filter(published_date__lte=timezone.now()).order_by('published_date')
# I have removed the comments.objects.all
# as you getting them with post.comment_set.all in your template
form = CommentForm()
data = {'posts': posts, 'form': form}
if request.method == "POST":
# get the id of post you are commenting on
cur_post_id = request.POST.get('post_id')
try:
# check if the post exists in the database.
post = Post.objects.get(id=cur_post_id)
comment_form = CommentForm(data=request.POST)
if comment_form.is_valid():
new_comment = comment_form.save(commit=False)
new_comment.title= post
new_comment.comment_auth = request.user
new_comment.save()
except:
data['err_msg'] = 'Post does not exist!'
return render(request, 'users/post_list.html', data)
I have this model:
class User(AbstractUser):
REQUIRED_FIELDS = []
USERNAME_FIELD = 'email'
email = models.EmailField(
_('email address'),
max_length=150,
unique=True,
help_text=_('Required. 150 characters of fewer. Must be a valid email address.'),
error_messages={
'unique':_("A user with that email address already exists."),
},
)
this form class:
class UserForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput)
class Meta:
model = User
fields = ['username','email','password']
this view class:
class UserFormView(View):
form_class = UserForm
template_name = 'workoutcal/register.html'
def get(self, request):
print("Hi again")
form = self.form_class(None)
return render(request, self.template_name, {'form':form})
def post(self, request):
form = self.form_class(request.POST)
if form.is_valid():
user = form.save(commit=False)
username = form.cleaned_data['username']
password = form.cleaned_data['password']
user.set_password(password)
user.save()
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
login(request, user)
return redirect('workoutcal:calendar')
return render(request, self.template_name, {'form': form})
and this url:
url(r'^register/$', views.UserFormView.as_view(), name='register')
So when I go to /workoutcal/register, I see this:
The "help text" is always shown in the browser. Is this default Django behaviour, or is it due to some error I have made?
Also, how do I make the text only show up if the user has entered bad data into the respective fields?
Yes if you are using {{ form }} in your template
It will always show help_text, label, errors and widget automatically
If you don't want that you need to render form manually by looping over fields
<form method="post" novalidate>
{% csrf_token %}
{{ form.non_field_errors }}
{% for hidden_field in form.hidden_fields %}
{{ hidden_field.errors }}
{{ hidden_field }}
{% endfor %}
{% for field in form.visible_fields %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }} {{ field }}
{{ field.help_text }} <!-- remove this line if you don't want to show it in your html.-->
</div>
{% endfor %}
<button type="submit">Submit</button>
</form>
For more read docs: https://docs.djangoproject.com/en/2.0/topics/forms/
I've made a profile model in models.py:
class Profile(models.Model):
user = models.OneToOneField(User)
title = models.CharField(max_length=20, default='title')
firstname = models.CharField(max_length=40, default='firstname')
lastname = models.CharField(max_length=40, default='lastname')
blurb = models.CharField(max_length=500, default='tell us about yourself')
#work out how to make filename equal the username
pic = models.ImageField(default="static/profile/blank.png", upload_to='static/profile/%d%m%y.jpg') #+ user.pk + '.jpg')
def __unicode__(self):
return self.user.username
and here is the view for a page to edit the profile of a logged in user:
def editprofile(request):
u_p = request.user.profile
template = loader.get_template('registration/editprofile.html')
if request.method == 'POST':
form = ProfileForm(request.POST, instance=u_p)
if form.is_valid():
form.save()
else:
# todo
None
else:
#todo
context = RequestContext(request, {'form': form})
return HttpResponse(template.render(context))
The template fragment reads:
<form method="POST" action=".">
{% csrf_token %}
<div class="regformout">
<div class="regform">
{% for field in form %}
<div class='cell'> {{ field.label_tag }} </div>
<div class='nogin'> {{ field.errors }} </div>
<div class='cell'> {{ field }} </div>
{% endfor %}
</div>
</div>
<input class="btn btn-large btn-primary" type="submit" value="Save Your Profile" ></input>
</form>
I want the form fields to automatically populate with the data for the current user on the corresponding page for editing the profile. However, no matter what I try I cannot make this happen. What am I doing wrong here?
Your main problem is you are only populating the form if the user hits the submit button, so when the view is requested initially, your form is empty.
from django.shortcuts import render, redirect
def editprofile(request):
u_p = request.user.profile
form = ProfileForm(request.POST or None, instance=u_p)
if request.method == 'POST':
if form.is_valid():
form.save()
return redirect('/')
return render(request,
'registration/editprofile.html', {'form': form})
I already have codes and it doesn't working. But I'am looking for solution or practice on how to pass data between pages with using form. Should I work with hiddenfields or sessions?. I am ready to change or rewrite my codes. I am open the other suggestions, thought.
Here is my codes
forms.py
class applyForm(forms.ModelForm):
basvuru_mesaji = forms.CharField(required=True,error_messages={'required':'Bu alanı boş bırakmamanız gerekiyor'}, widget=forms.Textarea(attrs={'class': 'full','placeholder': 'Başvuru mesajınızı buraya yazınız'}))
tcn = forms.IntegerField(required=False, error_messages={'invalid':'Numara dışında karakter girişi yaptınız'}, widget=forms.TextInput(attrs={'class': 'full','placeholder': 'T.C. Kimlik Numaranız'}))
hidden = forms.CharField(widget=forms.HiddenInput(), required = False)
class Meta():
model = apply
fields = '__all__'
models.py
class apply(models.Model):
tcn = models.PositiveIntegerField(blank=True, verbose_name='T.C.N :', null=True)
basvuru_mesaji = models.TextField(verbose_name='Başvuru Mesajı')
views.py
def form_for_apply(request):
form = applyForm(request.POST or None)
if form.is_valid():
new_join = form.save(commit=True)
new_join.save()
basvuru_mesaji = form.cleaned_data["basvuru_mesaji"]
return HttpResponseRedirect('/apply_ok/')
context = {"form":form}
template = "apply.html"
return render(request, template, context)
def apply_ok(request):
allfield = apply.objects.all()
print allfield
form = applyForm(request.GET)
context = {"form":form}
#print context.data
template = "apply_ok.html"
return render(request, template, context)
apply.html
{% csrf_token %}
{% if form.errors %}
{{ form.errors }}
{% endif %}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
<div class="mTopTwe">
<label for="{{ form.basvuru_mesaji.id_for_label }}">
{{form.basvuru_mesaji.field.label}}
</label>
{{ form.basvuru_mesaji.errors }}
{{ form.basvuru_mesaji }}
</div>
apply_ok.html
<div class="mTopTwe">
{{form.basvuru_mesaji.data}} {{ form.hidden.data }}
</div>
You can using django wizard-form for passing data between pages.
render_to_response solved my problem.
return render_to_response('apply_ok.html', context_instance=RequestContext(request,{'form':form}))
forms.py
def apply(request):
form = applyForm(request.POST or None)
if form.is_valid():
new_join = form.save(commit=True)
new_join.save()
basvuru_mesaji = form.cleaned_data['basvuru_mesaji']
return render_to_response('apply_ok.html', context_instance=RequestContext(request,{'form':form}))
context = {"form":form}
template = "apply.html"
return render(request, template, context)