Django form doesn't show error on template page - django

My code is exactly the same as https://simpleisbetterthancomplex.com/series/2017/09/18/a-complete-beginners-guide-to-django-part-3.html#rendering-bootstrap-forms this. But when I click on the "post" button in the template it shows me the same page without the errors like the field is required.
In my virtualenv,
Python 3.7.4,
Django 2.2.7
and I've installed Django-widgets-improved.
//view
def new_topic(request, pk):
board = get_object_or_404(Board, pk=pk)
user = User.objects.first()
if request.method == 'POST':
form = NewTopicForm(request.POST)
if form.is_valid():
topic = form.save(commit=False)
topic.board = board
topic.starter = user
topic.save()
post = Post.objects.create(
message = form.cleaned_data.get('message'),
topic = topic,
created_by = user
)
return redirect('board_topics', pk = board.pk)
form = NewTopicForm()
return render(request, 'new_topic.html', {'board': board, 'form': form})
//form html
<form method="post" novalidate>
{% csrf_token %}
{{ form.non_field_errors }}
{{ form.errors }}
{{ form.as_p }}
<button type="submit" class="btn btn-success">Post</button>
</form>
//models.py
from django.db import models
from django.contrib.auth.models import User
class Board(models.Model):
name = models.CharField(max_length=25, unique=True)
description = models.CharField(max_length=100)
def __str__(self):
return self.name
class Topic(models.Model):
subject = models.CharField(max_length=255)
last_updated = models.DateTimeField(auto_now_add=True)
board = models.ForeignKey(Board, on_delete=models.CASCADE, related_name='topics')
starter = models.ForeignKey(User, on_delete=models.CASCADE, related_name='topics')
class Post(models.Model):
message = models.TextField(max_length=4000)
topic = models.ForeignKey(Topic, on_delete=models.CASCADE, related_name='posts')
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(null=True)
created_by = models.ForeignKey(User, on_delete=models.CASCADE, related_name='posts')
updated_by = models.ForeignKey(User, null=True, on_delete=models.CASCADE, related_name='+')
//forms.py
from django import forms
from .models import Topic
class NewTopicForm(forms.ModelForm):
message = forms.CharField(
widget=forms.Textarea(
attrs={'rows':5, 'placeholder':'What is in your mind?'}
),
max_length=4000,
help_text='The max length of the text is 4000.')
class Meta:
model = Topic
fields = ['subject', 'message']
//main/urls.py
from django.contrib import admin
from django.urls import path
from boards import views
urlpatterns = [
path('admin/', admin.site.urls),
path('', views.home, name='home'),
path('boards/<int:pk>/', views.board_topics, name='board_topics'),
path('boards/<int:pk>/new/', views.new_topic, name='new_topic'),
]

Inital form form = NewTopicForm() must be declared before if request.method == 'POST': or in else: condition. In your case the clean form always arrives at the template.
def new_topic(request, pk):
board = get_object_or_404(Board, pk=pk)
user = User.objects.first()
form = NewTopicForm() # <---
if request.method == 'POST':
form = NewTopicForm(request.POST)
if form.is_valid():
topic = form.save(commit=False)
topic.board = board
topic.starter = user
topic.save()
post = Post.objects.create(
message = form.cleaned_data.get('message'),
topic = topic,
created_by = user
)
return redirect('board_topics', pk = board.pk)
return render(request, 'new_topic.html', {'board': board, 'form': form})
or
def new_topic(request, pk):
board = get_object_or_404(Board, pk=pk)
user = User.objects.first()
if request.method == 'POST':
form = NewTopicForm(request.POST)
if form.is_valid():
topic = form.save(commit=False)
topic.board = board
topic.starter = user
topic.save()
post = Post.objects.create(
message = form.cleaned_data.get('message'),
topic = topic,
created_by = user
)
return redirect('board_topics', pk = board.pk)
else:
form = NewTopicForm() # <---
return render(request, 'new_topic.html', {'board': board, 'form': form})

Related

DJANGO: forms dont show error to user (def post + ListView)

can you help me?
I can't fix problem: my don't show error validation
when I write not unique slug at form -> no error at form
I think problem at use def post() or return redirect after validations form.
I try many different solutions but nothing helps.
Maybe you should use a non-standard way to report an error?
models.py
class ShortUrl(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name='Автор URL', null=True)
url = models.CharField('Ссылка', max_length=200)
slug = models.SlugField('Короткое имя ссылки', unique=True, max_length=20)
def __str__(self):
#return self.slug
return f"Короткая ссылка: {self.user} >> {self.slug}"
​
class Meta:
verbose_name = 'Ссылка'
verbose_name_plural = 'Ссылки
forms.py
class ShortURLForm(forms.ModelForm):
slug = forms.SlugField(
label='Название URL',
required=True,
widget=forms.TextInput(attrs={'placeholder': 'Укажите уникальный URL'})
)
url = forms.CharField(
label='Ссылка',
required=True,
widget=forms.TextInput(attrs={'placeholder': 'Ссылка которую нужно сократить'})​
)
class Meta:
model = ShortUrl
fields = ['user', 'url', 'slug']
widgets = {'user': forms.HiddenInput()}
views.py
class ShortURLPage(LoginRequiredMixin, ListView):
model = ShortUrl
template_name = 'main/shorts.html'
context_object_name = 'shorts'
​
def get_context_data(self, *, object_list=None, **kwargs):
ctx = super(ShortURLPage, self).get_context_data(**kwargs)
ctx['form'] = ShortURLForm()
userurls = ShortUrl.objects.filter(user=self.request.user)
ctx['shorts'] = userurls
ctx['title'] = 'Добавление ссылок'
return ctx
​
def post(self, request, *args, **kwargs):
post = request.POST.copy()
post['user'] = request.user
request.POST = post
form = ShortURLForm(request.POST)
​
if form.is_valid():
slug = form.cleaned_data['slug']
url = form.cleaned_data['url']
form.save()
​
return redirect('shorts')
shorts.html
<form method="post" class="form">
{% csrf_token %}
{{ form }}
<button class="button" type="submit">Создать ссылку</button>
</form>
urls.py
urlpatterns = [
path('', views.homepage, name='home'),
path('about/', views.about, name='about'),
path('shorts/', views.ShortURLPage.as_view(), name='shorts'),
path('shorts/<str:slug>/', views.urlRedirect, name='redirect'),
]
Ok, you're not so far away with accomplishing what you want.
Generally your post method should look like this:
def post(self, request, *args, **kwargs):
post = request.POST.copy()
post['user'] = request.user
request.POST = post
form = ShortURLForm(request.POST)
​
if form.is_valid():
slug = form.cleaned_data['slug']
url = form.cleaned_data['url']
form.save()
else:
context = {
'form': form,
}
return render(
request,
self.template_name,
context,
)
return redirect('shorts')
Then, you should write your shorts.html template like this:
<form method="post" class="form">
{% csrf_token %}
{{ form.non_field_errors }}
{{ form.errors }}
{{ form }}
<button class="button" type="submit">Создать ссылку</button>
</form>

Django User Profile Update form returning blank

Form is updating without error but after saving form, all fields are empty.Here is my code:
#models.py
class User(AbstractUser):
is_employer = models.BooleanField(default=False)
is_jobseeker = models.BooleanField(default=False)
class JobseekerProfile(models.Model):
user = models.OneToOneField(User, on_delete = models.CASCADE, primary_key = True,
related_name='jobseekerprofile')
# Basic Information
FirstName = models.CharField(max_length=30, blank=False, null=False, verbose_name='First Name')
LastName = models.CharField(max_length=30, blank=False, null=False, verbose_name='Last Name')
Gender = models.CharField(max_length=20, choices=GENDER_CHOICE)
DateOffBorth = models.DateField(verbose_name='Date Of Birth')
MarrigeStatus = models.CharField(max_length=20, choices=MARRIED_STATUS_CHOICES, verbose_name='Marrige
Status')
Religion = models.CharField(max_length=20, choices=RELIGION_CHOOSE)
PhoneNumber = models.CharField(max_length=20, verbose_name='Phone Number')
Email = models.EmailField(max_length=30, null=False, verbose_name='Email Address')
Nationality = models.CharField(max_length=30, choices=NATIONALITY_CHOOSE, verbose_name='Nationality')
CurrentAddress = models.CharField(max_length=100, verbose_name='Current Address')
PernamentAddress = models.CharField(max_length=100, verbose_name='Pernament Address')
ProfileImage = models.ImageField(upload_to = 'Jobseeker/Profile_Pictures', verbose_name='Profile
Picture')
# Education Information
Education = models.CharField(max_length=100, choices=EDUCATION_CHOICES, verbose_name='Education')
EducationProgram = models.CharField(max_length=200, verbose_name='Education Program')
EducationBoard = models.CharField(max_length=100, choices=EDUCATION_BOARD_CHOICES,
verbose_name='Education Board')
NameOfInstitute = models.CharField(max_length=200, verbose_name='Name Of Institute')
# skill
MySkill = models.ManyToManyField(Skill, verbose_name='My Skill')
# Past jobs
WorkingExperience = models.IntegerField(default=0, verbose_name='Working Experience')
WorkedField = models.CharField(max_length=50, null=True, verbose_name='Worked Related Fields')
WorkedCompanyName = models.CharField(max_length=200, verbose_name='Worked Company Name')
WorkedCompanyWebsite = models.URLField(max_length=200, verbose_name='Worked Company Website')
# job category
JobCategory = models.ManyToManyField(Category, verbose_name='Job Category')
# add language
Language = models.CharField(max_length=20, choices=LANGUAGES_CHOICES)
# about Me
AboutMe = RichTextField(verbose_name='About Me')
# Social account
Facebook = models.URLField(max_length=100)
Twitter = models.URLField(max_length=100)
Instagram = models.URLField(max_length=100)
# upload cv
UploadCv = models.FileField(upload_to='Jobseeker/CVs', verbose_name='Upload Your CV')
def __str__(self):
return f'{self.user.username} profile'
def get_absolute_url(self):
return reverse("jobseeker:jobseeker_profile_detail")
#Signals.py
from django.db.models.signals import post_save
from account.models import JobseekerProfile
from django.contrib.auth.models import User
from django.dispatch import receiver
#receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **Kwargs):
if created:
JobseekerProfile.objects.create(user=instance)
#receiver(post_save, sender=User)
def save_profile(sender, instance, **Kwargs):
instance.jobseekerprofile.save()
#forms.py
class JobseekerSignupForm(UserCreationForm):
class Meta(UserCreationForm.Meta):
model = User
fields = ['username', 'password1', 'password2']
#transaction.atomic
def save(self):
user = super().save(commit=False)
user.is_jobseeker = True
user.save()
return user
class JobseekerUpdateForm(forms.ModelForm):
class Meta:
model = User
fields = ['username']
class JobseekerProfileForm(forms.ModelForm):
class Meta:
model = JobseekerProfile
fields = ['FirstName', 'LastName', 'Email','Gender','DateOffBorth',
'MarrigeStatus', 'Religion', 'PhoneNumber', 'Nationality',
'CurrentAddress', 'PernamentAddress', 'Religion', 'EducationProgram',
'EducationBoard', 'NameOfInstitute', 'MySkill', 'WorkingExperience',
'WorkedCompanyName', 'WorkedCompanyWebsite', 'JobCategory',
'Language', 'AboutMe', 'Facebook', 'Twitter', 'Instagram',
'UploadCv', 'UploadProfilePicture']
def clean_field(self):
data = self.cleaned_data["__all__"]
return data
#Views.py
#login_required
#jobseeker_required
def JobseekerProfileCreateView(request):
if request.method == 'POST':
username_form = JobseekerUpdateForm(request.POST, instance=request.user)
profile_form = JobseekerProfileForm(request.POST, request.FILES, instance =
request.user.jobseekerprofile)
if username_form.is_valid() and profile_form.is_valid():
username_form.save()
profile_form.save()
messages.success(request, f'Your Accounted has been updated!')
return redirect('../')
else:
username_form = JobseekerUpdateForm(request.POST, instance=request.user)
profile_form = JobseekerProfileForm(request.POST, request.FILES, instance =
request.user.jobseekerprofile)
contex = {'u_form': username_form, 'p_form': profile_form }
return render(request, 'account/Jobseeker/add_profile_detail.html' , contex)
#edit_Profile.html
<form method = 'POST' enctype="multipart/form-data">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">Add your detail in database</legend>
<div class = "container">
{{ u_form|crispy }}
{{ p_form|crispy }}
</div>
</fieldset>
<div class="form-group">
<button type="submit" class="btn btn-outline-info btn-block">Save</button>
</div>
</form>
user profile update form(blank):
Don't throw any errors while, fill required forms fields fields, all are saved successful but after refresh this page all forms fields are empty.
How to solve this it? any idea?
try this, in your views.py
if request.method == 'POST':
profile_form = JobseekerProfileForm(request.POST, request.FILES, instance=request.user.jobseekerprofile)
if profile_form.is_valid():
request.user.username = request.POST['username']
request.user.save()
profile_form.save()
messages.success(request, f'Your Accounted has been updated!')
return redirect('/')
else:
username_form = JobseekerUpdateForm(instance=request.user)
profile_form = JobseekerProfileForm(instance=request.user.jobseekerprofile)

Django Comments Newbie

I started learning Django about a month ago and just finished Django for Beginners by William Vincent. The book ends with Ch.15: Comments and shows how the admin can add comments to posts.
Q: Can someone, please, show me or point me in the right direction as to how I can let registered users also add comments to posts? Is there perhaps a 3rd party app for that?
What I have so far:
Models:
class Article(models.Model):
title = models.CharField(max_length=255)
body = models.TextField()
date = models.DateTimeField(auto_now_add=True)
image = models.ImageField(upload_to='images/', null=True, blank=True, height_field=None, width_field=None)
upload = models.FileField(upload_to='files/', null=True, blank=True)
author = models.ForeignKey(
get_user_model(),
on_delete=models.CASCADE,
)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('article_detail', args=[str(self.id)])
class Comment(models.Model):
article = models.ForeignKey(Article, on_delete=models.CASCADE, related_name='comment')
comment = models.CharField(max_length=140)
date = models.DateTimeField(auto_now_add=True)
author = models.ForeignKey(
get_user_model(), on_delete=models.CASCADE,
)
def __str__(self):
return self.comment
def get_absolute_url(self):
return reverse('article_list')
forms.py
class PostForm(forms.ModelForm):
class Meta:
model = Article
fields = ('title', 'body', 'image', 'upload')
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ('comment', 'author')
Views:
class ArticleListView(LoginRequiredMixin, ListView):
model = Article
template_name = 'article_list.html'
comment_form = CommentForm
login_url = 'login'
class ArticleDetailView(LoginRequiredMixin, DetailView):
model = Article
template_name = 'article_detail.html'
login_url = 'login'
class ArticleUpdateView(LoginRequiredMixin, UpdateView):
model = Article
fields = ('title', 'body', 'image', 'upload')
template_name = 'article_edit.html'
login_url = 'login'
def dispatch(self, request, *args, **kwargs):
obj = self.get_object()
if obj.author != self.request.user:
raise PermissionDenied
return super().dispatch (request, *args, **kwargs)
class ArticleDeleteView(LoginRequiredMixin, DeleteView):
model = Article
template_name = 'article_delete.html'
success_url = reverse_lazy('article_list')
login_url = 'login'
def dispatch(self, request, *args, **kwargs):
obj = self.get_object()
if obj.author != self.request.user:
raise PermissionDenied
return super().dispatch (request, *args, **kwargs)
class ArticleCreateView(LoginRequiredMixin, CreateView):
model = Article
form_class = PostForm
template_name = 'article_new.html'
login_url = 'login'
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
URLs:
urlpatterns = [
path('<int:pk>/edit/', ArticleUpdateView.as_view(), name='article_edit'),
path('<int:pk>/', ArticleDetailView.as_view(), name='article_detail'),
path('<int:pk>/delete/', ArticleDeleteView.as_view(), name='article_delete'),
path('', ArticleListView.as_view(), name='article_list'),
path('new/', ArticleCreateView.as_view(), name='article_new'),]
Thank you for your attention.
Solved. In my views.py I added the following function:
def add_comment(request, pk):
article = get_object_or_404(Article, pk=pk)
if request.method == "POST":
form = CommentForm(request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.article = article
comment.save()
return redirect('article_detail', pk=article.pk)
else:
form = CommentForm()
return render(request, 'add_comment.html', {'form': form})
Then the following .html file was added to templates:
add_comment.html
{% extends 'base.html' %}
{% block content %}
<h4>Add a Comment</h4>
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
<p>{{ form.as_p }}</p>
<button type="submit" class="btn btn-success">Submit</button>
</form>
{% endblock content %}
P.S.: Initially I was getting an ImportError: cannot import name 'add_comment' from 'articles.views'.
I thought it was a circular import problem and what worked for me was just getting the def add_comment indentation right.

Why is this ModelForm not valid

I'm new to coding with django, and I'm trying to add comments to my blog app, but I'm having trouble with the validation of this form, it always returns False with form.is_valid(), so the object is never saved
views.py
def blog_post_detail_view(request, slug):
obj = get_object_or_404(BlogPost, slug=slug)
comments = Comment.objects.filter(blog_post=obj)
initial_data = {
"blog_post": obj,
}
form = CommentModelForm(request.POST or None, initial=initial_data)
if form.is_valid():
comment_obj = form.save(commit=False)
comment_obj.user = request.user
comment_obj.save()
form = CommentModelForm()
else:
print('not clean')
context = {
"object": obj,
"comments": comments,
"form": form,
}
template_name = 'blog/detail.html'
return render(request, template_name, context)
forms.py
from django import forms
from .models import Comment
class CommentModelForm(forms.ModelForm):
class Meta:
model = Comment
fields = ['content','blog_post']
HTML
<form method='POST' action='.'> {% csrf_token %}
{{ form.as_p }}
<button type='submit'>Send</button>
</form>
models.py
class Comment(models.Model):
content = models.TextField(max_length=300)
user = models.ForeignKey(User, null=True, on_delete=models.SET_NULL, default=1)
blog_post = models.ForeignKey(BlogPost, null=True, on_delete=models.CASCADE)
timestamp = models.DateTimeField(auto_now_add=True)
def __unicode__(self):
return str(self.user.username)
def __str__(self):
return str(self.user.username)

Creating a Post but got an IntegrityError

I'm trying to create a post and update my list of posts. I currently get this error IntegrityError at /posts/create/ NOT NULL constraint failed: posts_post.publish Not sure what the error means and how to fix it. The files below are my posts/views.py, forms.py, post_forms.py and models
def posts_create(request):
# return HttpResponse("<h1> Create a posts. </h1>")
form = PostForm(request.POST or None)
if form.is_valid():
instance = form.save(commit=False)
instance.user = request.user
instance.save()
context = {
"form": form
}
# if request.method == "POST":
# print("This is the content: ", request.POST.get("content"))
return render(request, "post_form.html", context)
def posts_detail(request, id):
instance = get_object_or_404(Post, id=id)
context = {
"user": instance.user,
"instance": instance
}
return render(request, "posts_detail.html", context)
def posts_list(request):
# return HttpResponse("<h1> List a posts. </h1>")
# TODO: Privacy stuff
queryset = Post.objects.all()
context = {
"object_list": queryset,
"user": "username"
}
return render(request, "post.html", context)
Models for post:
user = models.ForeignKey(settings.AUTH_USER_MODEL,
on_delete=models.CASCADE)
status = models.CharField(max_length=6, choices=Status, default=POST)
content = models.TextField()
publish = models.DateField(auto_now=False, auto_now_add=False)
updated = models.DateTimeField(auto_now=True, auto_now_add=False)
timestamp = models.DateTimeField(auto_now=False, auto_now_add=True)
privacy = models.IntegerField(choices=Privacy, default=PUBLIC)
unlisted = models.BooleanField(default=False)
This is the post_form.html
<html>
<body>
<h3>Create Post</h3>
<form method="POST" action="">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Share" />
</form>
</body>
</html>
This is the respective forms.py
from django import forms
from .models import Post
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = [
"content"
]
from datetime import datetime
def posts_create(request):
# return HttpResponse("<h1> Create a posts. </h1>")
form = PostForm(request.POST or None)
if form.is_valid():
instance = form.save(commit=False)
instance.user = request.user
instance.publish = datetime.now()
instance.save()
context = {
"form": form
}
# if request.method == "POST":
# print("This is the content: ", request.POST.get("content"))
return render(request, "post_form.html", context)
do this in your view. import the first line then change your view