I cannot Save comments in django
my post model is
#model.py
class Post(models.Model):
thumbnail = models.ImageField()
slug = models.SlugField(null=True)
title = models.CharField(max_length=200)
description = models.TextField()
content = HTMLField(null=True)
categories = models.ManyToManyField(Category)
featured = models.BooleanField()
timeStamp = models.DateTimeField(auto_now_add=True)
commentCount = models.IntegerField(default=0)
viewCount = models.IntegerField(default=0)
def __str__(self):
return self.title
def absoluteUrl(self):
return reverse('postContent', kwargs={
'slug' : self.slug
})
#property
def getComments(self):
return self.comments.all()
my comment model is
#model.py
class Comment(models.Model):
name = models.CharField(max_length=25)
timeStamp = models.DateTimeField(auto_now_add=True)
comment = models.TextField()
post = models.ForeignKey(Post, related_name='comments', on_delete=models.CASCADE)
def __str__(self):
return self.name
my forms.py is
from .models import Post, Comment
class CommentForm(forms.ModelForm):
name = forms.CharField(widget=forms.TextInput(attrs={
'class': 'form-control',
'id' : 'name',
'placeholder': 'Name'
}))
comment = forms.CharField(widget=forms.Textarea(attrs={
'class' : 'form-control w-100',
'id' : 'comment',
'cols' : '30',
'rows' : 9,
'placeholder' : 'Write Comment'
}))
class Meta:
model = Comment
fields = ('name', 'comment')
my view.py is
from .forms import CommentForm
def post(request, slug):
categoryCount = getCategoryCount()
featured = Post.objects.filter(featured=True)
post = get_object_or_404(Post, slug=slug)
if request.method == 'POST':
form = CommentForm(request.POST)
if form.is_valid():
form.instance.post = post
form.save()
else:
form = CommentForm()
context = {
'post' : post,
'featured': featured,
'categoryCount': categoryCount,
'form' : form
}
return render(request, 'post.html', context)
my post.html is
<div class="comment-form">
<h4>Leave a Reply</h4>
<form class="form-contact comment_form" method="POST" action="." id="commentForm">
{% csrf_token %}
<div class="row">
<div class="col-12">
<div class="form-group">
{{ form }}
</div>
</div>
</div>
<div class="form-group">
<button type="submit" class="button button-contactForm btn_1 boxed-btn">Send Message</button>
</div>
</form>
</div>
my urls.py
from Posts.views import posts, post, search
urlpatterns = [
path('admin/', admin.site.urls),
path('posts/', posts, name='postLists'),
path('posts/<slug>', post, name='postContent'),
path('search/', search, name='search'),
path('tinymce', include('tinymce.urls')),
]
if settings.DEBUG:
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
I can save comments in admin section but the main problem is when I click the submit button in html the comment is not saving. I am new to django and I cannont figure out the problem.
Is I miss something else?
You can do something like this
temp = form.save(commit=False)
temp.post = post
temp.save()
Update
as per #Abdul Aziz Barkat mentioned you have to change your URL in urls.py add a trailing slash after posts/<slug> and add one more URL to handle POST request
for eg.
from Posts.views import posts, post, search
urlpatterns = [
path('posts/<slug>/', post, name='postContent'),
path('post_comment/<slug>/', post, name='postComment'),
]
and than inside your form action add this
<form method="POST" action="{% url 'postComment' post.slug %}">
and in your view.py
def post(request, slug):
Related
AttributeError at /blog/
Manager isn't accessible via Post instances
Error during template rendering
In template C:\Users\Mahdyar Eatemad\OneDrive\Projects\Gallery\templates\blog\post\list.html, error at line 33
Manager isn't accessible via Post instances
error
i used get_absolute_url to create slug for blog posts
This is my models
from django.db import models
from django.contrib.auth.models import User
from django.utils import timezone
from django.urls import reverse
# Create your models here.
class PublishedManager(models.Manager):
def get_queryset(self):
return super(PublishedManager, self).get_queryset().filter(status='published')
class Post(models.Model):
STATUS_CHOICES = (
('draft', 'چرک نویس'),
('published', 'منتشر شده'),
)
title = models.CharField(max_length=100)
slug = models.SlugField(max_length=100, unique_for_date='publish', allow_unicode=True)
body = models.TextField()
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='blog_posts')
bolded_text = models.TextField(blank=True)
picture = models.ImageField(upload_to='photos', blank=True)
publish = models.DateTimeField(default=timezone.now)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
status = models.CharField(max_length=10, choices=STATUS_CHOICES, default='draft')
objects = models.Manager()
published = PublishedManager()
class Meta:
ordering = ('-publish',)
def get_absolute_url(self):
return reverse('blog:post_detail', args=[self.published.year, self.published.month, self.published.day, self.slug])
def __str__(self):
return self.title
my views
from django.shortcuts import render, get_object_or_404
from .models import Post
# Create your views here.
def post_list(request):
posts = Post.published.all()
return render(request, 'blog/post/list.html', {'posts': posts})
def post_detail(request, year, month, day, slug):
post = get_object_or_404(Post, slug=slug, status='published', published__year=year, published__month=month, published__day=day)
return render(request, 'blog/post/list.html', {'post': post})
my url
from django.urls import path, register_converter
from django.urls.converters import SlugConverter
from . import views
app_name = 'blog'
class PersianSlugConvertor(SlugConverter):
regex = '[-a-zA-Z0-9_ضصثقفغعهخحجچگکمنتالبیسشظطزژرذدپوءآ]+'
register_converter(PersianSlugConvertor, 'persian_slug')
urlpatterns = [
path('', views.post_list, name='post_list'),
path('<int:year>/<int:month>/<int:day>/<persian_slug:slug>', views.post_detail, name='post_detail'),
]
template
{% for post in posts %}
<article class="post">
<div class="post_header">
<h3 class="post_title">{{ post.title }}</h3>
<div class="post_sub"><i class="fa-time"></i>منتشر شده در {{ post.publish }} توسط {{ post.author }}<i class="fa-comments-alt"></i> 6 نظر </div>
</div>
<div class="post_content">
<figure><img alt="عکس پست" src="{{ post.picture }}"></figure>
<p>{{ post.body|truncatewords:30|linebreaks }}</p>
بیشتر بخوانید </div>
</article>
{% endfor %}
you write
reverse('blog:post_detail', args=[self.published.year,
self.published.month, self.published.day, self.slug])
where you are referencing published which is a manager, instead you want to refer to publish which is your date time field
I am working on my project I faced a problem with "COMMENT":
I add a comment as a section when the user clicks "view" button to see the post from the home page.
Django error :
NoReverseMatch at /Post/8
Reverse for 'comments' with arguments '('',)' not found. 1 pattern(s) tried: ['Post/(?P[0-9]+)$']
views.py file
def viewList(request, id):
item = Post.objects.get(id=id)
context = {
'item': item,
'comment_form': comment(),
'comments': item.get_comments.all(),
}
return render(request, 'auctions/item.html', context)
#login_required
def comments(request, id):
listing = Post.objects.get(id=id)
form = comment(request.PSOT)
newComment = form.save(commit=False)
newComment.user = request.user
newComment.listing = listing
newComment.save()
return HttpResponseRedirect(reverse("listing", {'id': id}))
models.py file
class Post(models.Model):
# data fields
title = models.CharField(max_length=64)
textarea = models.TextField()
# bid
price = models.FloatField(default=0)
currentBid = models.FloatField(blank=True, null=True)
imageurl = models.CharField(max_length=255, null=True, blank=True)
category = models.ForeignKey(
Category, on_delete=models.CASCADE, default="No Category Yet!", null=True, blank=True)
creator = models.ForeignKey(User, on_delete=models.PROTECT)
watchers = models.ManyToManyField(
User, blank=True, related_name='watched_list')
date = models.DateTimeField(auto_now_add=True)
# for activated the Category
activate = models.BooleanField(default=True)
def __str__(self):
return f"{self.title} | {self.textarea} | {self.date.strftime('%B %d %Y')}"
class Comment(models.Model):
body = models.CharField(max_length=100)
createdDate = models.DateTimeField(default=timezone.now)
# link to the post model
auction = models.ForeignKey(
Post, on_delete=models.CASCADE, related_name="get_comments")
user = models.ForeignKey(User, on_delete=models.CASCADE)
status = models.BooleanField(default=True)
def __str__(self):
return self.createdDate.strftime('%B %d %Y')
HTML file
<!-- Comments -->
<div class="comments">
<p>Add a comment:</p>
<div class="row">
<div class="col-6">
<form action="{% url 'comments' listing.id %}" method="post">
{% csrf_token %}
<div class="input-group">
{{ comment_form }}
</div>
<input type="submit" value="save" class="btn btn-outline-dark btn-sm m-1"/>
</form>
</div>
{% for comment in comments %}
<div class="col-4">
Comments:
<h4>Name: {{comment.user}}</h4>
<h4>Content: {{comment.body}}</h4>
<h4>Date: {{comment.createdDate}}</h4>
</div>
{% endfor %}
</div>
</div>
url.py
from django.urls import path
from . import views
urlpatterns = [
path("", views.index, name="index"),
path("login", views.login_view, name="login"),
path("logout", views.logout_view, name="logout"),
path("register", views.register, name="register"),
path("category/", views.category, name="category"),
path("Post", views.createList, name="createList"),
#comment url
path("Post/<str:id>", views.viewList, name="viewList"),
path("Post/<int:id>", views.comments, name="comments"),
]
You passed the Post object as item to the template, hence you should resolve the URL with:
<!-- use item not listing ↓ -->
<form action="{% url 'comments' item.id %}" method="post">
…
</form>
Your view to create comments also has some mistakes: you should use request.POST, not request.PSOT:
from django.shortcuts import redirect
#login_required
def comments(request, id):
if request.method == 'POST'
form = comment(request.POST, request.FILES)
if form.is_valid():
form.instance.user = request.user
form.instance.auction_id = id
form.save()
return redirect('viewList', id=id)
Furthermore your comment form should inherit from ModelForm and not Form:
class comment(forms.ModelForm):
class Meta:
model = Comment
fields = ('content',)
widgets = {
'content': forms.Textarea(attrs={"class": "form-control"})
}
finally your urls.py has two (fully) overlapping patterns, you should use a different URL to add the given comment:
urlpatterns = [
# …
#comment url
path('Post/<int:id>', views.viewList, name='viewList'),
path('Post/<int:id>/add', views.comments, name='comments'),
]
Note: Usually a Form or a ModelForm ends with a …Form suffix,
to avoid collisions with the name of the model, and to make it clear that we are
working with a form. Therefore it might be better to use CommentForm instead of
comment.
My model has a field call topic, and I want to create a page which can show the specific, and the urls can be dynamic path to different topics rendered by the same html template. How do I suppose to do it?
models.py:
TOPIC = (
(0,"Finance"),
(1,"Toys"),
(2,"Foods"),
(3,"Travel"),
)
class Post(models.Model):
name = models.CharField(max_length=200)
slug = models.SlugField(unique=True, max_length=200)
author = models.ForeignKey(User, on_delete=models.CASCADE,related_name='blog_posts')
updated_on = models.DateTimeField(auto_now= True)
created_on = models.DateTimeField(auto_now_add=True)
body = RichTextField(null=True)
status = models.IntegerField(choices=STATUS, default=0)
topic = models.IntegerField(choices=TOPIC, default=0)
cover_img = models.ImageField(upload_to='post_cover', null=True, default='post_cover/coming_soon.jpg')
def __str__(self):
return self.name
def get_img(self):
return f"{'/media/post_cover/'+self.cover_img}"
html
<div class="col-md-6 mt-3 ">
<a href="{% url 'topic_list' %}">
<img src="../media/topic/travel3.jpg" alt=''>
</a>
</div>
views.py
def topic_list(request):
posts = Post.objects.filter(topic=0)
context = {'posts': posts, 'autor_list':autor_list}
return render(request, 'topic_list.html', context)
urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.home, name='home'),
path('topic/', views.topic_list, name='topic_list'),
path('<slug:slug>/', views.post_detail, name='post_detail'),]
To generate a dynamic url in the template use url-reversion function with arguments
{% for post in post_list %}
{{ post.name}}
{% endfor %}
this will reverse post_detail url pattern from your urls.py with post.slug value passed to '<slug:slug>/'
If you need to list posts per topic then fix your url pattern and the view like below:
urlpatterns = [
...
path('topic/<int:pk>/', views.topic_post_list, name='topic-posts-list'),
]
def topic_post_list(request, pk):
posts = Post.objects.filter(topic_id=pk, )
context = {'posts': posts, }
return render(request, 'post_list.html', context)
I am trying to post comments to a post in Django, but my form is never valid. I have discovered that this is because my request.method is always a GET and not a POST. I would like to allow a user to add a new comment and have it automatically save to the database and display on my post's detail view.
views.py
def add_comment_to_post(request, pk):
print("REQUEST METHOD", request.method)
post = get_object_or_404(Post, pk=pk)
if request.method == "POST":
print("POST")
print(request.POST)
form = CommentForm(request.POST)
if form.is_valid():
print("HREE")
comment = form.save(commit=False)
comment.author = request.user
comment.date_posted = timezone.now()
comment.post = post
comment.save()
return redirect('post_detail', pk=comment.post.pk)
else:
print("ELSE")
form = CommentForm()
# Note the indentation (this code will be executed both if NOT POST
# and if form is not valid.
return render(request, 'main/add_comment_to_post.html', {'form': form, 'post':post})
forms.py
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ['author', 'content']
models.py
class Comment(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='comments')
comment_id = models.AutoField(primary_key=True)
author = models.ForeignKey(Profile, on_delete=models.CASCADE)
content = models.TextField()
date_posted = models.DateTimeField(default=timezone.now)
# approved_comment = models.BooleanField(default=False)
def approve(self):
self.approved_comment = True
self.save()
class Meta:
ordering = ['date_posted']
def __str__(self):
return 'Comment {} by {}'.format(self.content, self.author.first_name)
class Post(models.Model):
run_id = models.AutoField(primary_key=True)
author = models.ForeignKey(Profile, on_delete=models.CASCADE)
title = models.TextField(max_length=100, blank=False, default="title holder.")
distance = models.FloatField(default=0.0, blank=False)
time = models.IntegerField(default=0, blank=False)
date_posted = models.DateTimeField(default=timezone.now)
location = models.TextField(max_length=100, blank=False, default="")
image = models.TextField(max_length=250, blank=True)
content = models.TextField(max_length=1000, blank=True, default="")
#property
def pace(self):
if self.distance == 0.0:
return 0.0
return round(self.time / self.distance, 2)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('post-detail', kwargs={'pk': self.pk})
#receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
#receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
instance.profile.save()
urls.py
urlpatterns = [
# path('', views.home, name="main-home"),
path('', PostListView.as_view(), name="main-home"),
path('admin/', admin.site.urls),
path('register/', views.register, name="register"),
path('post/<int:pk>/', PostDetailView.as_view(), name='post-detail'),
path('post/new/', PostCreateView.as_view(), name='post-create'),
path('post/<int:pk>/update/', PostUpdateView.as_view(), name='post-update'),
path('post/<int:pk>/delete/', PostDeleteView.as_view(), name='post-delete'),
path('about/', views.about, name="main-about"),
path('search/', SearchResultsView.as_view(), name="main-search"),
path('post/<int:pk>/comment/', views.add_comment_to_post, name='add_comment_to_post'),
]
add_comment_to_post.html
{% extends "main/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<h1>New comment</h1>
<form action="" method="POST">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">New Comment</legend>
{{ form|crispy }}
</fieldset>
<div class="form-group">
<a class="btn btn-outline-info" type="submit" href="{% url 'post-detail' pk=post.pk %}">Send</a>
</div>
</form>
{% endblock %}
What I have tried
checking out what type of request it is and handling it
searching other similar posts to no avail
changing the views function
Any help would be appreciated.
You didn't define else state for if form.is_valid(): statement. So, if your form has errors, view render your template again.
<div class="form-group">
<a class="btn btn-outline-info" type="submit" href="{% url 'post-detail' pk=post.pk %}">Send</a>
</div>
Your problem is this is a link and not actually a form submit. Try replacing that link with a simple <input type="submit" value="Send">.
I'm trying to make a way to log notes associated with records. When the form is submitted, it's trying to redirect to the same url, but without the record id, which should be required to view the page. I defined it in urls with the record id, so it should be tracker/19/newnote
I want it to route to tracker/19/detail, and I'm not sure why it's routing to tracker/newnote, which doesn't exist in my urls file. Maybe I need to create it?
anyway, here are my files if anyone wants to take a crack at this with me.
models.py
class Record(models.Model):
serial = models.CharField('Serial Number', max_length=9)
product = models.CharField('Product', max_length=6)
ticket = models.CharField('Log/RID', max_length=9)
eng_date = models.DateField('Date Engaged')
customer = models.CharField('Customer', max_length=80)
details = models.TextField('Problem Details', max_length=800)
owner = models.CharField('Owner', max_length=40)
class Note(models.Model):
record = models.ForeignKey(Record, on_delete=models.CASCADE)
note_text = models.TextField('Notes', max_length=2000)
note_date = models.DateField('Date Entered')
views.py
def newnote(request, record_id):
if request.method == 'POST':
form = NoteForm(request.POST)
if form.is_valid():
r = Record.objects.get(pk=record_id)
r.note_set.create(note_text=form.note_text, note_date=form.note_date)
r.save()
return HttpResponseRedirect('/tracker/%s/detail/' % record_id)
else:
form = NoteForm()
return render(request, 'tracker/noteform.html', {'form': form})
forms.py
class NoteForm(ModelForm):
class Meta:
model = Note
fields = ['note_text',
'note_date'
]
widgets = {
'note_date': DateInput(),}
urls.py
urlpatterns = [
path('', views.index, name='index'),
path('create/', views.create, name='create'),
path('<int:record_id>/detail/', views.detail, name='detail'),
path('result/', views.result, name='result'),
path('query/', views.query, name='query'),
path('all/', views.show_all, name='all'),
path('<int:record_id>/newnote/', views.newnote, name='newnote'),
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
nameform.html template
<div id=form>
<h3>New Note??</h3>
<hr>
<form action="/tracker/newnote/" method="post">
<div id="fields">
{% csrf_token %}
<p>Note:<br>{{ form.note_text }}</p>
<p>Note Date:<br>{{ form.note_date }}</p>
<input type="submit" value="Submit" />
</div>
</form>
</div>