I'm trying to post comment but it's not getting posted, rather this error is appearing UNIQUE constraint failed: players_comment.user_id. I don't know why this error is occuring.
My forms.py:
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ('body', 'transfernews')
My models.py :
class Transfernews(models.Model):
player_name = models.CharField(max_length=255)
player_image = models.CharField(max_length=2083)
player_description = models.CharField(max_length=3000)
date_posted = models.DateTimeField(default=timezone.now)
class Comment(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
transfernews = models.ForeignKey(Transfernews, related_name="comments", on_delete=models.CASCADE)
body = models.TextField()
date_added = models.DateTimeField(auto_now_add=True)
def __str__(self):
return '%s - %s' % (self.transfernews.player_name, self.user.username)
My views.py:
def transfer_targets(request):
transfernews = Transfernews.objects.all()
form = CommentForm(request.POST or None)
if form.is_valid():
new_comment = form.save(commit=False)
new_comment.user = request.user
new_comment.save()
return redirect('transfernews/')
return render(request, 'transfernews.html', {'transfernews': transfernews, 'form': form})
My transfernews.html:
{% for transfer in transfernews %}
{% if not transfer.comments.all %}
No comments Yet...
{% else %}
{% for comment in transfer.comments.all %}
<strong>
{{ comment.user.username }} - {{ comment.date_added }}
</strong>
<br/>
{{ comment.body }}
<br/><br/>
{% endfor %}
{% endif %}
<hr>
<div>Comment and let us know your thoughts</div>
<form method="POST">
{% csrf_token %}
{{ form|crispy }}
<button class="btn btn-primary btn-sm shadow-none" type="submit">Post comment</button>
<button class="btn btn-outline-primary btn-sm ml-1 shadow-none" type="button">Cancel</button>
</form>
{% endfor %}
In models.py, in the comment class, change
user = models.OneToOneField(User, on_delete=models.CASCADE)
to
user = models.ForeignKey(to=User, on_delete=models.CASCADE)
One to one works both ways, user's allowed to only have one comment and a comment can belong to only one user. By changing to one to many via foreignkey you'll preserve the latter and get rid of the former constraint.
Related
Coding some kind of blog with django, and I can't make homepage to contain images of the articles... It just doesn't upload a image...
my Views.py :
class AddPostView(CreateView):
model = Post
form_class = PostForm
template_name = 'add_post.html'
my Models.py:
class Post(models.Model):
title = models.CharField(max_length=255)
title_tag = models.CharField(max_length=255, default="YNTN")
#author = models.ForeignKey(User, on_delete=models.CASCADE)
body = RichTextField(blank=True, null=True)
image = models.ImageField(upload_to="profile_pics", blank=True, null=True)
#body = models.TextField()
post_date = models.DateField(auto_now_add=True)
likes = models.ManyToManyField(User, related_name="blog_posts")
def total_likes(self):
return self.likes.count()
def __str__(self):
return (self.title + " | " + str(self.author))
def get_absolute_url(self):
return reverse("home")
My Forms.py:
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = ('title', 'title_tag', 'body', 'image')
widgets = {
'title': forms.TextInput(attrs={'class':'form-control', 'placeholder':'Title of the Blog'}),
'title_tag': forms.TextInput(attrs={'class':'form-control', 'placeholder':'Copy the title with no space and a hyphen in between'}),
'body': forms.Textarea(attrs={'class':'form-control', 'placeholder':'Content of the Blog'}),
}
and my add_post.html :
{% extends 'base.html' %}
{% block title %}Make an article{% endblock %}
{% block content %}
{% if user.is_authenticated %}
<h1>Make an article</h1>
<div class="form-group">
<form method="POST">
<br/>
{% csrf_token %}
{{ form.media }}
{{ form.as_p }}
<button class="btn btn-dark">POST</button>
</div>
{% else %}
<h1>You are not allowed to post! You need to Log in or Register</h1>
{% endif %}
{% endblock %}
I tried on many ways but never worked..
You are missing enctype="multipart/form-data" (as mentioned in the documentation) in the form tag inside the html template. Update the html file like this:
<form method="POST" enctype="multipart/form-data">
<br/>
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-dark">POST</button>
</form>
I want my users to be able to add comments under a transfernews [I am creating a sports related website], I tried this code, but for some reason I am getting this error TypeError at /transfernews/ Field 'id' expected a number but got <Transfernews: Transfernews object (3)>., I can add comments manually from the admin page but can't from the comment form. Can anyone please tell me how to fix my code?
My models.py:
class Transfernews(models.Model):
player_name = models.CharField(max_length=255)
player_image = models.CharField(max_length=2083)
player_description = models.CharField(max_length=3000)
date_posted = models.DateTimeField(default=timezone.now)
class Comment(models.Model):
user = models.ForeignKey(to=User, on_delete=models.CASCADE)
transfernews = models.ForeignKey(Transfernews, related_name="comments", on_delete=models.CASCADE)
body = models.TextField()
date_added = models.DateTimeField(auto_now_add=True)
def __str__(self):
return '%s - %s' % (self.transfernews.player_name, self.user.username)
My forms.py:
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ('body',)
My views.py:
def transfer_targets(request):
transfernews = Transfernews.objects.all()
news = request.POST.get("transfer_id", None)
form = CommentForm(request.POST or None)
if form.is_valid():
new_comment = form.save(commit=False)
new_comment.user = User.objects.get(id=request.user.id)
new_comment.transfernews_id = Transfernews.objects.get(id=news)
new_comment.save()
return redirect(request.path_info)
return render(request, 'transfernews.html', {'transfernews': transfernews, 'form': form})
My html file:
{% for transfer in transfernews %}
<h2>Comments...</h2>
{% if not transfer.comments.all %}
No comments Yet...
{% else %}
{% for comment in transfer.comments.all %}
<strong>
{{ comment.user.username }} - {{ comment.date_added }}
</strong>
<br/>
{{ comment.body }}
<br/><br/>
{% endfor %}
{% endif %}
<hr>
<div>Comment and let us know your thoughts</div>
<form method="POST">
{% csrf_token %}
<input type="hidden" value="{{ transfer.id}}">
<div class="bg-alert p-2">
<div class="d-flex flex-row align-items-start">
</div>
<div class="mt-2 text-right">
{{ form|crispy }}
<br>
<button class="btn btn-primary btn-sm shadow-none" type="submit">Post comment</button>
<button class="btn btn-outline-primary btn-sm ml-1 shadow-none" type="button">Cancel</button>
</div>
</div>
</form>
{% endfor %}
Try using new_comment.transfernews = transfernews instead of new_comment.transfernews_id = transfernews.id.
Also change redirect(request.path_info) to redirect(reverse('<app_name>:<url_namespace>')).
You have to add a name attribute to your hidden input, then only the hidden input data will be included in the form data.
<input type="hidden" name="transfer_id" value="{{ transfer.id}}">
and in your transfer_targets view make these changes
def transfer_targets(request):
transfernews = Transfernews.objects.all()
transfernews = request.POST.get("transfer_id", None)
form = CommentForm(request.POST or None)
if form.is_valid():
new_comment = form.save(commit=False)
new_comment.user = User.objects.get(id=request.user.id)
new_comment.transfernews_id = transfernews.id
new_comment.transfernews_id = Transfernews.objects.get(id=transfernews)
new_comment.save()
return redirect(request.path_info)
return render(request, 'transfernews.html', {'transfernews': transfernews, 'form': form})
I made a project with net-ninja on youtube now I am adding "uploading media" feature in my own project but it is not working although every thing is set just tell me where i m going wrong.
My form is keep asking me to upload image file even though i had already done, every time i send a post request it renders the page again with no value in image field. what is wrong here, why it is not taking image input?Don't comment set the required to false that is not the solution i don't know why some people said this to others on stackoverflow when they asked the same question as me.
My model class looks like this
class Products(models.Model):
name = models.CharField(max_length=500, unique=True, )
price = models.IntegerField()
stock = models.IntegerField()
date_added = models.DateTimeField(verbose_name="date added", auto_now_add=True, )
thumb = models.ImageField(default='default.png', blank=True)
profile = models.ForeignKey(Profile, on_delete=models.CASCADE, default=None,)
def __str__(self):
return self.name
class Meta():
verbose_name_plural = "Products"
My form looks like this
class AddProduct(forms.ModelForm):
name = forms.CharField(widget=forms.TextInput(attrs={'placeholder':'Product Name', 'required':'True', 'class': 'form-control'}))
price = forms.IntegerField(widget=forms.NumberInput(attrs={'placeholder':'Set Price', 'required':'True', 'class': 'form-control'}))
stock = forms.IntegerField(widget=forms.NumberInput(attrs={'placeholder':'Number of items', 'required':'True', 'class': 'form-control'}))
thumb = forms.ImageField(required=False, widget=forms.ClearableFileInput(attrs={'placeholder':'Upload Picture', 'enctype' : 'multipart/form-data'}))
class Meta():
model = Products
fields = ('name', 'price', 'stock','thumb', )
HTML looks like this
<form class="row contact_form" action="/shop/add_products" method="post">
{% csrf_token %}
{% for field in form %}
<div class="col-md-12 form-group p_star">
{{ field }}
{{ field.errors }}
</div>
{% endfor %}
<!-- {% for field in form %}
{% for error in field.errors %}
<div class="col-md-12 form-group p_star">
{{ error }}
</div>
{% endfor %}
{% endfor %} -->
{% if form.non_field_errors %}
<div class="col-md-12 form-group p_star">
{{ form.non_field_errors }}
</div>
{% endif %}
<div class="col-md-12 form-group">
<button type="submit" value="submit" class="btn_3">
Add Product
</button>
</div>
</form>
My views file looks like this
#login_required(login_url='/shop/login')
def shop_add_products(request):
if request.method == 'POST':
form = AddProduct(request.POST, request.FILES)
if form.is_valid():
instance = form.save(commit=False)
instance.profile = request.user
instance.save()
return redirect("/shop/products")
else:
form = AddProduct()
return render(request, "pillow_site_html/add_product.html", { 'form':form })
Oh sorry i didn't understood the question here, you are getting that because in fact you are not sending the picture inside your form as you have to add this to your form so it can accept files handling
<form class="row contact_form" action="/shop/add_products" method="post" enctype="multipart/form-data">
I have Comment model in my Django app.
I want to make comment author to be current registered author, not another registered account.
Here is screenshot, I can choose user2 account to post the comment, but currently I'm on user1 account.
Here is my Django Comment model:
class Comment(models.Model):
post = models.ForeignKey(Post,on_delete=models.CASCADE,related_name='comments')
name = models.ForeignKey(User, on_delete=models.CASCADE)
email = models.EmailField()
body = models.TextField()
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.name)
And some code from html form:
<article class="media content-section">
<div class="media-body">
<!-- comments -->
{% if comments.count == 1 %}
<h2>{{ comments.count }} comment</h2>
{% else %}
<h2>{{ comments.count }} comments</h2>
{% endif %}
{% for comment in comments %}
<div class="comments" style="padding: 10px;">
<p class="font-weight-bold">
{{ comment.name }}
<span class=" text-muted font-weight-normal">
{{ comment.created_on }}
</span>
</p>
{{ comment.body | linebreaks }}
</div>
{% endfor %}
{% if new_comment %}
<div class="alert alert-success" role="alert">
Your comment is awaiting moderation
</div>
{% else %}
<h3>Leave a comment</h3>
{% load crispy_forms_tags %}
<form method="post" style="margin-top: 1.3em;">
{{ comment_form | crispy }}
{% csrf_token %}
<button type="submit" class="btn btn-primary btn-lg">Submit</button>
</form>
{% endif %}
</div>
</article>
EDIT
view.py
def post_detail(request, slug):
template_name = 'blog/post_detail.html'
post = get_object_or_404(Post, slug=slug)
comments = post.comments.filter(active=True)
new_comment = None
# Comment posted
if request.method == 'POST':
comment_form = CommentForm(data=request.POST)
if comment_form.is_valid():
# Create Comment object but don't save to database yet
new_comment = comment_form.save(commit=False)
# Assign the current post to the comment
new_comment.post = post
# Save the comment to the database
new_comment.save()
else:
comment_form = CommentForm()
return render(request, template_name, {'posts': post,
'comments': comments,
'new_comment': new_comment,
'comment_form': comment_form})
You can make the field non-editable, by setting the editable=… parameter [Django-doc] to False. I furthermore advise to use user and not name, since it is a reference to the user object, not the name of the user:
class Comment(models.Model):
post = models.ForeignKey(Post,on_delete=models.CASCADE,related_name='comments')
user = models.ForeignKey(User, editable=False, on_delete=models.CASCADE)
email = models.EmailField()
body = models.TextField()
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.user)
Then in your view, when the form is valid, you set the instance.user of that form to the request.user:
from django.contrib.auth.decorators import login_required
#login_required
def add_comment(request, post_id):
# …
if request.method == 'POST':
form = CommentForm(request.POST, request.FILES)
if form.is_valid():
form.instance.user = request.user
# …
# …
# …
Well, there shouldn't be a choice of users. To identify user just use request.user in your view. I don't know how your view looks like, but you can set name like this:
name = request.user
# or if you're using classes:
name = self.request.user
I have 4 models: User, Blogger, Post and Comment.
Now, in 'post_desc.html', i want to insert a comment box.
{% if user.is_authenticated %}
<form method="post">
{% csrf_token %}
<input type="text" name="comment" style="width: 800px; height: 145px;"></br></br>
<button type="submit">Submit Comment</button>
</form>
{% else %}
<p>Login to comment</p>
{% endif %}
So, this form will only take comment from the user.
But how to store information like 'commented_by' which will the user that is currently logged in and 'commented_on' which will be the post_topic in which he/she is commenting.
How to store these information automatically? in views.py i tried 'request.user' but that didn't worked. Any solutions?
Comment model:
class Comment(models.Model):
commented_by = models.ForeignKey(User, related_name='comments')
commented_on = models.ForeignKey(Post, related_name='comments')
commented_text = models.CharField(max_length=500)
commented_time = models.DateTimeField(auto_now_add=True)
Post model:
class Post(models.Model):
topic = models.CharField(max_length=200)
description = models.TextField()
created_by = models.ForeignKey(User, related_name='posts')
created_on = models.DateTimeField()
I did this in my view.py
def post_desc(request, pk):
post = get_object_or_404(Post, pk=pk)
if request.method == 'POST':
comment = request.POST['comment']
comments = Comment.objects.create(
commented_text = comment,
commented_on = request.topic,
commented_by = request.user
)
return redirect('post_desc', pk=post.pk)
return render(request, 'post_desc.html', {'post': post})
But it is giving error, "'WSGIRequest' object has no attribute 'post'".
The only thing wrong with your code is that there's no such thing as request.topic. The topic is the Post, which you already have.
comments = Comment.objects.create(
commented_text = comment,
commented_on = post,
commented_by = request.user
)
you have to a create a url that have a pk parameter to know where to post the comment in which post?:
url(r'add/comment/post/(?P<pk>[0-9]+)', views.new_comment, name="comment")
now let's create the view new_comment:
from django.utils import timezone
def new_comment(request, pk):
user = request.user
comment_text = request.POST['your-comment-input-name']
post = Post.objects.get(id=pk)
Comment.objects.create(created_by=user, text=comment_text, post=post, create_at=timezone.localtime(timezone.now()))
return HttpResponseRedirect(request.META.get('HTTP_REFERER'))
don't forget to set your form action to action="{% url 'comment' Post.id %}"
I have something like that in my blog project which I develop for improve myself in django python.
my model;
class Comment(models.Model):
post = models.ForeignKey('post.Post', related_name='comments', on_delete=models.CASCADE)
name = models.CharField(max_length=150, verbose_name='Your Name')
comment = models.TextField(verbose_name='Your Comment')
created_date = models.DateTimeField(auto_now_add=True)
my view for post detail page;
def post_detail(request, slug):
post = get_object_or_404(Post, slug=slug)
form = CommentForm(request.POST or None)
if form.is_valid():
comment = form.save(commit=False)
comment.post = post
comment.save()
return HttpResponseRedirect('your redirect page')
context = {
'post': post,
'form': form,
}
return render(request, 'post/detail.html', context)
my post detail template page;
<h3>Comments;</h3>
{% if post.comments.count <= 0 %}
<h4>No comment yet!</h4>
{% else %}
{% for comment in post.comments.all %}
<h4>{{ comment.name }} |
<small>{{ comment.created_date|timesince }}</small>
</h4>
<p>{{ comment.comment|linebreaks }}</p>
<hr/>
{% endfor %}
{% endif %}
<h3>Add Comment:</h3>
{% include 'post/comment.html' %}
my comment form template;
{% load crispy_forms_tags %}
<form method="post">
{% csrf_token %}
{{ form|crispy }}
<input class="btn btn-primary" type="submit" value="Add Comment"/>
</form>
Hope this helps.