Why the ValueError Exception is raised? - python

models.py
class Post(models.Model):
message = models.CharField(max_length=2000)
topic = models.ForeignKey(Topic, related_name="posts", null=True,
blank=True, on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
created_by = models.ForeignKey(User, null=True, blank=True,
on_delete=models.CASCADE)
like = models.IntegerField(default=0)
views = models.IntegerField(default=0)
class ReplyPost(models.Model):
reply = models.CharField(max_length=2000)
post = models.ForeignKey(Post, related_name="reply", null=True,
blank=True, on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
created_by = models.ForeignKey(User, null=True, blank=True,
on_delete=models.CASCADE)
views.py
def reply_post(request, pk):
post = get_object_or_404(Post, pk=pk)
if request.method == "POST":
form = ReplyPostForm(request.POST)
if form.is_valid():
replypost = form.save(commit = False)
replypost.reply = form.cleaned_data.get("reply")
replypost.post = post
replypost.created_by = request.user
replypost.save()
return redirect("post", post.id)
else:
form = ReplyPostForm()
args = {
'form': form,
'post':post
}
return render(request, 'home/replypost.html', args)
urls.py
urlpatterns = [
#.....
url(r'^home/questions/(?P<pk>\d+)/reply/$', views.reply_post,
name="replypost"),
url(r'^home/questions/(?P<pk>\d+)/$', views.post, name="post"),
]
forms.py
class ReplyPostForm(ModelForm):
reply = forms.CharField(widget = forms.Textarea)
class Meta:
model = ReplyPost
fields = ('reply',)
The error:
ValueError. The view 'WebBoard.views.reply_post' didn't return an
'HttpResponse' object. It returned 'None' instead.
I can't not understand what is wrong with the code..Please update me if the code above is not sufficient to understand.

Your code needs to return an HttpResponse instance for the case when a request is POST but the form is not valid.
Looking at your code, try to move the last lines back one indentation level; that way everything that isn't a POST with a valid form will fall into that last return statement.
def reply_post(request, pk):
post = ...
if request.method == "POST":
form = ReplyPostForm(request.POST)
if form.is_valid():
...
return redirect("post", post.id)
else:
form = ReplyPostForm()
args = {
'form': form,
'post': post,
}
return render(request, 'home/replypost.html', args)

Related

I want create comment section that can only logged in users can use but I have this problem

I get an Error:
cannot unpack non-iterable bool object
profile = Profile.objects.get(Profile.user == request.user)
This is my models.py in account app and blog app:
class Profile(models.Model):
STATUS_CHOICES = (
('manager', 'مدیر'),
('developer', 'توسعه‌دهنده'),
('designer', 'طراح پروژه'),
)
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
bio = models.CharField(max_length=50, blank=True)
task = models.CharField(choices=STATUS_CHOICES, max_length=20, blank=True, null=True, default=None)
date_of_birth = models.DateField(blank=True, null=True)
photo = models.ImageField(upload_to='users/photos/%Y/%m/%d/', blank=True)
def __str__(self):
return f'{self.user.get_full_name()}'
class Comment(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='comments')
profile = models.ForeignKey(Profile, on_delete=models.CASCADE, related_name='user_comments')
body = models.TextField()
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
active = models.BooleanField(default=False)
and this is my views.py for comments:
def post_detail(request, year, month, day, slug):
post = get_object_or_404(Post, slug=slug, status='published', publish__year=year, publish__month=month, publish__day=day)
tags = Tag.objects.all()
tagsList = []
for tag in post.tags.get_queryset():
tagsList.append(tag.name)
profile = Profile.objects.get(Profile.user == request.user)
comments = post.comments.filter(active=True)
new_comment = None
if request.method == 'POST':
comment_form = CommentForm(data=request.POST)
if comment_form.is_valid():
new_comment = comment_form.save(commit=False)
new_comment.profile = profile
new_comment.post = post
new_comment.save()
return redirect('post_detail', slug=post.slug)
else:
comment_form = CommentForm()
post_tags_ids = post.tags.values_list('id', flat=True)
similar_posts = Post.published.filter(tags__in=post_tags_ids).exclude(id=post.id)
similar_posts = similar_posts.annotate(same_tags=Count('tags')).order_by('-same_tags', '-publish')[:3]
return render(request, 'blog/post/detail.html', {'post': post, 'comments': comments, 'new_comment': new_comment, 'comment_form': comment_form, 'similar_posts': similar_posts, 'tagsList': tagsList, 'tags': tags})
Is there any solution for this problem?
Assuming you need to get only single profile instance i.e. current logged in user's profile so you can either use:
profile = Profile.objects.get(user=request.user)
or:
get_object_or_404(Profile, user=request.user)
To limit the view to be accessed by only logged in users, use #login_required decorator so:
#login_required(login_url='/accounts/login/') # you can give any login_url you want.
def post_detail(request, year, month, day, slug):
#...

Allow the user to input only a part of django model creaton form (add to form after user submitted it)

How I can add data to form that user submitted ? I want the user to fill in the "name" and "done" in the form and automatically add "user" (creator) and "board"
code:
#views.py
#login_required(login_url='loginPage')
def taskAdd(request, pk):
board = Board.objects.filter(user=request.user).get(pk=pk)
form = AddTaskForm()
if request.method == "POST":
form = AddTaskForm(request.POST)
if form.is_valid():
form.initial['user'] = request.user
form.initial['board'] = board
# that doesn't seem to work....
form.save()
return redirect('insideBoard', pk)
context = {'form': form}
return render(request, 'tasks/taskAdd.html', context)
#forms.py
class AddTaskForm(ModelForm):
class Meta:
model = Task
fields = "__all__"
exclude = ('user', 'board',)
#models.py
class Board(models.Model):
title = models.CharField(max_length=50, null=True)
user = models.ForeignKey(User, null=True, on_delete=models.CASCADE)
def __str__(self):
return self.title
class Task(models.Model):
title = models.CharField(max_length=200, null=True)
done = models.BooleanField(default=False, null=True)
created_at = models.DateTimeField(auto_now_add=True, null=True)
user = models.ForeignKey(User, null=True, on_delete=models.CASCADE)
board = models.ForeignKey(Board, null=True, on_delete=models.CASCADE)
def __str__(self):
return self.title
You can edit the instance wrapped in the form:
from django.shortcuts import get_object_or_404
#login_required(login_url='loginPage')
def taskAdd(request, pk):
board = get_object_or_404(Board, user=request.user, pk=pk)
form = AddTaskForm()
if request.method == 'POST':
form = AddTaskForm(request.POST)
if form.is_valid():
form.instance.user = request.user
form.instance.board_id = pk
form.save()
return redirect('insideBoard', pk)
context = {'form': form}
return render(request, 'tasks/taskAdd.html', context)
Note: It is often better to use get_object_or_404(…) [Django-doc],
then to use .get(…) [Django-doc] directly. In case the object does not exists,
for example because the user altered the URL themselves, the get_object_or_404(…) will result in returning a HTTP 404 Not Found response, whereas using
.get(…) will result in a HTTP 500 Server Error.

IntegrityError at /create/ NOT NULL constraint failed: main_post.author_id

When i try to create an new post with http://localhost:8000/create/ , i get this error. I couldn't find the solution thought they seem similar. I follows some blog tutorial
I can't paste the settings.py here because there to much code in the post but i think the settings.py is fine btw
My models.py (* i deleted some code maynot involve)
User = get_user_model()
class Author(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
profile_picture = models.ImageField()
def __str__(self):
return self.user.username
class Post(models.Model):
title = models.CharField(max_length=100)
overview = models.TextField()
detail = models.TextField()
timestamp = models.DateTimeField(auto_now_add=True)
content = RichTextUploadingField(config_name='post_ckeditor')
comment_count = models.IntegerField(default=0)
view_count = models.IntegerField(default=0)
author = models.ForeignKey(Author, on_delete=models.CASCADE)
thumbnail = models.ImageField()
categories = models.ManyToManyField(Category)
featured = models.BooleanField()
previous_post = models.ForeignKey('self', related_name='previous', on_delete=models.SET_NULL, blank = True, null = True)
next_post = models.ForeignKey('self', related_name='next', on_delete=models.SET_NULL, blank = True, null = True)
My views.py
def get_author(user):
qs = Author.objects.filter(user=user)
if qs.exists():
return qs[0]
return None
pass
def post_create(request):
form = PostForm(request.POST or None, request.FILES or None)
author= get_author(request.user)
if request.method == 'POST':
if form.is_valid():
form.instance.author = author
form.save()
return redirect(reverse('post-detail', kwargs={
'id': form.instance.id
}))
context = {
'form': form
}
return render(request, 'post_create.html', context)
pass
My forms.py
from django import forms
from .models import Post, Comment
class PostForm(forms.ModelForm):
content = forms.CharField
class Meta:
model = Post
fields = ('title', 'overview', 'content', 'thumbnail', 'categories', 'featured', 'previous_post', 'next_post')
class CommentForm(forms.ModelForm):
content = forms.CharField(widget=forms.Textarea(attrs={
'class':'form-control',
'placeholder':'Type your comment',
'id':'usercomment',
'rows':4
}))
class Meta:
model = Comment
fields = ('content', )
Please help !
If you are trying to save request.user in the author field you don't need to write the extra methods just do like this.
if request.method == 'POST':
if form.is_valid():
post =form.save(commit=False)
post.author = request.user
post.save()
return redirect(reverse('post-detail', kwargs={'id': post.id }))
Whenever there is a change in model fields or new model added or removed, you should migrate. And pass a default object to foreign key if not null.

Checking record owner before editing in Django

I’m learning Django, but it’s hanging on such a seemingly simple moment. I need to check and allow the user to edit only his posts, and if he clicks the link for editing someone else’s - render a specific page.
I can not form a condition for user verification, please help:
views.py
#login_required
def blogs_edit_text_post(request, post_id):
post_form = PostForm(instance=TextPost.objects.get(id=post_id))
owner = TextPost.objects.get(pk=1)
if request.user == owner:
if request.method == "POST":
post_form = PostForm(request.POST, instance=TextPost.objects.get(id=post_id))
if post_form.is_valid():
post = post_form.save()
return redirect(blogs_blog)
return render(request, 'blogs/edit_text_post.html', {
'post_form': post_form
})
else:
return render(request, 'blogs/error_page.html', {})
models.py
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile_user_id')
blog_title = models.CharField(max_length=300, verbose_name='Название блога')
blog_description = models.TextField(max_length=500, verbose_name='Пара слов о себе', blank=True)
profile_pic = models.ImageField(default='nophoto.jpg', upload_to='user_pics/', blank=True, verbose_name='Аватар')
class TextPost(models.Model):
author = models.ForeignKey(Profile, on_delete=models.CASCADE)
title = models.CharField(max_length=300, verbose_name='Заголовок')
post = models.TextField(max_length=500, verbose_name='Текст поста', blank=False)
created_date = models.DateTimeField(default=timezone.now)
published_date = models.DateTimeField(blank=True, null=True)
urls.py
path('blogs/blog/', views.blogs_blog, name='blogs-blog')
Please note these points:
Don't relate TextPost to Profile model, relate it directly to the User model. It will be more easy for your project.
Always use "related_name" in OneToOneField or ForeignKeyField.
Always use context (or another named variable) to pass variable in template. in big projects, you will have to pass many variables.
models.py
class TextPost(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='user_name') # User, not Profiel, related_name added
title = models.CharField(max_length=300, verbose_name='Заголовок')
post = models.TextField(max_length=500, verbose_name='Текст поста', blank=False)
created_date = models.DateTimeField(default=timezone.now)
published_date = models.DateTimeField(blank=True, null=True)
views.py
#login_required
def blogs_edit_text_post(request, post_id):
post = TextPost.objects.get(id=post_id)
if post.author == request.user: # post.author.user == request.user if it's related to Profile
if request.method == "POST":
post_form = PostForm(request.POST, instance=TextPost.objects.get(id=post_id))
if post_form.is_valid():
post = post_form.save()
return redirect(blogs_blog)
else:
post_form = PostForm(instance=TextPost.objects.get(id=post_id))
context = {
'post_form': post_form
}
return render(request, 'blogs/edit_text_post.html', context)
else:
return render(request, 'blogs/error_page.html', {})

Django email notification

I want to ask for guidance on how to do this Django email notification
https://docs.djangoproject.com/en/1.8/topics/email/#send-mail
I have a basic task form and option to assign it to someone, when the form is saved I want to send an email notification to the assigned user.
Job/task models.py
class Job(models.Model):
completed = models.BooleanField(default=False)
task_name = models.CharField(max_length=80, blank=False)
description = models.CharField(max_length=80, blank=False)
is_important = models.BooleanField(default=False)
completion_date = models.DateField(blank=True, null=True)
assign_to = models.ForeignKey(User, blank=True, null=True)
comments = models.TextField(blank=True)
def __unicode__(self):
return self.task_name
Job/task view.py
#login_required
def job(request):
if request.method == 'POST':
form = JobForm(request.POST)
if form.is_valid():
job_record = form.save(commit=False)
job_record = form.save(commit=False)
job_record.user = request.user
job_record.save()
return redirect('jobs:list')
else:
form = JobForm()
return render(request, 'jobs/form.html', {'form': form})
You are nearly there:
#login_required
def job(request):
form = JobForm(request.POST or None)
if form.is_valid():
job_record = form.save(commit=False)
job_record.assign_to = request.user
job_record.save()
send_mail(
subject="subject",
message="message",
from_email="from#myserver.com",
recipient_list=[job_record.assign_to.email]
)
return redirect('jobs:list')
return render(request, 'jobs/form.html', {'form': form})

Categories