I want to save my form in database, but save() doesn't work. When I do this, error wasn't showing. At the start, I think problem was in database, but it isn't
views.py
def comments(request):
comments = Comment.objects.all()
form = CommentForm()
context = {"comments": comments, "form": form}
if request.method == "POST":
form = CommentForm(request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.avtor = request.user
comment.save()
return HttpResponseRedirect(reverse('comment'))
else:
context["form"] = form
return render(request, "home/comments.html", context)
else:
return render(request, "home/comments.html", context)
And models. So, I think problem yet in views.py. I bad know how function save() is working.
models.py
class Comment(models.Model):
Text = models.TextField(verbose_name='Text')
date = models.DateTimeField(default=timezone.now, verbose_name='date')
avtor = models.ForeignKey(User, verbose_name='avtor', on_delete=models.CASCADE)
def __str__(self):
return 'Comment {} at {}'.format(self.avtor, self.date)
class Meta:
ordering = ["-id"]
forms.py
class CommentForm(ModelForm):
class Meta:
model = Comment
fields = ("Text",)
At the last, I want to save avtor, text and Date. Help me please.
<div class="container" style="min-height: 520px;">
<form class="text-light formGroupComm" action="/" method="post">
{% csrf_token %}
{{ form }}
<br>
<button style="width: 6%!important;" class="btn btn-warning mb-5 mt-3 mx-auto" type="submit">submit</button>
</form>
<div class="comments text-dark">
{% for comentPost in comments %}
<div class="commentItem bg-warning my-3" style="border-radius: 40px; padding: 20px;">
<div style="border-bottom: 3px solid black;" class="comTitle mx-3 my-3">{{ comentPost.avtor }}</div>
<div style="" class="comText mx-5">{{ comentPost.Text }}</div>
<div style="" class="comDate mx-3 my-5">{{ comentPost.date|date:"F d, Время: h:i" }}</div>
</div>
{% endfor %}
</div>
</div>
The action attribute specifies where to send the form-data when a form is submitted (https://www.w3schools.com/tags/att_form_action.asp).
So when you put the "/" in there, the form will send the data to the home page (represented by / in html). This means that your data doesn't get to the POST section of your def comments(request) method. When the method is not called, the logical outcome is thus that there isn't a new comment added.
This is the correct code:
<div class="container" style="min-height: 520px;">
<form class="text-light formGroupComm" method="post">
{% csrf_token %}
{{ form }}
<br>
<button style="width: 6%!important;" class="btn btn-warning mb-5 mt-3 mx-auto" type="submit">submit</button>
</form>
<div class="comments text-dark">
{% for comentPost in comments %}
<div class="commentItem bg-warning my-3" style="border-radius: 40px; padding: 20px;">
<div style="border-bottom: 3px solid black;" class="comTitle mx-3 my-3">{{ comentPost.avtor }}</div>
<div style="" class="comText mx-5">{{ comentPost.Text }}</div>
<div style="" class="comDate mx-3 my-5">{{ comentPost.date|date:"F d, Время: h:i" }}</div>
</div>
{% endfor %}
</div>
</div>
Related
show Reply button should be specific for different comments . When I press show reply button it opens different replies which dosen't belong to that comment.
views.py
from django.shortcuts import render, HttpResponse, redirect,reverse
from fitness.models import Post, BlogComment
from django.contrib.auth.models import User
from fitness.templatetags import extras
# Create your views here.
def fitness(request):
everypost=Post.objects.all()
context={"everypost":everypost}
return render(request, "fitness/fit.html", context)
def blogfit(request, slug):
post=Post.objects.filter(slug=slug).first()
comments= BlogComment.objects.filter(post=post, parent=None)
replies= BlogComment.objects.filter(post=post).exclude(parent=None)
replyDict={}
for reply in replies:
if reply.parent.sno not in replyDict.keys():
replyDict[reply.parent.sno]=[reply]
else:
replyDict[reply.parent.sno].append(reply)
context={"post":post, 'comments': comments, 'user': request.user, 'replyDict': replyDict}
return render(request, "fitness/blogfit.html", context)
def postComment(request):
if request.method == "POST":
comment=request.POST.get('comment')
user=request.user
postSno =request.POST.get('postSno')
post= Post.objects.get(sno=postSno)
parentSno= request.POST.get('parentSno')
if parentSno=="":
comment=BlogComment(comment= comment, user=user, post=post)
comment.save()
else:
parent= BlogComment.objects.get(sno=parentSno)
comment=BlogComment(comment= comment, user=user, post=post , parent=parent)
comment.save()
return HttpResponse(reverse('fitness:fitness'))
Models.py
from django.db import models
from ckeditor.fields import RichTextField
from django.contrib.auth.models import User
from django.utils.timezone import now
# Create your models here.
class Post(models.Model):
sno=models.AutoField(primary_key=True)
title=models.CharField(max_length=255)
author=models.CharField(max_length=14)
slug=models.CharField(max_length=130)
timeStamp=models.DateTimeField(blank=True)
content=RichTextField(blank=True, null=True)
def __str__(self):
return self.title + " by " + self.author
class BlogComment(models.Model):
sno= models.AutoField(primary_key=True)
comment=models.TextField()
user=models.ForeignKey(User, on_delete=models.CASCADE)
post=models.ForeignKey(Post, on_delete=models.CASCADE)
parent=models.ForeignKey('self',on_delete=models.CASCADE, null=True )
timestamp= models.DateTimeField(default=now)
def __str__(self):
return self.comment[0:13] + "..." + "by" + " " + self.user.username
Html page
<h2 class="blog-post-title">{{post.title}}</h2>
<p class="blog-post-meta">{{post.timeStamp}} by {{post.author}}</p>
<p>{{post.content|safe}}</p>
<hr>
</div>
</div>
</div>
{% if user.is_authenticated %}
<form action="{% url 'fitness:postComment' %}" method="post">
{% csrf_token %}
<div class="form-group">
<label for="exampleInputEmail1">Post Comment </label>
<input type="text" class="form-control" name="comment" placeholder="Enter comment here">
</div>
<input type="hidden" name="postSno" value="{{post.sno}}">
<input type="hidden" name="parentSno" value="">
<button type="submit" class="btn btn-primary">Submit</button>
</form>
{% else %}
Please login to post a comment
{% endif %}
</div>
{% for comment in comments %}
<div class="row my-3">
<div class="col-md-1 ">
<img class="rounded mx-auto d-block w-100 border border-dark p-2" src="http://i9.photobucket.com/albums/a88/creaticode/avatar_1_zps8e1c80cd.jpg" alt="user">
</div>
<div class="col-md-11 ">
<h6 class="comment-name by-author"> {{comment.user.username}} </h6> <span class="badge badge-secondary "></span>
<b> {{comment.comment}} </b> <span class="badge badge-secondary "></span><br>
<button class="btn btn-sm btn-primary" type="button" data-toggle="collapse" data-target="#replyBox{{comment.sno}}" aria-expanded="false" aria-controls="replyBox{{comment.sno}}">
Reply
</button>
<button class="btn btn-sm btn-primary" type="button" onClick="myFunction()" id= "show-hide" >
Show Replies
</button>
<div class="reply mx-0" >
<div class="collapse" id="replyBox{{comment.sno}}">
<div class="card card-body my-2" >
<form action="{% url 'fitness:postComment' %}" method="post">
{% csrf_token %}
<div class="form-group" >
<label for="comment">Post a reply </label>
<input type="text" class="form-control" name="comment" placeholder="Enter comment here">
<input type="hidden" name="parentSno" value="{{comment.sno}}">
</div>
<input type="hidden" name="postSno" value="{{post.sno}}">
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
</div>
<div class="replies bg-danger my-2" id = "replies" >
{% for reply in replyDict|get_val:comment.sno %}
<div class="replies">{{reply}}</div>
<br>
{% endfor %}
</div>
</div>
</div>
</div>
{% endfor %}
<!-- Contenedor Principal -->
<script>
function myFunction(){
var x = document.getElementById("replies");
if(x.style.display === "none"){
x.style.display = "block";
}
else{
x.style.display = "none";
}
}
</script>
I think it is a logical error. Can someone help me to find out this error? While everything is working fine but my reply button not working fine.
Change in models.py. update parent in BlogComment (add related_name)
parent=models.ForeignKey('self', on_delete=models.CASCADE, null=True, related_name='replies' )
Change in views.py where you are getting comments
comments= BlogComment.objects.filter(post=post, parent=None).prefetch_related('replies')
You don't need separate query for replies.
In html (Only for replies. Please change as per your requirement)
{% for comment in comments %}
{% for reply in comment.replies.all %}
{{ reply.comment }}
{% endfor %}
{% endfor %}
This will work. Remember related_name=replies
(Sorry for unclear answer. It's closing time in office and I am leaving. Good luck)
I am trying to use a ModelForm to save objects to the database. I have also added an ImageField. Through the admin panel, I am easily able to add objects with an image but every time I submit the ModelForm with the same image it doesn't get saved and returns an error saying "This field is required" (screenshot and code attached).
How do I fix this?
Here's a screenshot of the error:
The models file:
from django.db import models
from django.conf import settings
class Book(models.Model):
rel_user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, verbose_name="Posted By")
image = models.ImageField(verbose_name="Image", upload_to="static/Books/img")
title = models.CharField(max_length=256, verbose_name="Title")
description = models.TextField(verbose_name="Description")
price = models.IntegerField(verbose_name="Price")
state = models.CharField(max_length=256, verbose_name="State")
city = models.CharField(max_length=256, verbose_name="City")
neighbourhood = models.CharField(max_length=256, verbose_name="Neighbourhood")
phone = models.IntegerField(verbose_name="Phone Number")
def __str__(self):
return self.title + f" ({self.rel_user.username})"
The forms file:
from django.forms import ModelForm
from Books.models import Book
class BookForm(ModelForm):
class Meta:
model = Book
fields = ['image', 'title', 'description', 'price', 'state', 'city', 'neighbourhood', 'phone']
The views file:
from django.shortcuts import render, redirect
from Books.forms import BookForm
from django.contrib import messages
from Books.models import Book
def sell(request):
if request.method == "GET":
form = BookForm()
else:
form = BookForm(request.POST)
form.instance.rel_user = request.user
if form.is_valid():
form.save()
messages.success(request, "Successfully added!")
return redirect('sell')
else:
messages.error(request, "Please fill in all the fields.")
return render(request, 'Books/sell.html', {"form": form})
The HTML code:
<div class="container" style="padding: 2%">
<div class="row">
<div class="col-md-4 col-sm-4 col-xs-12"></div>
<div class="col-md-4 col-sm-4 col-xs-12" style="background-color: rgba(256, 256, 256, 0.8);">
{% if messages %}
{% for message in messages %}
<div class="alert alert-primary" role="alert" style="margin-top: 2%;">
{{ message }}
</div>
{% endfor %}
{% endif %}
<form method="POST" action="{% url 'sell' %}">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">Sell A Book</legend>
{{ form|crispy }}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">Submit
</button>
</div>
</form>
</div>
<div class="col-md-4 col-sm-4 col-xs-12"></div>
</div>
</div>
from Books.forms import BookForm
from django.contrib import messages
from Books.models import Book
def sell(request):
if request.method == "GET":
form = BookForm()
else:
form = BookForm(request.POST,request.FILES)
form.instance.rel_user = request.user
if form.is_valid():
form.save()
messages.success(request, "Successfully added!")
return redirect('sell')
else:
messages.error(request, "Please fill in all the fields.")
return render(request, 'Books/sell.html', {"form": form})```
<div class="container" style="padding: 2%">
<div class="row">
<div class="col-md-4 col-sm-4 col-xs-12"></div>
<div class="col-md-4 col-sm-4 col-xs-12" style="background-color:rgba(256, 256, 256, 0.8);">
{% if messages %}
{% for message in messages %}
<div class="alert alert-primary" role="alert" style="margin-top: 2%;">
{{ message }}
</div>
{% endfor %}
{% endif %}
<form method="POST" action="{% url 'sell' %}"enctype="multipart/form-data">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">Sell A Book</legend>
{{ form|crispy }}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">Submit
</button>
</div>
</form>
</div>
<div class="col-md-4 col-sm-4 col-xs-12"></div>
</div>
</div>
I am adding a functionality in my website, where users can like posts.
I have successfully done this, however I am having trouble adding one functionality.
This is text within a button depending on whether a post is liked or not.
Right now the button stays the same no matter if the post is liked or not.
models.py
class Post(models.Model):
file = models.ImageField(upload_to='images/')
summary = models.TextField(max_length=600)
pub_date = models.DateTimeField(auto_now=True)
user = models.ForeignKey(User, on_delete=models.CASCADE)
likes = models.ManyToManyField(User, through='Like', related_name='likes')
def __str__(self):
return self.user.username
def pub_date_pretty(self):
return self.pub_date.strftime('%b %e %Y')
def summary_pretty(self):
return self.summary[:50]
#property
def total_likes(self):
return self.likes.count()
class Like(models.Model):
status = models.BooleanField()
post = models.ForeignKey(Post, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
views.py
def likepost(request, post_id):
if request.method == 'POST':
post = get_object_or_404(Post, pk=post_id)
user = request.user
if post.likes.filter(id=user.id).exists():
post.likes.remove(user)
return redirect('home')
else:
like = Like()
like.post = post
like.user = user
like.status = True
like.save()
post.likes.add(user)
return redirect('home')
my template:
{% if post.likes.status == True %}
<button class="btn btn-primary btn-lg btn-block"><span class="oi oi-caret-top"></span> Unlike {{ post.total_likes }} </button>
{% else %}
<button class="btn btn-primary btn-lg btn-block"><span class="oi oi-caret-top"></span> Like {{ post.total_likes }} </button>
{% endif %}
EDIT - HOME VIEW:
#login_required(login_url="/login")
def home(request):
posts = Post.objects.all()
return render(request, 'posts/home.html', {'posts': posts})
EDIT 2:
{% extends 'accounts/base.html' %}
{% block content %}
{% load static %}
{% for post in posts.all %}
<div class="container pl-5">
<div class="row pt-3">
<img src="{% static 'grey.jpg' %}" width="600px" height="60px">
<div class="pt-3 pl-5" style="position: absolute;"> <b> {{ post.user.username }} </b> </div>
</div>
<br>
<div class="card" style="width: 600px; bottom: 24px; right: 15px;">
<img src="{{ post.file.url }}" width="599px">
</div>
<br>
<div class="card" style="width: 600px; bottom: 50px; right: 15px;"> <img src="{% static 'grey.jpg' %}" width="600px" height="150px"> </div>
<div class="col-6" style="bottom:145px; left: 5px;">
<div style="position: absolute;"> <b> {{ post.user.username }} </b> {{ post.summary_pretty }}</div>
</div>
{% for like in post.likes.all %}
{{like.username}}
{% endfor %}
{% if like.status %}
<button class="btn btn-primary btn-lg btn-block"><span class="oi oi-caret-top"></span> Unlike {{ post.total_likes }} </button>
{% else %}
<button class="btn btn-primary btn-lg btn-block"><span class="oi oi-caret-top"></span> Like {{ post.total_likes }} </button>
{% endif %}
<form id="likepost{{ post.id }}" method="POST" action="{% url 'likepost' post.id %}">
{% csrf_token%}
<input type="hidden">
</form>
</div>
<br>
<br>
<br>
{% endfor %}
{% endblock %}
In your model you have defined likes as a ManyToManyField field:
class Post(models.Model):
likes = models.ManyToManyField(User, through='Like', related_name='likes')
But in your template you are trying to get a single boolean value from many likes:
{% if post.likes.status == True %}
post.likes will return multiple objects. You need to instead get the like based on the user.
EDIT:
One way you could get the like status is by doing the following in your view:
context['like'] = Like.objects.get(post=post, user=request.user)
Then in your template:
{% if like.status == True %}
i am using two models named Posts and PostPicture and posts model have multiple text fields whereas PostPicture model have one image field and one posts foreignkey field and i am using formset_factory on image field in views to let the user upload multiple images with the post, the problem is that whenever i try to update the post it updates the text fields of Posts model but it doesn't update the images i upload with it...there's something wrong with my update view and i can't figure out
Here's my views.py for update_post
def update_post(request, post_id):
ImageFormSet = modelformset_factory(PostPicture,
form=AddPictures, extra=5, min_num=1,
can_delete=True)
post_form = get_object_or_404(Posts, pk=post_id)
pics_form = PostPicture.objects.filter(post=post_id)
if request.method == "POST":
form = AddFile(request.POST, instance=post_form)
formset = ImageFormSet(request.POST or None, queryset=pics_form)
if form.is_valid() and formset.is_valid():
posting = form.save(commit=False)
posting.user = request.user
posting.save()
for form in formset.cleaned_data:
image = form['image']
photo = PostPicture(post=posting, image=image)
photo.save()
messages.success(request, 'Post updated Successfully!')
return render(request, 'vehicles_app/addfile.html', {
'form': form,
'pics_form': pics_form,
'formset': formset,
'post_form': post_form,
'post_id': post_id,
})
else:
messages.success(request, 'Post not updated Successfully!')
print(form.errors, formset.errors)
else:
form = AddFile(instance=post_form)
formset =
ImageFormSet(queryset=PostPicture.objects.filter(post=post_id))
return render(request, 'vehicles_app/update_post.html', {'form':
form, 'formset': formset, 'pics_form': pics_form,
'post_form':post_form,'post_id': post_id})
here's my update_post.html
<form id="post_form" method="post" action="{% url
'vehicles_app:update_post' post_id %}"
enctype="multipart/form-data">
{% csrf_token %}
<div class="row">
<div class="form-group">
<div style="float: left; width: 50%">
<label for="title">Ad Title</label>
</div>
<div class="title" style="float: right; width: 45%">
<input type="text" name="title" placeholder="Type Here"
value='{{ form.initial.title }}' required>
</div>
</div>
<br>
<div class="form-group">
<div style="float: left; width: 50%">
<label for="city">City</label>
</div>
<div class="form-group">
<div style="float: left; width: 50%">
<label for="mileage">Mileage</label>
</div>
<div class=mileage style="float: right; width: 45%">
<input type="text" name="mileage" placeholder="ie:50000"
value='{{ form.initial.mileage }}' required>
</div>
</div>
</div>
<br>
<div class="form-group">
<div style="float: left; width: 50%">
<label for="details">Type details here</label>
</div>
<div class="details" style="float: right; width: 45%">
<textarea name="details" rows="9" cols="45" value='{{
form.initial.details }}' required></textarea>
</div>
</div>
<br>
{{ formset.management_form }}
{% if formset %}
{% for form in formset %}
{% if form %}
<table class="display" cellspacing="1" width="100%">
<tr>
<td>{{ form }}</td>
</tr>
</table>
{% endif %}
{% endfor %}
{% endif %}
<input type="submit" name="submit" value="Update"
class="btn btn-info" id="post_btn">
<input type=button class="btn btn-default" value="Cancel"
onClick="javascript:history.go(-1);">
</form>
i am using two models named Posts and PostPicture and posts model have multiple text fields whereas PostPicture model have one image field and one posts foreignkey field and i am using formset_factory on image field in views to let the user upload multiple images with the post, the problem is that whenever i try to update the post it updates the text fields of Posts model but it doesn't update the images i upload with it...there's something wrong with my update view and i can't figure out
Here's my views.py for update_post
def update_post(request, post_id):
ImageFormSet = modelformset_factory(PostPicture,
form=AddPictures, extra=5, min_num=1,
can_delete=True)
post_form = get_object_or_404(Posts, pk=post_id)
pics_form = PostPicture.objects.filter(post=post_id)
if request.method == "POST":
form = AddFile(request.POST, instance=post_form)
formset = ImageFormSet(request.POST or None, queryset=pics_form)
if form.is_valid() and formset.is_valid():
posting = form.save(commit=False)
posting.user = request.user
posting.save()
for form in formset.cleaned_data:
image = form['image']
photo = PostPicture(post=posting, image=image)
photo.save()
messages.success(request, 'Post updated Successfully!')
return render(request, 'vehicles_app/addfile.html', {
'form': form,
'pics_form': pics_form,
'formset': formset,
'post_form': post_form,
'post_id': post_id,
})
else:
messages.success(request, 'Post not updated Successfully!')
print(form.errors, formset.errors)
else:
form = AddFile(instance=post_form)
formset =
ImageFormSet(queryset=PostPicture.objects.filter(post=post_id))
return render(request, 'vehicles_app/update_post.html', {'form':
form, 'formset': formset, 'pics_form': pics_form,
'post_form':post_form,'post_id': post_id})
here's my update_post.html
<form id="post_form" method="post" action="{% url
'vehicles_app:update_post' post_id %}"
enctype="multipart/form-data">
{% csrf_token %}
<div class="row">
<div class="form-group">
<div style="float: left; width: 50%">
<label for="title">Ad Title</label>
</div>
<div class="title" style="float: right; width: 45%">
<input type="text" name="title" placeholder="Type Here"
value='{{ form.initial.title }}' required>
</div>
</div>
<br>
<div class="form-group">
<div style="float: left; width: 50%">
<label for="city">City</label>
</div>
<div class="form-group">
<div style="float: left; width: 50%">
<label for="mileage">Mileage</label>
</div>
<div class=mileage style="float: right; width: 45%">
<input type="text" name="mileage" placeholder="ie:50000"
value='{{ form.initial.mileage }}' required>
</div>
</div>
</div>
<br>
<div class="form-group">
<div style="float: left; width: 50%">
<label for="details">Type details here</label>
</div>
<div class="details" style="float: right; width: 45%">
<textarea name="details" rows="9" cols="45" value='{{
form.initial.details }}' required></textarea>
</div>
</div>
<br>
{{ formset.management_form }}
{% if formset %}
{% for form in formset %}
{% if form %}
<table class="display" cellspacing="1" width="100%">
<tr>
<td>{{ form }}</td>
</tr>
</table>
{% endif %}
{% endfor %}
{% endif %}
<input type="submit" name="submit" value="Update"
class="btn btn-info" id="post_btn">
<input type=button class="btn btn-default" value="Cancel"
onClick="javascript:history.go(-1);">
</form>