I' wanted to try Django framework and i tried the blog app tutorial. i tried to add a comment feature. i know these questions have been asked several times but couldn't find a solution to my problem.
I got the following error:
No Post matches the given query.
Thanks for your help. Here are the Model and all:
urls.py :
path('', PostListView.as_view(), name='blog-home'),
path('user/<str:username>/', UserPostListView.as_view(), name='user-posts'),
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('post/<int:pk>/comment/', PostCommentView.as_view(), name='post-comment'),
path('about/', views.about, name='blog-about'),
]
models.py:
class Post(models.Model):
title = models.CharField(max_length=50)
content = models.TextField()
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE) # many to one relation use foreign key
def __str__(self):
return self.title
#property
def get_comments(self):
return self.comment_content.all()
# return the url as string
def get_absolute_url(self):
return reverse('post-detail', kwargs={'pk': self.pk})
class Comment(models.Model):
content = models.TextField()
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
post = models.ForeignKey(Post, related_name='comment_content', on_delete=models.CASCADE)
def __str__(self):
return self.content
def get_absolute_url(self):
return reverse('comment-create', kwargs={'pk': self.pk})
forms.py:
class CommentForm(forms.ModelForm):
content=forms.Textarea()
class Meta:
model = Comment
fields=['content']
views.py:
class PostCommentView(LoginRequiredMixin, CreateView):
model = Comment
fields = ['content']
template_name = 'blog/comment_form.html'
success_url = '/'
def form_valid(self, form):
post = get_object_or_404(Post, id=self.kwargs.get('id'))
print(post.id)
form.instance.author = self.request.user
form.instance.post = post
return super().form_valid(form)
comment_form.htlm:
{% extends "blog/base.html" %}
{% load crispy_forms_filters %}
{% load crispy_forms_tags %}
{% block content %}
<div class="content-section">
<form method="POST">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">Comment tag</legend>
{{ form|crispy }}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">Post comment</button>
</div>
</form>
<div class="border-top pt-3">
<small class="text-muted">
Abort the Comment? <a class="ml-2" href="{% url 'blog-home' %}">Back to Main Page</a>
</small>
</div>
</div>
{% endblock content %}
'id' is standard primary key of a Django Model but not of the POST that is created with ModelForm etc.
I suppose you need to put a hidden field "id" in your form to get it sent with the POST request.
Try print(self.kwargs.get('id')) before the 'get_object...' and you will see if 'id' has some content.
Related
I'm struggling to set an initial value in a form instance based on the URL parameter in Django 3.0.
I have a Claim model:
# models.py
class Claim(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE)
text = models.TextField()
date_added = models.DateTimeField(default=timezone.now)
member = models.ForeignKey(User, on_delete=models.CASCADE)
I have a NewClaimForm based on ModelForm:
# forms.py
class NewClaimForm(forms.ModelForm):
class Meta:
model = Claim
fields = ['product', 'text']
I have a NewClaimView based on CreateView:
# views.py
class NewClaimView(LoginRequiredMixin, CreateView):
model = Claim
form_class = NewClaimForm
template_name = 'portal/new_claim.html'
def form_valid(self, form):
form.instance.member = self.request.user
return super(NewClaimView, self).form_valid(form)
And using the following template fragment on the index page...
# index.html
<div class="card-deck">
{% for product in products %}
<div class="card text-center">
<div class="card-header">
<h5 class="card-title text-primary">{{ product }}</h5>
</div>
<div class="card-body">
<ol class="card-text text-left">
<li>Fill in the {{ product }} form</li>
<li>Attach your medical records</li>
<li>Get your claim reviewed within 48 hours</li>
</ol>
Online Form
</div>
</div>
{% endfor %}
</div>
...I pass the product_id parameter to the URL:
# urls.py
app_name = 'portal'
urlpatterns = [
path('new_claim/<int:product_id>/', NewClaimView.as_view(), name='new_claim_product'),
]
And lastly, this is what my new_claim template looks like:
# new_claim.html
{% extends "portal/base.html" %}
{% load bootstrap4 %}
{% block content %}
<p>Submit a new claim</p>
<form action="{% url 'portal:new_claim' %}" method='post' class="form" enctype="multipart/form-data">
{% csrf_token %}
{% bootstrap_form form %}
{% buttons %}
<button name="submit">Submit claim</button>
{% endbuttons %}
</form>
{% endblock content %}
I would like to now use the product_id to set the initial value of the product field in the form instance according to product_id. How can I achieve this?
Figured out how to do this by modifying the get method for my class-based view:
# views.py
class NewClaimView(LoginRequiredMixin, CreateView):
model = Claim
form_class = NewClaimForm
template_name = 'portal/new_claim.html'
def get(self, request, product_id=None, *args, **kwargs):
form = self.form_class(initial={'product': product_id})
return render(request, self.template_name, {'form': form})
def form_valid(self, form):
form.instance.member = self.request.user
return super(NewClaimView, self).form_valid(form)
Here's a link to the relevant documentation.
Is this an optimal way to solve this?
Do I need the *args and **kwargs in the modified get method? I'm not using them in my code but perhaps it would be useful to keep them there for other purposes in the future?
I'm making a simple blog app with comments on a 'posts detail view' page, but I'm getting a 404 error saying "No comment found matching the query" whenever I try submitting my comment. Everything else in the app works except for the comments. I'm new to django and am making this site to learn, would appreciate any help!
Views.py
class PostDetailView(DetailView):
model = Post
fields = ['content']
class CommentCreateView(LoginRequiredMixin, CreateView):
model = Comment
fields = ['content']
template_name = 'blog/comment.html'
def form_valid(self, form):
post = self.get_object()
form.instance.author = self.request.user
return super().form_valid(form)
models.py
class Comment(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='comments')
author = models.ForeignKey(User, on_delete=models.CASCADE)
content = models.TextField()
date_posted = models.DateTimeField(default=timezone.now)
class Meta:
ordering = ['-date_posted']
def __str__(self):
return f'Comment {self.content} by {self.author.username}'
def get_absolute_url(self):
return reverse('comment', kwargs={'pk': self.pk})
urls.py
from django.urls import path
from .views import (
PostListView,
PostDetailView,
PostCreateView,
PostUpdateView,
PostDeleteView,
UserPostListView,
CommentCreateView
)
from . import views
urlpatterns = [
path('', PostListView.as_view(), name='blog-home'),
path('post/comment/<int:pk>/', CommentCreateView.as_view(), name='create'),
path('user/<str:username>', UserPostListView.as_view(), name='user-posts'),
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='blog-about'),
]
comments.html This is the form. It's supposed to redirect to a different form to comment then back to post detail view
{% extends "blog/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<div class="content-section">
<form method="POST">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">Comment</legend>
{{ form|crispy }}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">Post</button>
</div>
</form>
</div>
{% endblock content %}
I am developing a crud application using django,using Class based views, Create, retrieve, details functions are working properly but update function don't here is my code snippets
kindly dont mark my question negative, i'm a beginner.
ERROR
views.py
class Update(UpdateView):
fields = ('age', 'email')
models = models.CreateUser
urls.py
app_name='main'
urlpatterns = [
url(r'^create/$', views.Create.as_view(), name='create'),
url(r'^(?P<pk>\d+)/$', views.Details.as_view(), name='detail'),
url(r'^update/(?P<pk>\d+)/$', views.Update.as_view(), name='update'),
url(r'', views.UsersList.as_view(), name='allUsers'),
]
models.py
class CreateUser(models.Model):
name = models.CharField(max_length=256)
age = models.IntegerField()
email = models.CharField(max_length=256)
gender = models.CharField(max_length=50)
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('main:create', kwargs={'pk': self.pk})
From details page i'm calling that view on a button
<!DOCTYPE html>
{% extends 'mainApp/base.html' %}
{% block body_block %}
<div class="jumbotron container">
<h1>Welcome to the Users detail page</h1>
<h2>User Details</h2>
<p>Name : {{user_details.name}}</p>
<p>Age: {{user_details.age}}</p>
<p>Email: {{user_details.email}}</p>
<p>Gender: {{user_details.gender}}</p>
<p><a class="btn btn-warning" href="{% url 'main:update' pk=user_details.pk %}">Update this</a></p>
</div>
{% endblock %}
This is for a library management web app, I need to filter a specific book object by it's id from a BookIssue object and make it as ISSUED when I click on issue button.
Here Post model have details of book and BookIssue have details of Library Member to borrow book.
When I click on Issue in html, it will go class BookIssueView, fromviews.py I need to change the value of issued field of Post model to True
See post = Post.objects.filter(id=self.request.GET.get('id')).update(issued=True) in views.py
Here I need to get the specific book that I selected by it's id.
How can I implement it?
models.py
class Post(models.Model):
title = models.CharField(max_length=100)
book_author = models.CharField(default="",max_length=100)
publisher = models.CharField(default="",max_length=100)
content = models.TextField(max_length=200)
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
issued = models.BooleanField(default=False)
issued_to = models.CharField(default="",max_length=100,null=False)
issue_to_phone_number = models.CharField(default="",max_length=10)
def __str__(self):
return [self.title,self.id]
def get_absolute_url(self):
return reverse('post-detail', kwargs={'pk' : self.pk})
class BookIssue(models.Model):
issue_name = models.CharField(max_length=100,null=False)
issue_email = models.EmailField(max_length=254)
issue_phone_number = models.CharField(default="",max_length=10)
issue_address = models.TextField(max_length=300)
issued_book = models.ManyToManyField(Post,default="")
def __str__(self):
return self.issue_name
def get_absolute_url(self):
return reverse('blog-home')
views.py
class BookIssueView(LoginRequiredMixin,CreateView,Post):
model = BookIssue
fields = ['issue_name','issue_email','issue_phone_number','issue_address']
def form_valid(self, form):
post = Post.objects.filter(id=self.request.GET.get('id')).update(issued=True)
form.instance.author = self.request.user
return super().form_valid(form)
Template
bookissue_form.html
{% extends "blog/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
<div class="content-section">
<form method="post">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">Issue Book</legend>
{{ form|crispy }}
</fieldset>
<div class="form-group">
<button class="btn btn-success" type="submit" name="button">Issue</button>
<button class="btn btn-danger" type="submit" name="button">Cancel</button>
</div>
</form>
</div>
{% endblock %}
urls.py
from django.urls import path
from . import views
from .views import (PostListView,
PostDetailView,
PostCreateView,
PostUpdateView,
PostDeleteView,
BookIssueView,
BookReturnView)
urlpatterns = [
# path('',views.home, name='blog-home'),
path('',PostListView.as_view(), name='blog-home'),
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('post/<int:pk>/issue/',BookIssueView.as_view(), name='book-issue'),
path('post/<int:pk>/return/',BookReturnView.as_view(), name='book-return'),
path('about/',views.about, name='blog-about'),
]
The id is not in request.GET, it is in the pk kwarg of the URL.
Also, you don't seem to be doing anything to associate the Post with the BookIssue.
post = Post.objects.get(id=self.kwargs["pk"])
post.issued=True
post.save()
response = super().form_valid(form)
form.instance.issued_book.add(post)
return response
am using django 2.0 and here is the problem
Page not found (404)
Request Method: GET
Request URL: http://localhost:8000/blog/post-detail/
Raised by: blog.views.post_detail
No Post matches the given query.
here is the blog/urls
from django.urls import path,include
from .import views
urlpatterns = [
path('blog/',views.post_list,name="post_list"),
path('blog/post-detail/',views.post_detail,name="post_detail"),
]
and views.py
from django.shortcuts import render,get_object_or_404
from.models import Post
# Create your views here.
def post_list(request):
object_list=Post.objects.all()
context={
'object_list': object_list,
}
return render(request,"blog.html",context)
def post_detail(request,slug=None):
post=get_object_or_404(Post,slug=slug)
context={
'post':post,
}
return render(request,"post_detail.html",context)
and the post_detail.html
{% extends "base.html" %}
{% load static %}
{% block seo_title %}{% endblock %}
{% block seo_description %}{% endblock %}
{% block Content %}
<article>
<div class="embed-responsive embed-responsive-16by9">
<img src="images/blog1.jpg" alt="" />
</div>
<div class="post-content">
<h2>{{post.title}}</h2>
<div>
{{post.created}} Author {{Post.user}}
<hr/>
<p>{{post.body}}</p>
</article>
{% endblock Content %}
CAN ANYONE HELP ON THIS THE ONLY PROBLEM I SEE THAT SLUG THING I MUST HAVE CONFUSED SOMEWHERE
blog.html
<!-- Blog -->
<div class="blog">
<div class="row">
<div class="col-sm-8">
<!-- Blog Post-->
{% for obj in object_list %}
{% if obj.status == 'Published' %}
<article>
<div class="embed-responsive embed-responsive-16by9">
<img src="images/blog1.jpg" alt="" />
</div>
<div class="post-content">
<h2>{{obj.title}}</h2>
<div>
{{obj.created}} Author {{obj.user}}
<hr/>
<p>{{obj.body}}</p>
<a class="mtr-btn button-navy ripple" href= "{% url 'post_detail' slug= post.slug %}">Continue reading →</a><br>
</div>
</article>
{% endif %}
{% endfor %}
The view post_detail(request,slug=None) is to view details about a post. So your URL pattern is incorrect:
path('blog/post-detail/<slug:slug>',views.post_detail,name="post_detail"),
To call it in templates, the simpler and correct way to do is:
<a class="mtr-btn button-navy ripple" href= "{% url 'post_detail' obj.slug %}">Continue reading →</a><br>
</div>
#FOLLOW THIS PROCEDURE.I HOPE IT HELPS YOU OR ANY ONE ELSE IN THE FUTURE
# At blog/urls.py
from django.urls import path
from .views import (post_list, post_detail)
urlspatterns = [
path('blog/', post_list, name='post-list'),
path('<str:slug>/blog/post-detail/', post_detail, name='post-detail'),
]
#At blog/views.py
from django.shortcuts import render, get_object_or_404
from .models import Post
def post_list(request):
posts = Post.objects.all()
template_name = blog/post_list.html
context = {'posts':posts}
return render(request, template_name, context)
def post_detail(request, slug):
posts = get_object_or_404(Post, slug=slug)
template_name = blog/post_detail.html
context = {'posts':posts}
return render(request, template_name, context)
# At the template/blog/post_list.html
{% block content %}
{% for post in posts %}
<article>
<div>
<small>{{ post.created_on|date:"F d, Y" }}</small>
<h2>{{ post.title }}</h2>
<p >{{ post.body }}</p>
</div>
</article>
{% endfor %}
{% endblock content %}
# At template/blog/post_detail.html
<article>
<div>
<small>{{ posts.created_on|date:"F d, Y" }}</small>
<h2>{{ posts.title }}</h2>
<p>{{ posts.body }}</p>
</div>
</article>
#The above code should fix the the issue properly.
If your a following Django 3 By Example Book can check this soltuion because I had the same problem.
Book teach how to create Post with a slug attribute with
models.SlugField and unique_for_date='pusblish' condition.
Then you add some posts from admin site.
Then you add some posts from admin site but then in admin.py book teach how to edit the register with
prepopulated_fields = {'sulg':('title',)}.
Finally, book teach you how to edit posts.
This is a problem because never
going to find a post created. So, the solution for me was delete
posts and the create new ones.
here my code:
models.py
from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User
from django.urls import reverse
class PublishedManager(models.Manager):
def get_queryset(self):
return super(PublishedManager, self).get_queryset().filter(status='published')
class Post(models.Model):
STATUS_CHOICES = (
('draft', 'Draft'),
('published', 'Published'),
)
title = models.CharField(max_length=250)
slug = models.SlugField(max_length=250, unique_for_date='publish')
author = models.ForeignKey(User,
on_delete=models.CASCADE,
related_name='blog_posts')
body = models.TextField()
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() # The default manager.
published = PublishedManager() # Our custom manager.
class Meta:
ordering = ('-publish',)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('blog:post_detail',
args=[self.publish.year,
self.publish.month,
self.publish.day, self.slug])
admin.py
from django.contrib import admin
from .models import Post
#admin.register(Post)
class PostAdmin(admin.ModelAdmin):
list_display = ('title', 'slug', 'author', 'publish', 'status')
list_filter = ('status', 'created', 'publish', 'author')
search_fields = ('title', 'body')
prepopulated_fields = {'slug': ('title',)}
raw_id_fields = ('author',)
date_hierarchy = 'publish'
ordering = ('status', 'publish')
views.py
from django.shortcuts import render, get_object_or_404
# another views...
def post_detail(request, year, month, day, post):
post = get_object_or_404(Post, slug=post,
status='published',
publish__year=year,
publish__month=month,
publish__day=day)
return render(request,
'blog/post/detail.html',
{'post': post})
blog/urls.py
from django.urls import path
from . import views
app_name = 'blog'
urlpatterns = [
# post views
path('', views.PostListView.as_view(), name='post_list'),
path('<int:year>/<int:month>/<int:day>/<slug:post>/',
views.post_detail,
name='post_detail'),
]
my_site/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('blog/', include('blog.urls', namespace='blog')),
]