I am following the guide to create comment given by Django central, https://djangocentral.com/creating-comments-system-with-django/ and it is working. However I am using the {{ form.as_p }} Which will give 3 fields, as the form say, with name, email and the body. But i wanted to have predefined name, which would be your username you are logged inn with and the email attached to that account. How would i go ahead to create that?
forms.py
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ['name', 'email', 'body']
models.py
class Comment(models.Model):
post = models.ForeignKey(Post, related_name='comments', on_delete=models.CASCADE)
name = models.CharField(max_length=255)
email = models.EmailField()
body = models.TextField()
date_added = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ['-date_added']
def __str__(self):
return self.name
views.py
def post_detail(request, category_slug, slug, status=Post.ACTIVE):
post = get_object_or_404(Post, slug=slug)
if request.method == 'POST':
form = CommentForm(request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.post = post
comment.save()
return redirect('post_detail', category_slug=category_slug, slug=slug)
else:
form = CommentForm()
return render(request, 'blog/post_detail.html', {'post': post, 'form': form})
in the html template
{% if user.is_authenticated %}
<h2 class="subtitle is-4">Comments</h2>
<form method="post" class="mb-6">
{% csrf_token %}
{{ form.as_p }}
<div class="field">
<div class="control">
<button class="button is-success">Submit comment</button>
</div>
</div>
</form>
{% endif %}
If you want to pre-set the username and email fields, you can use the initial form parameters like this:
views.py
def post_detail(request, category_slug, slug, status=Post.ACTIVE):
post = get_object_or_404(Post, slug=slug)
if request.method == 'POST':
form = CommentForm(request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.post = post
comment.save()
return redirect('post_detail', category_slug=category_slug, slug=slug)
else:
user = request.user
form = CommentForm(initial={"name": user.username, "email": user.email})
return render(request, 'blog/post_detail.html', {'post': post, 'form': form})
forms.py
class CommentForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['name'].disabled = True
self.fields['email'].disabled = True
# OR set readonly widget attribute.
# self.fields['name'].widget.attrs['readonly'] = True
# self.fields['email'].widget.attrs['readonly'] = True
class Meta:
model = Comment
fields = ['name', 'email', 'body']
Related
I'm working on a Django blog and I'm stuck here... I want to post comment and when I do that it just refresh the page and nothing happens.
I have no idea where I'm making a mistake, please see my code below:
this is views.py
def post_detail(request, slug):
post = get_object_or_404(Post, slug=slug)
related_posts = post.tags.similar_objects()[:3]
comments = post.comments.filter(active=True)
new_comment = None
if request.method == 'POST':
if request.user.is_authenticated:
comment_form = CommentForm(data=request.POST)
if comment_form.is_valid():
new_comment = comment_form.save(commit=False)
new_comment.post = post
new_comment.author = request.user
new_comment.save()
else:
messages.warning(request, 'You need to be logged in to add a comment.')
else:
if request.user.is_authenticated:
comment_form = CommentForm(initial={'author': request.user})
else:
comment_form = CommentForm()
context = {'post': post, 'related_posts': related_posts, 'comments': comments, 'new_comment': new_comment, 'comment_form': comment_form}
return render(request, 'post_detail.html', context)
this is comment part post_detail.html
{% if user.is_authenticated %}
<!--comment form-->
<div class="comment-form">
<h3 class="mb-30">Leave a Reply</h3>
<form class="form-contact comment_form" action="{% url 'post_detail' post.slug %}" method="post">
{% csrf_token %}
<div class="row">
<div class="col-12">
<div class="form-group">
{{ comment_form | crispy }}
</div>
</div>
</div>
<div class="form-group">
<button type="submit" class="button button-contactForm">Post Comment</button>
</div>
</form>
</div>
{% else %}
<div class="alert alert-danger" role="alert">
Please log in to post a comment.
</div>
{% endif %}
this is models.py
class Post(models.Model):
created_at = models.DateTimeField(auto_now_add=True, verbose_name="Created at")
updated_at = models.DateTimeField(auto_now=True, verbose_name="Updated at")
published_at = models.DateTimeField(null=True, blank=True, editable=False, verbose_name="Published at")
post_title = models.CharField(max_length=200, verbose_name="Title")
slug = models.SlugField(max_length=200, unique=True)
author = models.ForeignKey('auth.User', verbose_name="Author", on_delete=models.CASCADE)
category = models.ForeignKey(Category, verbose_name="Category", on_delete=models.CASCADE)
tags = TaggableManager()
body = QuillField()
image = StdImageField(upload_to='featured_image/%Y/%m/%d/', variations={'standard':(1170,820),'banner':(1170,530),'single_post':(1170,556),'thumbnail':(500,500)})
image_credit = models.CharField(max_length=200, verbose_name="Image credit:")
status = models.IntegerField(choices=STATUS, default=0)
def get_absolute_url(self):
return reverse('post_detail', args=[self.slug])
def get_readtime(self):
result = readtime.of_text(self.body)
return result.text
class Meta:
verbose_name = "Post"
verbose_name_plural = "Posts"
ordering = ['-created_at']
def publish(self):
self.is_published = True
self.published_at = timezone.now()
self.save()
def __str__(self):
return self.post_title
class Comment(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='comments')
body = models.TextField()
author = models.ForeignKey(User, on_delete=models.CASCADE)
created_on = models.DateTimeField(auto_now_add=True)
active = models.BooleanField(default=False)
class Meta:
ordering = ['created_on']
def __str__(self):
return 'Comment "{}" by {}'.format(self.body, self.author.username)
this is forms.py
class CommentForm(forms.ModelForm):
author = forms.CharField(widget=forms.HiddenInput)
class Meta:
model = Comment
fields = ('body', 'user')
Please not that I can post comment over admin page (http://127.0.0.1:8000/admin), but on the front-end doesn't work for some reason.
Any ideas?
You need to redirect() after dealing with POST data, the tip is not specific to Django, its a good web practice in general so:
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib import messages
def post_detail(request, slug):
post = get_object_or_404(Post, slug=slug)
related_posts = post.tags.similar_objects()[:3]
comments = post.comments.filter(active=True)
new_comment = None
if request.method == 'POST':
if request.user.is_authenticated:
comment_form = CommentForm(data=request.POST)
if comment_form.is_valid():
new_comment = comment_form.save(commit=False)
new_comment.post = post
new_comment.author = request.user
new_comment.save()
return redirect(post.get_absolute_url()) # redirect here
else:
messages.warning(request, 'You need to be logged in to add a comment.')
else:
if request.user.is_authenticated:
comment_form = CommentForm(initial={'author': request.user})
else:
comment_form = CommentForm()
context = {'post': post, 'related_posts': related_posts, 'comments': comments, 'new_comment': new_comment, 'comment_form': comment_form}
return render(request, 'post_detail.html', context)
I am working on a movie website with Django and I'm trying to add user comments. Only the registered users should be allowed to comment. I have the following so far:
models.py:
class Comment(models.Model):
movie = models.ForeignKey(Movie, related_name = "comments", on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete = models.CASCADE)
content = models.TextField()
date_added = models.DateTimeField(auto_now_add=True)
def __str__(self):
return '%s - %s' % (self.movie.title, self.name)
forms.py
class CommentForm(forms.ModelForm):
content = forms.CharField(label ="", widget = forms.Textarea(
attrs ={
'class':'form-control',
'placeholder':'Comment here!',
'rows':5,
'cols':50
}))
class Meta:
model = Comment
fields =['content']
views.py
class MovieDetailsView(generic.DetailView):
model = Movie
template_name = "details.html"
def comment(request, id):
movie= Movie.objects.get(id)
if request.method == 'POST':
cf = CommentForm(request.POST or None)
if cf.is_valid():
content = request.POST.get('content')
comment = Comment.objects.create(movie = movie, user = request.user, content = content)
comment.save()
return redirect(movie.get_absolute_url())
else:
cf = CommentForm()
context ={
'comment_form':cf,
}
return render(request, 'details.html', context)
details.html
<form method="POST" action="#" class="form">
{% csrf_token %}
{{comment_form.as_p}}
<button type="submit" class="btn btn-primary btn-lg">Submit</button>
<textarea id="text" name="text" class="form__textarea" placeholder="Add comment"></textarea>
<button type="button" class="form__btn">Send</button>
</form>
The MovieDetailsView displays the details page of the movie and has a comment section. However, when I submit the comment, it simply displays a white page and this link: http://127.0.0.1:8000/details/1# . The comment is not saved on the database and I can't seem to find what the issue is. I am also following the example from this link.
Thanks in advance!
You can combine FormMixin with DetailView - Using FormMixin with DetailView.
from django.urls import reverse
from django.views.generic.detail import DetailView
from django.views.generic.edit import FormMixin
from django.http import HttpResponseForbidden
class MovieDetailsView(FormMixin, DetailView):
model = Movie
template_name = "details.html"
form_class = CommentForm
def get_success_url(self):
return reverse('movie_detail', kwargs={'pk': self.object.pk})
# or
# return self.object.get_absolute_url()
def post(self, request, *args, **kwargs):
if not request.user.is_authenticated:
return HttpResponseForbidden()
self.object = self.get_object()
form = self.get_form()
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
def form_valid(self, form):
form.instance.user = self.request.user
form.instance.movie = self.object
form.save()
return super().form_valid(form)
In the post() method, we first check if the user is logged in:
if not request.user.is_authenticated:
return HttpResponseForbidden()
In template:
<form method="POST" class="form">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-primary btn-lg">Submit</button>
</form>
You can remove the action attribute, the form will be submitted to the same page.
I am new to django, I created a form to save Data into my database but it not working corectly, I got no error but data is not sent in database. Thanks for helping!
views.py
#login_required()
def data(request):
if request.POST == "POST":
form = CreatePost(request.POST)
if form.is_valid():
form.instance.author = request.user
form.save()
return redirect(data)
else:
form = CreatePost()
context = {
"form": form
}
return render(request, "sms/data.html", context)
forms.py
class CreatePost(forms.ModelForm):
class Meta:
model = Post
fields = ["title", "content"]
models.py
class Post(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
author = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.title
data.html
<form method="POST">
{% csrf_token %}
{{ form|crispy }}
<pre></pre>
<button class="btn btn-outline-info" type="submit" value="Submit">Data</button>
</form>
try like this
#login_required()
def data(self, request):
if request.method == "POST": #this line
form = CreatePost(request.POST)
if form.is_valid():
post = form.save(commit=False) #new line
post.author = self.request.user #this line
post.save() #this line
return redirect(data)
else:
form = CreatePost()
context = {
"form": form
}
return render(request, "sms/data.html", context)
if request.POST == "POST":
Should instead be:
if request.method == 'POST':
I have a problem when I was creating the comment form with django. After I wrote my view.py, models.py and html, I got an ValueError that said:
Cannot assign "<class 'blog.models.post'>": "Comment.post" must be a "post" instance".
Below are my codes.
HTML
{% block content %}
<h1>Add New Comment:</h1>
<form method='POST' action=''>
{% csrf_token %}
{{ form.as_p }}
<button type='submit'>Submit</button>
</form>
{% endblock %}
views.py
def add_comment(request, slug):
po = get_object_or_404(post, slug=slug)
if request.method == 'POST':
form = CommentForm(request.POST or None)
if form.is_valid():
comment = form.save(commit=False)
comment.post = post
comment.save()
return redirect('blog:post', slug=post.slug)
else:
form = CommentForm()
return render(request, 'blog/post/add_comment.html', {'form': form})
models.py
class Comment(models.Model):
post = models.ForeignKey(post, related_name='comments', on_delete=models.CASCADE)
user = models.CharField(max_length=250)
email = models.EmailField()
body = models.TextField()
created = models.DateTimeField(auto_now_add=True)
approved = models.BooleanField(default=False)
def approved(self):
self.approved = True
self.save()
def __str__(self):
return self.user
The post you fetched from the database is po:
po = get_object_or_404(post, slug=slug)
Therefore you should set form.post = po:
def add_comment(request, slug):
po = get_object_or_404(post, slug=slug)
if request.method == 'POST':
form = CommentForm(request.POST or None)
if form.is_valid():
comment = form.save(commit=False)
comment.post = po
comment.save()
Note that normally in Django you would use Post for your model and post for the instance you fetch from the database.
Try it:
class Comment(models.Model):
post = models.ForeignKey(Post, related_name='comments', on_delete=models.CASCADE)
In my project as soon as user signup it is redirected to update view where he has to fill this information.Since the user has also logged in automatically after signup I want that user field to be filled automatically and can't be edited.
models.py
class Userpro(models.Model):
user = models.OneToOneField(User)
dob = models.DateField(default=datetime.date.today)
country = models.CharField(max_length=50, default='')
qualification = models.CharField(max_length=10, choices=CHO,
default='No')
university = models.CharField(max_length=100, default='')
location = models.CharField(max_length=100, default='')
def __str__(self):
return str(self.user)
forms.py
class UserProForm(forms.ModelForm):
class Meta:
model = Userpro
fields = '__all__'
views.py
def update(request):
if request.method == 'POST':
form = UserProForm(request.POST or None)
if form.is_valid():
form.save()
return redirect('/')
else:
redirect('/')
else:
form = UserProForm()
return render(request, 'app/update.html', {'form': form})
All the required libraries are imported.
I was with the same problem. The solution I've found is very simple.
First remove the "user" field in your forms.py
them in views:
if form.is_valid():
obj = form.save(commit=False)
obj.user = request.user
obj.save()
by making this the obj is a saved form (but not commited in database) and them you can manage it like puting the user as the request.user; them save.
notice that obj."the name you put in your models"
You can use widgets for your form. Something like this(code below is not tested).
from django.forms import TextInput
class UserProForm(forms.ModelForm):
class Meta:
model = Userpro
fields = '__all__'
widgets = {
'user': TextInput(attrs={'readonly': 'readonly'})
}
def update(request):
instance = Userpro.objects.filter(user=request.user).first()
if request.method == 'POST':
form = UserProForm(request.POST, instance=instance)
if form.is_valid():
form.save()
return redirect('/')
else:
return redirect('/')
else:
form = UserProForm(instance=instance)
return render(request, 'app/update.html', {'form': form})
Edited: we should pass user inside dict like this:
form = UserProForm({'user': request.user})
Edited 2: You should find profile object first and then pass it to the form
instance = Userpro.objects.filter(user=request.user).first()
form = UserProForm(request.POST, instance=instance)
I think it will be better if you will use ModelForm with fields that you want to modify and in template show object instance values like that.
from django.forms import TextInput
class UserProfileForm(forms.ModelForm):
class Meta:
model = Userprofile
fields = ('field1', 'field2')
def update(request):
if request.method == 'POST':
form = UserProfileForm(request.POST or None)
if form.is_valid():
form.save()
return redirect('/')
else:
redirect('/')
else:
form = UserProfileForm(user=request.user)
return render(request, 'app/update.html', {'form': form})
# template
<form method="post">
{% csrf_token %}
<div class="form-row">
{{ form.field1.errors }}
{{ form.field1.label_tag }} {{ form.field1 }}
</div>
<div class="form-row">
{{ form.field2.errors }}
{{ form.field2.label_tag }} {{ form.field2 }}
</div>
<div class="form-row">
{{ form.instance.field3.errors }}
{{ form.instance.field3.label_tag }} {{ form.instance.field3 }}
</div>
</form>