I want to get all posts that a user send. For example user: admin, it will show admin's posts. I write some code, but probably I made a mistake and I got an error.
The error that I get:
AttributeError at /index_page/
'WSGIRequest' object has no attribute 'models'
Here is my code:
views.py
def index_page(request):
logged_in_user = request.models.author
logged_in_user_posts = Post.objects.filter(author=user)
return render(request, 'blog/post_list.html', {'posts': logged_in_user_posts})
models.py
class Post(models.Model):
author = models.ForeignKey('auth.User', on_delete=models.CASCADE)
title = models.CharField(max_length=200)
text = RichTextField()
created_date = models.DateTimeField(
default=timezone.now)
published_date = models.DateTimeField(
blank=True, null=True)
def publish(self):
self.published_date = timezone.now()
self.save()
def __str__(self):
return self.title
post_list.html
<div>
{% for post in posts %}
Username: {{ post.author.username }}
Post: {{ post.text }}
<br>
{% endfor %}
Where is my mistake?
The error already hints to the line:
logged_in_user = request.models.author
A request object has no models attribute. It has a .user attribute that specifies the logged in user, so you can use:
logged_in_user = request.user
There is another error: you use Post.objects.filter(user=user), but there is no user variable either, there is a logged_in_user variable. So you can fix the view with:
def index_page(request):
logged_in_user_posts = Post.objects.filter(author=request.user)
return render(request, 'blog/post_list.html', {'posts': logged_in_user_posts})
Extra notes:
since you need a user, it makes sense to decorate the function with the login_required decorator [Django-doc]; and
Since Django allows you to change the User model, it might be beneficial to use the standard way to refer to the user model [Django-doc]. If you later change your mind and implement another user model, the creating migrations will automatically let the relations refer to the new model.
The two comments above are not strictly necessary to let it work. But it is what I think are good practices when developing Django apps (although of course these can be a bit "opinion-based").
The issue is in your view, request object does not contain your models.The view should be like below,
def index_page(request):
logged_in_user = request.user
logged_in_user_posts = Post.objects.filter(author=logged_in_user)
return render(request, 'blog/post_list.html', {'posts': logged_in_user_posts})
I am answering a little bit late , But may be it help someone later . you can use class-based views . In your case
views.py :
class UserPostListView(ListView):
model = Post
template_name = 'app_name/template_name.html'
context_object_name = 'posts'
def get_queryset(self):
user = get_object_or_404(User,username=self.kwargs.get('username'))
return Post.objects.filter(author=user)
and in your urls.py :
path('user/<str:username>', views.UserPostListView.as_view(), name='user-posts'),
and then in your template :
{% block content%}
<h1> My files </h1>
{% for post in posts %}
{% endfor %}
{% endblock %}
Related
I want to add like unlike feature to my blog site, everythin is okay there, like and unlike objects are being created.. But I'm getting NoReverseMatch when I'm clicking the Like and Unlike..and the problem is I can't figure it out why I'm getting this...my models.py, views.py, urls.py, blog_page.html...all are attatched here..
plz try help me solve this
**models.py**
from email.policy import default
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Blog(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(max_length=200, verbose_name="Put a Title")
blog_content = models.TextField(verbose_name="What is on your mind")
blog_image = models.ImageField(upload_to="blog_images", default = "/default.png")
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
def __str__(self):
return self.title
class Comment(models.Model):
blog = models.ForeignKey(Blog, on_delete=models.CASCADE, related_name = "blog_comment" )
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name = "user_comment")
comment = models.TextField()
comment_date = models.DateField(auto_now_add=True)
def __str__(self):
return self.comment
class Like(models.Model):
blog = models.ForeignKey(Blog, on_delete=models.CASCADE, related_name = "blog_liked")
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name = "user_liked")
class Unlike(models.Model):
blog = models.ForeignKey(Blog, on_delete=models.CASCADE, related_name = "blog_unliked")
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name = "user_unliked")
**views.py**
from django.shortcuts import render
from . models import Blog, Comment, Like, Unlike
# Create your views here.
def home(request):
blogs = Blog.objects.all()
context = {'blogs': blogs}
return render(request, 'blog_app/home.html', context)
def blog_view(request, pk):
blog = Blog.objects.get(id=pk)
context = {"blog": blog}
return render(request, 'blog_app/blog_page.html', context)
def like(request, pk):
blog = Blog.objects.get(id=pk)
user = request.user
liked, like = Like.objects.get_or_create(blog=blog, user=user)
context = {"liked" : liked}
return render(request, "blog_app/blog_page.html", context)
def unlike(request, pk):
blog = Blog.objects.get(id=pk)
user = request.user
unliked, unlike = Unlike.objects.get_or_create(blog=blog, user=user)
context = {"unliked" : unliked}
return render(request, "blog_app/blog_page.html", context)
**urls.py**
from django.urls import path
from blog_app import views
urlpatterns = [
path("", views.home, name='home'),
path("blog_page/<str:pk>/", views.blog_view, name='blog_page'),
path("like/<str:pk>/", views.like, name="like"),
path("unlike/<str:pk>/", views.unlike, name="unlike"),
]
**blog_page.html**
{% extends "main.html" %}
{% load static %}
{% block content %}
<div style="text-align:center;">
<h2>{{blog.title}}</h2>
<img src="{{blog.blog_image.url}}" alt="" width="630px" height="300px">
</div>
<div style="text-align:center;">
{{blog.blog_content|linebreaks}}
</div>
{% if liked %}
<h4>Unlike</h4>
{% else %}
<h4> Like </h4>
{% endif %}
{% endblock content %}
Your URLs are expecting a string value for blog_id but you are passing them an int in {% url 'unlike' blog.id %} Try changing your URL file to expect an int, and you should be able to look it up more successfully.
path("blog_page/<int:pk>/", views.blog_view, name='blog_page'),
path("like/<int:pk>/", views.like, name="like"),
path("unlike/<int:pk>/", views.unlike, name="unlike"),
Also, as you are using the same page template for the like and unlike view, you will need to pass the blog element in the context again to make links work on those pages, eg,
context = {"liked" : liked, "blog", blog}
Why my custom template tag doesn't work?
templatetags.py:
from django import template
from ..models import User
register = template.Library()
#register.inclusion_tag('main/post_detail.html', takes_context=True)
def get_user_liked_posts():
request = context['request']
user = User.objects.get(username=request.user.username)
liked_posts = []
for post in user.liked_posts.all():
liked_posts.append(post.name)
return {'liked_posts': liked_posts}
post_detail.html:
{% load static %}
{% load templatetags %}
<nav class="blog-pagination" aria-label="Pagination">
<span id="likes_count">{{ post.likes_count }}</span>
{% if post.name in liked_posts %}
<button id="like_button" class="btn btn-outline-primary btn-primary text-
white">Like</button>
{% else %}
<button id="like_button" class="btn btn-outline-primary">Like</button>
{% endif %}
</nav>
views.py:
class PostDetailView(DetailView):
model = Post
slug_field = 'url'
class LikePostView(View):
def post(self, request, slug):
post = Post.objects.get(id=request.POST['id'])
user = User.objects.get(username=request.user.username)
if request.POST['like'] == 'true':
post.likes_count += 1
user.liked_posts.add(post)
else:
post.likes_count -= 1
user.liked_posts.remove(post)
user.save()
post.save()
return redirect('post_detail', slug)
models.py:
class Post(models.Model):
"""
This is post model
"""
name = models.CharField(max_length=150, blank=False)
article = models.TextField(blank=False)
image = models.ImageField(upload_to='uploads/', blank=True)
likes_count = models.IntegerField(default=0)
url = models.CharField(max_length=150, blank=False)
def get_absolute_url(self):
return reverse('post_detail', kwargs={'slug': self.url})
I want to check if the post is in the liked post of the current user, but it doesn't work.
It doesn't show any errors, it just does nothing.
User in my app must like or unlike posts. In models, I have many to many relationship user with the post. I want to check if the user likes this post
The problem is that you don't even use the template tag, furthermore this is not even needed as you can simply write something like so in the template:
{% if post in request.user.liked_posts.all %}
A Liked post
{% else %}
Not a liked post
{% endif %}
But this is a bit inefficient as we are getting all the posts liked by the user just to check if they like some post. Also if this were in a loop with multiple posts we would be making a query for each post.
Instead we can simply annotate whether the user likes a post in the view itself using an Exists subquery [Django docs] on the through model of the many to many:
from django.db.models import Exists, OuterRef
class PostDetailView(DetailView):
model = Post
slug_field = 'url'
def get_queryset(self):
queryset = super().get_queryset()
queryset = queryset.annotate(
liked_by_user=Exists(
User.liked_posts.through.objects.filter(
post_id=OuterRef("pk"),
user_id=self.request.user.id
)
)
)
return queryset
Now in the template we can simply write:
{% if post.liked_by_user %}
A Liked post
{% else %}
Not a liked post
{% endif %}
Note: Your way of saving the count similarly can simply be turned into an annotation using the Count aggregation function [Django
docs].
Generally one should not store calculated attributes in a column since
that might lead to inconsistent data when updating and forgetting to update the related count, etc.
Can anyone advise on how to query the `total_likes of a post to be shown in my HTML, I tried, but was given this error:
Page not found (404)
No BlogPost matches the given query.
THANK YOU!
I think it might be the way I am querying and linking the blog post with the likes but I'm not sure why I'm wrong and I don't know how to modify it despite trying for a few hours.
views.py
def home_feed_view(request, **kwargs):
context = {}
blog_posts = sorted(BlogPost.objects.all(), key= attrgetter('date_updated'), reverse = True)
blog_post = get_object_or_404(BlogPost, slug=request.POST.get('blog_post_slug'))
total_likes = blog_post.total_likes()
liked = False
if blog_post.likes.filter(id=request.user.id).exists():
liked = True
context['blog_posts'] = blog_posts
context['blog_post'] = blog_post
context['total_likes'] = total_likes
return render(request, "HomeFeed/snippets/home.html", context)
def LikeView(request, slug):
context = {}
post = get_object_or_404(BlogPost, slug=slug)
liked = False
if post.likes.filter(id=request.user.id).exists():
post.likes.remove(request.user)
liked = False
else:
post.likes.add(request.user)
liked = True
return redirect('HomeFeed:detail', slug=slug)
.html
{% for post in blog_posts %}
<td class="table-primary">
<form action="{% url 'HomeFeed:like_post' post.slug %}" method="POST">
{% csrf_token %}
<button type="submit" name="blog_post_slug" value="{{post.slug}}" class='btn btn-primary btn-sm'>
Like
</button>
{{ total_likes }} Likes
</form>
</td>
{% endfor %}
models.py
class BlogPost(models.Model):
body = models.TextField(max_length=5000, null=False, blank=False)
likes = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name='blog_posts', blank=True)
slug = models.SlugField(blank=True, unique=True)
def total_likes(self):
return self.likes.count()
urls.py
from django.urls import path
from HomeFeed.views import(
home_feed_view,
LikeView,
)
urlpatterns = [
path('', home_feed_view , name= "main"),
path('<slug>/like/', LikeView, name='like_post'),
]
The exception: Page not found (404) No BlogPost matches the given query. is being raised by get_object_or_404 as it does exactly what the name says. If the BlogPost with the supplied slug in any of the views doesn't exist in the database, Django will raise an Http404 exception as you're witnessing.
Now, since we don't know the structure of your BlogPost model, I can't really tell you where to change, all I can tell you is you need to make sure, the slug is a unique field on each BlogPost instance, othwerwise your code is working as one would expect.
EDIT
I had not seen the BlogPost model, my bad, but the information is still relavant a BlogPost with such a slug does not exist. So do a manual check, see what the slug arrives in the view(s) as, and then check manually either in DB or in your shell.
I have a problem where I can't use my Django variables inside Html
This is my code :
models.py
from django.db import models
from django.urls import reverse
# Create your models here.
class Post(models.Model):
title = models.CharField(max_length=255)
slug = models.SlugField(max_length=255, unique=True)
created = models.DateTimeField(auto_now_add=True)
content = models.TextField(default="---")
H_price = models.IntegerField(default=0)
L_price = models.IntegerField(default=0)
remaining = models.IntegerField(default=0)
original_price = models.IntegerField(default=0)
Ended = models.BooleanField(default=False)
Published = models.BooleanField(default=True)
class Meta:
ordering = ['-created']
def __unicode__(self):
return u'%s'% self.title
def get_absolute_url(self):
return reverse('Products.views.post', args=[self.slug])
Views.py
from django.shortcuts import render
from .models import Post
# Create your views here.
def index(request):
posts=Post.objects.all()
return render(request, 'Index.html', {"Posts": posts})
def post(request):
return
Index.html
<h1>This is just a title </h1>
{% for post in posts %}
<div>
<h3> {{ post.title }}</h3>
<h3> {{ post.content }}</h3>
</div>
{% endfor %}
I know this isn't the best way to do Html but the goal is just to get it to work then I will style it with css and make everything Look Clean When i run the server i only get "this is just a title"
Any suggestions to help me fix it will be apreciated
Note that I am a begginer in django
Variables in the Django template language are case sensitive. You use {% for post in posts %} in your template, therefore you need to use posts not Posts in your view.
return render(request, 'Index.html', {"posts": posts})
I'm trying to display specific content/data based on a logged in user. I want to display only their info. This is what I've tried but I can't get it to work.
views.py
class DemoView(TemplateView):
template_name = 'demographics/demographics.html'
def get(self, request):
demos = Demographics.objects.filter(user=request.user)
context = {
'demos': demos,
}
return render(request, self.template_name, context)
models.py
class Demographics(models.Model):
first_name = models.CharField(max_length=50, null=True)
middle_name = models.CharField(max_length=50, null=True)
last_name = models.CharField(max_length=50, null=True)
user = models.ForeignKey(User, null=True)
HTML
{% if demos %}
{% for demographics in demos %}
<p>First Name</p> {{ demographics.first_name }}
{% endfor %}
{% else %}
<h3>you dont have demo yet</h3>
{% endif %}
I feel like I'm close. What am I missing?
I think the issue may be that you are filtering out all answers from your queryset because the content of request.user is not quite a match for a 'user' object. I don't know why they wouldn't match, but in my code I use:
User.objects.get(username = request.user.username)
I think debugging using pdb will help why the get is not rendering the data properly but if you know how django templateview class handles the context data, you have to modify the code a bit. Here I used get_context_data instead of get and hope this time it will work.
class DemoView(TemplateView):
template_name = 'demographics/demographics.html'
def get_context_data(self, **kwargs):
context = super(DemoView, self).get_context_data(**kwargs)
demos = Demographics.objects.filter(user=self.request.user)
context['demos'] = demos
return context
Also you can check if the table Demographics has the data for the selected user.
full Answer:
Views.py
class DemoView(TemplateView):
template_name = 'demographics/demographics.html'
def get(self, request, *args, **kwargs):
demos = Demographics.objects.filter(user=User.objects.get (username=request.user))
context = {
'demos': demos,
}
return render(request, self.template_name, context)
HTML:
{% if demos %}
{% for demographics in demos %}
<p>First Name</p> {{ demographics.first_name }}
{% endfor %}
{% else %}
<h3>you dont have demo yet</h3>
{% endif %}
urls.py
url(r'^test/', views.DemoView.as_view()),
admin.py
admin.site.register(Demographics)
models.py
class Demographics(models.Model):
first_name = models.CharField(max_length=50, null=True)
middle_name = models.CharField(max_length=50, null=True)
last_name = models.CharField(max_length=50, null=True)
user = models.ForeignKey(User, null=True)
Go to django admin, check your objects, and make sure you're logged in to the account that has demographic objects associated with it.
The above setup works for me, if it doesn't work for you, you're most likely logged in as a user which doesn't have any demographic objects associated with it.
Also, don't name your models as plural, it should be Demographic, because it is a representation of one object. When you filter in views, you name the variable demographics (plural), because the query returns more than one object.