No post found matching the query - django

views.py
class PostDetailView(DetailView):
model = Post
template_name = 'blog/post_detail.html'
urls.py
path('post/<int:pk>/', PostDetailView.as_view(), name='post-detail')
When I go to 127.0.0.1:8000/post/1, it says no post found matching the query
Screenshot

In Views.py
class PostDetailView(DetailView):
model = Post
template_name = 'blog/post_detail.html'
lookup_field = 'id'
def get_object(self, *args, **kwargs):
kwargs = self.kwargs
kw_id = kwargs.get('id')
return Post.objects.get(id=kw_id)

Related

How to allow only the author of the article in the Django UpdateView to access the article update page?

How to allow only the author of the article in the Django UpdateView to access the article update page?
#views.py
class ArticleUpdate(LoginRequiredMixin, UpdateView):
model = Article
template_name = 'articles/update_view.html'
context_object_name = 'article_update'
form_class = ArticleForm
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['securities_types_list'] = StocksETFsBonds.objects.all()
context['tags_list'] = Tag.objects.annotate(articles_quantiy=Count('taggit_taggeditem_items')).order_by(
'-articles_quantiy')[:10]
return context
Implement get_object and check if the requesting user is the author of the article (you did not provide the details of your models, so i will presume that your Article model has a author field):
class ArticleUpdate(LoginRequiredMixin, UpdateView):
model = Article
template_name = 'articles/update_view.html'
context_object_name = 'article_update'
form_class = ArticleForm
def get_object(self, *args, **kwargs):
obj = super().get_object(*args, **kwargs)
if obj.author != self.request.user:
raise PermissionDenied()
return obj
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['securities_types_list'] = StocksETFsBonds.objects.all()
context['tags_list'] = Tag.objects.annotate(articles_quantiy=Count('taggit_taggeditem_items')).order_by(
'-articles_quantiy')[:10]
return context
You can also implement ArticleUpdate.get_queryset (if the requesting user is not the author of the article they receive a 404 error):
def get_queryset(self, *args, **kwargs):
return Article.objects.filter(author=self.request.user)

how to call and use my pk given in urls in a class based view?

I have this code in urls
from .views import testview
urlpatterns = [
path('test/<pk>', testview.as_view(), name='test')
]
And this is my view :
class testview(FormView):
template_name = 'test/test.html'
form_class = ExampleForm
def form_valid(self, form):
cl = form.cleaned_data
book= Book(user_id='pk',
book = cl['book'],
price = book.price )
return create_book(self.request, book)
So how can I take that pk in the urls and use it inside the view?
You can use self.kwargs to access the URL parameters...
For example:
class testview(FormView):
template_name = 'test/test.html'
form_class = ExampleForm
def form_valid(self, form):
pk_from_url = self.kwargs['pk']
# rest of your code
You can get the object during the dispatch for the view and the url param is added to the kwargs for the view;
class TestFormView(FormView):
template_name = 'test/test.html'
form_class = ExampleForm
book = None
def dispatch(self, request, *args, **kwargs):
self.book = get_object_or_404(
Book, pk=kwargs.get('pk')
)
return super().dispatch(request, *args, **kwargs)
Reading these docs may be useful; https://docs.djangoproject.com/en/3.1/ref/class-based-views/base/#django.views.generic.base.View.dispatch

Django Improved UpdateView?

I have this UpDateView class and I need just author of article can edit the blog .I had the solution for the CreateView class(using def Form_valid) but it doesn't work for UpdateView class :::
class ArticleUpdateView(LoginRequiredMixin,UpdateView):
model = models.Article
template_name = 'article_edit.html'
fields = ['title','body']
login_url = 'login'
class ArticleCreateView(LoginRequiredMixin,CreateView):
model = models.Article
template_name = 'article_new.html'
fields = ['title','body',]
login_url='login'
def form_valid(self,form):
form.instance.author = self.request.user
return super().form_valid(form)
You can override the get_object method in your view class:
class ArticleUpdateView(LoginRequiredMixin,UpdateView):
model = models.Article
template_name = 'article_edit.html'
fields = ['title','body']
login_url = 'login'
def get_object(self, *args, **kwargs):
article = super().get_object(*args, **kwargs)
if article.author != self.request.user:
raise PermissionDenied('You should be the author of this article.')
return article

django authorization in class-based view

I'm trying to restrict access of CRUD pages to the owners, but I can't find the class-based view equivalent of "if request.user != post.author raise Http404". Thx for your time.
models.py
class Article(models.Model):
title = models.CharField(max_length=255)
body = models.TextField()
date = models.DateTimeField(auto_now_add=True)
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('article_detail', args=[str(self.id)])
views.py
class ArticleUpdateView(LoginRequiredMixin, UpdateView):
model = Article
fields = ['title', 'body']
template_name = 'article_edit.html'
login_url = 'login'
I tried the following (and many other combination arround those lines), but it isn't working.
def get(self, request, *args, **kwargs):
if self.request.user == self.obj.author:
raise Http404()
Youn can do something like this:-
class ArticleUpdateView(LoginRequiredMixin, UpdateView):
model = Article
fields = ['title', 'body']
template_name = 'article_edit.html'
login_url = 'login'
def get(self, request, *args, **kwargs):
self.obj = self.get_object()
if self.request.user != self.obj.author:
raise Http404()
return super(ArticleUpdateView, self).get(request, *args, **kwargs)
I think you can override the get_queryset method to achieve this. For example:
class ArticleUpdateView(...):
def get_queryset(self):
queryset = super(ArticleUpdateView, self).get_queryset()
return queryset.filter(author = self.request.user)
So, when a user tries to update an post which is not created by him, then he will not be able to get it because will not be able find the post object in Queryset provided by get_queryset method. For details, please SingleObjectMixin which is later sub-classed by UpdateView. FYI you don't need to override the get method for this implementation.

Django - DetailView with FormMixin and initial

I have DetaiView for my post and I want to use a form in this view so I decided to use DetailView with FormMixin. I need to set some initial to this form and I don't know how to do it. Here is my code:
models.py
class Comment(models.Model):
post = models.ForeignKey(Post, related_name="comments", on_delete=models.CASCADE)
name = models.CharField("Nick", max_length=80)
email = models.EmailField()
body = models.TextField("Body")
created = models.DateTimeField("created", auto_now_add=True)
updated = models.DateTimeField("Updated", auto_now=True)
forms.py
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = (
"name",
"email",
"body"
)
views.py
class PostDetailView(FormMixin, DetailView):
model = Post
form_class = CommentForm
template_name = "newspaper/post-detail.html"
def get_success_url(self):
return reverse("post-detail", kwargs={"slug": self.object.slug})
def get_context_data(self, **kwargs):
context = super(PostDetailView, self).get_context_data(**kwargs)
context["form"] = self.get_form()
return context
def post(self, request, *args, **kwargs):
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):
return super().form_valid(form)
So I want to post in CommentForm to post of this DetailView. I hope you understand :D.
Thanks in advance for the help!
With FormMixin you can specify form's initial using initial attribute:
class PostDetailView(FormMixin, DetailView):
model = Post
form_class = CommentForm
template_name = "newspaper/post-detail.html"
initial={'name': 'John'}
Or get_initial method:
def get_initial(self):
return {"post": self.get_object() }