I'm trying to make comments on the site, but when I start the server, I do not see the forms. I create a simple blog in which a person can post likes and comment, but the problem is that when i add a comment form, they simply do not appear.
P.S
And excuse me for my English I am from another country and I don’t know English very well
post.html main template
{% extends "ShapeHtml/wrapper.html" %}
{% block content %}
<div class="panel panel-default">
<div class="panel-heading">
<h1 class=" text-info">{{object.title}}</h1>
</div>
<div class="panel-body">
<p> {{object.post|safe|linebreaks}} </p>
<h3 align="right" class=" text-info"> Опубликованно: {{articles.date|date:"d-m-Y в H:i"}}</h3>
</div>
<h4>Comments</h4>
<form action="{% url '' %}" method="post">
{% csrf_token %}
{% if CommentModel %}
{% for CommentModel in comments %}
{{ CommentModel.WhoAreYou }} <br>
{% endfor %}
{% endif %}
{{ form }}
<input type="submit" value="Submit">
</form>
{% endblock %}
views.py
from .forms import CommentForm
class ArticlesList(ListView):
model = Articles
template_name = 'news/posts.html'
class ArticleDetail(DetailView):
model = Articles
template_name = 'news/post.html'
def GetComments(request):
if request.method == 'POST':
form = CommentForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect(request.path_info)
else:
form = CommentForm()
comments = CommentModel.objects.all()
return render(request, 'news/post.html', {'form': form, 'comments': comments})
urls.py
urlpatterns=[
path('', ArticlesList.as_view(), name='articles_list'),
path('<int:pk>/', ArticleDetail.as_view(), name='article_detail'),
path('aboutUs', views.aboutUs, name='aboutUs'),
]+ static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
models.py it's models for posts and for comments
from django.db import models
class Articles(models.Model):
title = models.CharField(max_length= 200)
post = models.TextField()
date = models.DateTimeField()
img = models.ImageField(upload_to='', default="default_value")
def __str__(self):
return self.title
class CommentModel(models.Model):
WhoAreYou = models.CharField(max_length=100)
forms.py form for fields
class CommentForm(ModelForm):
class Meta:
model = CommentModel
fields = ('WhoAreYou',)
you've write class CommentForm(forms.ModelForm) in forms.py:
class CommentForm(forms.ModelForm):
comment = forms.CharField()
class Meta:
model = CommentModel
fields = ('WhoAreYou',)
I guess it'll works.
Related
I'm trying to create user Profile for my django project, I'm using UpdateView to allow user to edit Profile model when they want to create profile for their account but it return an error every time I click on create profile url in the profile template.
the error message:
Page not found (404)
No profile found matching the query
Request Method: GET
Request URL: http://127.0.0.1:8000//6/edit
Raised by: answer.views.EditProfileView
Profile Template:
<div class="container">
<div class="row justify-content-center">
{% for profile in profiles %}
<div class="col">
{{profile.website}}
{{profile.website}}
</div>
{% endfor %}
</div>
</div>
<br>
<div class="container">
<div class="row">
Create Profile
</div>
</div>
My model:
class Profile(models.Model):
user = models.OneToOneField(User,on_delete=models.CASCADE)
profile_image = models.ImageField(upload_to="avatars/")
stories = models.TextField(max_length=500,blank=True, null=True)
website = models.URLField(max_length=250, blank=True, null=True)
twitter = models.URLField(max_length=250, blank=True, null=True)
location = models.CharField(max_length=50, blank=True, null=True)
slug = models.SlugField(blank=True, null=True)
my urls:
path('editprofile/<slug:slug>/edit', views.EditProfileView.as_view(), name='editProfile'),
my views:
#login_required(login_url='login')
def profile(request, pk):
profiles = Profile.objects.filter(user=request.user)
questions = Question.objects.filter(user=request.user)
context = {'questions':questions, 'profiles':profiles}
return render(request, 'profile.html', context)
class EditProfileView(UpdateView):
model = Profile
fields = ['profile_image', 'stories', 'website', 'twitter', 'location']
template_name = 'edit_profile.html'
success_url = reverse_lazy('index')
def save(self, *args, **kwargs):
self.slug = slugify(self.user)
super(Creator, self).save(*args, **kwargs)
my index template:
<div class="container">
<div class="row justify-content-center">
<div class="row justify-content-center">
<div class="col-md-6">
Ask Question
<a href="{% url 'notification' %}" class="btn btn-primary">Notifications
{% if unread_notifications %}
<span class="badge bg-secondary">{{unread_notifications}}</span>
{% endif %}
</a>
FeedBack
Profile
Log Out
</div>
</div>
</div>
</div>
You have made user a OneToOneField in your Profile model, that means you should not use filter() in profile view, you should use get_object_or_404 for getting single user's profile, as it has OneToOneRelation.
Try this:
from django.shortcuts import get_object_or_404
#login_required(login_url='login')
def profile(request, pk):
profile = get_object_or_404(Profile,user=request.user)
questions = Question.objects.filter(user=request.user)
context = {'questions':questions, 'profile':profile}
return render(request, 'profile.html', context)
class EditProfileView(UpdateView):
model = Profile
fields = ['profile_image', 'stories', 'website', 'twitter', 'location']
template_name = 'edit_profile.html'
success_url = reverse_lazy('index')
def index(request):
return render(request, 'index.html')
profile.html:
<div class="container">
<div class="row justify-content-center">
{% comment %} {% for profile in profiles %} {% endcomment %}
<div class="col">
{{profile.website}}
{{profile.website}}
</div>
{% comment %} {% endfor %} {% endcomment %}
</div>
</div>
<br>
<div class="container">
<div class="row">
Create Profile
</div>
</div>
Note: I have passed profile.slug since the EditProfileView also requires slug to come in route.
Note: You should not run loop while displaying data with single object.
index.html (success template):
<body>
<h3>Profile updated successfully.</h3>
</body>
edit_profile.html
<body>
<h2>You can edit your profile </h2>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Save">
</form>
</body>
urls.py
urlpatterns = [
path('profile-updated/', views.index, name='index'),
path('profile/<int:pk>/', views.profile, name='profile'),
path('editprofile/<slug:slug>/edit/',
views.EditProfileView.as_view(), name='editProfile')
]
That will successfully update your profile.
Firstly fix
def save(self, *args, **kwargs):
self.slug = slugify(self.user.field) #field is what you want to slugfiy
super(Creator, self).save(*args, **kwargs)
secondly
You are sending ID but url requires slug
#old
Create Profile
#should be
Create Profile
my views.py file:
from django.shortcuts import render
from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView
from django.contrib.auth.mixins import (
LoginRequiredMixin,
UserPassesTestMixin,
)
from .models import Post
# Create your views here.
class PostListView(ListView):
model = Post
template_name = "blog/index.html"
context_object_name = "posts"
ordering = ["-date_posted"]
class PostDetailView(DetailView):
model = Post
class PostCreateView(CreateView, LoginRequiredMixin, UserPassesTestMixin):
model = Post
fields = ['title', 'genere', 'content']
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
class PostUpdateView(UpdateView, LoginRequiredMixin, UserPassesTestMixin):
model = Post
success_url = "blog-home"
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
def test_func(self):
post = self.get_object()
if self.request.user == post.author:
return True
return False
class PostDeleteView(DeleteView, LoginRequiredMixin, UserPassesTestMixin):
model = Post
success_url = "/"
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
def test_func(self):
post = self.get_object()
if self.request.user == post.author:
return True
return False
def about(request):
return render(request, 'blog/about.html')
My models.py:
from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User
from django.urls import reverse
# Create your models here.
class Post(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
genere = models.CharField(max_length=50, default='')
def __str__(self):
return f'{self.title} by {self.author}'
def get_absolute_url(self):
return reverse('blog-home')
my urls.py url:
from django.urls import path
from .views import PostListView, PostDetailView, PostCreateView, PostUpdateView, PostDeleteView
from . import views
urlpatterns = [
path("", PostListView.as_view(), name="blog-home"),
path("about", views.about, name="blog-about"),
path("post/<int:pk>", PostDetailView.as_view(), name="blog-detail"),
path("post/new", PostCreateView.as_view(), name="blog-create"),
path("post/<int:pk>/update", PostUpdateView.as_view(), name="blog-update"),
path("post/<int:pk>/delete", PostDeleteView.as_view(), name="blog-delete"),
]
index.html
{% extends "blog/base.html" %}
{% load static %}
{% block content %}
<div class="row tm-row">
{% for post in posts %}
<article class="col-12 col-md-6 tm-post">
<hr class="tm-hr-primary">
<a href="{% url 'blog-detail' post.id %}" class="effect-lily tm-post-link tm-pt-60">
<div class="tm-post-link-inner">
<img src="{% static 'img/img-01.jpg' %}" alt="Image" class="img-fluid">
</div>
<span class="position-absolute tm-new-badge">New</span>
<h2 class="tm-pt-30 tm-color-primary tm-post-title">{{ post.title }}</h2>
</a>
<p class="tm-pt-30">
{{ post.content|safe|truncatewords:"30"|linebreaks }}
</p>
<div class="d-flex justify-content-between tm-pt-45">
<span class="tm-color-primary">{{ post.genere }}</span>
<span class="tm-color-primary">{{ post.date_posted|date:'N j,Y' }}</span>
</div>
<hr>
<div class="d-flex justify-content-between">
<span>36 comments</span>
<span>by {{ post.author }}</span>
</div>
</article>
{% endfor %}
</div>
{% endblock %}
post_detail.html:
{% extends 'blog/base.html' %}
{% load crispy_forms_tags %}
{% load static %}
{% block content %}
<div class="container">
<article class="col-12 col-md-6 tm-post">
<hr class="tm-hr-primary">
<a href="" class="effect-lily tm-post-link tm-pt-60">
<div class="tm-post-link-inner">
<img src="{% static 'img/img-01.jpg' %}" alt="Image" class="img-fluid">
</div>
<span class="position-absolute tm-new-badge">New</span>
<h2 class="tm-pt-30 tm-color-primary tm-post-title">{{ object.title }}</h2>
{% if object.author == user %}
<a class="btn btn-outline-danger" href="{% url 'blog-delete' object.id %}">Delete</a>
<a class="btn btn-outline-secondary" href="{% url 'blog-update' object.id %}">Update</a>
{% endif %}
</a>
<p class="tm-pt-30">
{{ object.content }}
</p>
<div class="d-flex justify-content-between tm-pt-45">
<span class="tm-color-primary">{{ object.genere }}</span>
<span class="tm-color-primary">{{ object.date_posted|date:'N j,Y' }}</span>
</div>
<hr>
<div class="d-flex justify-content-between">
<span>36 comments</span>
<span>by {{ object.author }}</span>
</div>
</article>
</div>
{% endblock %}
post_confirm_delete.html:
{% extends 'blog/base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<div class="container">
<form method="POST">
{% csrf_token %}
<h2>Are You Sure You Want To Delete "{{ object.title }}"</h2>
<button class="btn btn-outline-danger">Yes, I'm Sure</button>
<a class="btn btn-outline-secondary" href="{% url 'blog-detail' object.id %}">Cancel</a>
</form>
</div>
{% endblock %}
So, what I'm getting is that suppose 2 person jeff and ram are users so ram cannot update the posts of jeff and vice versa.
And if jeff views the post of ram, so he does not get the update and delete, so he cannot edit the post of ram but if jeff goes to "127.0.0.1:8000/post/9/delete" from "127.0.0.1:800/post/9",
So he get the confirm delete page and he can even delete his post.
How can I fix this bug in my project??????
you can use get_queryset() to restrict query in database
class PostUpdateView(UpdateView, LoginRequiredMixin, UserPassesTestMixin):
model = Post
success_url = "blog-home"
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
def get_queryset(self):
pk = self.kwargs.get(self.pk_url_kwarg)
return self.model.objects.filter(pk=pk,user=self.request.user)
I am a beginner in Django
I want to save a form data in database but i am not able to save, followed some tutorials also.
form.py:
from django.forms import ModelForm
from .models import *
class listsForm(ModelForm):
class Meta:
model = todo
fields = "__all__"
views.py:
from django.shortcuts import render
from .models import *
from .form import *
def index(request):
lists = todo.objects.all()
form = listsForm()
context = {
'lists':lists,
'form':form,
}
if request.method == 'POST':
form = listsForm(request.POST)
if form.is_valid:
form.save()
return render(request, 'index.html', context)
models.py:
from django.db import models
class todo(models.Model):
title = models.CharField(max_length=200)
description = models.TextField(null=True, blank=True)
created = models.DateField(auto_now_add=True)
def __str__(self):
return self.title
Why are you rendering listsForm?
Your form should be in the template not rendered!
In index.html, your form should looks like the following:
<form action="{% url 'create_todo' %}" method="POST">
{% csrf_token %}
<div class="form-group">
<label for="title">Title</label>
<input type="text" name="title" class="form-control" id="title" required></div>
<div class="form-group">
<label for="Description">Description</label>
<textarea name="description" class="form-control" id="description" ></textarea></div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
In views.py
def index(request):
return render(request, 'index.html')
def create_todo(request):
if request.method == 'POST':
form = listsForm(request.POST)
if form.is_valid():
form.save()
return redirect('index')
In urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index'),
path('create_todo/', views.create_todo, name='create_todo')
]
You will still need to render existed todos, preferably in another template.
So in views.py
def alltodos(request):
todos = Todo.objects.all()
return render(request, 'index.html', {'todos':todos})
In index.html, above form or after it, it doesn't matter, just for clear visibility
<div class="row justify-content-center mt-5">
<div class="col-md-10">
{% if todos %}
<div class="list-group">
{% for todo in todos %}
<a class="list-group-item list-group-item-action><b>{{ todo.title }}</b>{{ todo.description|truncatechars:30 }}{% endif %}</a>
{% endfor %}
</div>
{% else %}
<div class="text-center">
<h2>Looks like you don't have any todos!</h2>
<br>
</div>
{% endif %}
</div>
</div>
In urls.py add
path('todos', views.alltodos, name='alltodos'),
Advanced project of mine
I have find out why it was not working,
I was using <input type="button"> for submit button
but when I changed it to <button type="submit"> it works.
I want to create app with search and pagination. Pagination didn't work with ListView.
When I click on the link "next" I am moving from start page http://127.0.0.1:8001/ ---> to the http://127.0.0.1:8001/?city=2 but elements of the list did not change.
And next click to the "next" link did not changes the url ( http://127.0.0.1:8001/?city=2 --> http://127.0.0.1:8001/?city=2).
Could you help me to find error?
I think that error in *.html file, but can't find it
My code:
models.py
from django.db import models
class City(models.Model):
name = models.CharField(max_length=255)
state = models.CharField(max_length=255)
class Meta:
verbose_name_plural = "cities"
def __str__(self):
return self.name
urls.py
# cities/urls.py
from django.urls import path
from . import views
from .views import HomePageView, SearchResultsView
urlpatterns = [
path('search/', SearchResultsView.as_view(), name='search_results'),
path('', HomePageView.as_view(), name='home'),
path('city/<int:pk>/', views.city_detail, name='city_detail'),
]
views.py
from django.shortcuts import render
from django.views.generic import TemplateView, ListView
from .models import City
from django.db.models import Q
from django.shortcuts import render, get_object_or_404
class HomePageView(ListView):
model = City
template_name = 'cities/home.html'
paginate_by = 3
def city_detail(request, pk):
city = get_object_or_404(City, pk=pk)
return render(request, 'cities/city_detail.html', {'city': city})
class SearchResultsView(ListView):
model = City
template_name = 'cities/search_results.html'
def get_queryset(self): # new
query = self.request.GET.get('q')
object_list = City.objects.filter(
Q(name__icontains=query) | Q(state__icontains=query)
)
return object_list
home.html
<!-- templates/home.html -->
<h1>HomePage</h1>
<form action="{% url 'search_results' %}" method="get">
<input name="q" type="text" placeholder="Search...">
</form>
<ul>
{% for city in object_list %}
<li>
<h1>{{ city.name }}</h1>
</li>
{% endfor %}
</ul>
{{page_obj}}
<div class="pagination">
<span class="page-links">
{% if page_obj.has_previous %}
previous
{% endif %}
<span class="page-current">
Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.
</span>
{% if page_obj.has_next %}
next
{% endif %}
</span>
</div>
The standard name for the page query parameter is 'page' You should either change the name of the queryparameter, or render the template with the ?page= parameter.
Option 1: Changing the page_kwarg
You can change that by altering the page_kwarg attribute [Django-doc]:
class HomePageView(ListView):
model = City
template_name = 'cities/home.html'
paginate_by = 3
page_kwarg = 'city'
Option 2: Changing the template
It might be more sensical however to simply change the template, such that it uses page as parameter:
<div class="pagination">
<span class="page-links">
{% if page_obj.has_previous %}
previous
{% endif %}
<span class="page-current">
Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.
</span>
{% if page_obj.has_next %}
next
{% endif %}
</span>
</div>
I'm creating an application where a user can create their own posts, and other users can comment on the posts.
I have already tried retrieving comments from the database, and displaying them for that certain post, however this has been unsuccessful
Here is my code to tackle this problem:
views.py
def comment(request, pk):
form = CommentForm()
comments = Comment.objects.filter(post=pk)
if request.method == 'POST':
form = CommentForm(request.POST)
if form.is_valid():
comment = Comment()
comment.body = form.cleaned_data['body']
comment.user = request.user
comment.post = Post.objects.get(pk=pk)
comment.save()
return redirect('home')
return render(request, 'posts/comments.html')
else:
return render(request, 'posts/comments.html', {'error': 'Please submit valid data'})
else:
return render(request, 'posts/comments.html', {'form': form}, {'comments': comments})
comments.html
{% block content %}
<div class="container">
{% for com in comments.all %}
<p>{{ com.body }}</p>
<br>
{% endfor %}
{% if error %}
{{ error }}
<br>
<br>
{% endif %}
<br>
<br>
<br>
<br>
<br>
<form method="post">
<h2> Comment</h2>
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-primary">
Comment</button>
</form>
</div>
{% endblock %}
models.py
class Comment(models.Model):
body = models.CharField(max_length=130)
user = models.ForeignKey(User, on_delete=models.CASCADE)
post = models.ForeignKey(Post, on_delete=models.CASCADE)
def __str__(self):
return self.body
urls.py
path('create/', post_views.Create.as_view(), name='create'),
path('post/<int:pk>/', post_views.DetailPost.as_view(), name='detail'),
path('comment/<int:pk>/', post_views.comment, name='comment'),
urls.py for home
path('admin/', admin.site.urls),
#HOME
path('', post_views.home, name='home'),
This is expected to display a posts comments when a button is pressed to view the post, however the comments do not show. See this here