I cannot show all the users name who liked the post in django. I have tried many ways to do that but its not working.
my models.py:
class post(models.Model):
title = models.CharField(max_length=100)
image = models.ImageField(upload_to='post_pics', null=True, blank=True)
video = models.FileField(upload_to='post_videos', null=True, blank=True)
content = models.TextField()
likes = models.ManyToManyField(User, related_name='likes', blank=True)
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.title
def delete(self, *args, **kwargs):
self.image.delete()
super().delete(*args, **kwargs)
def get_absolute_url(self):
return reverse ('blog-home')
in views.py :
def like_post(request):
# posts = get_object_or_404(Post, id=request.POST.get('post_id'))
posts = get_object_or_404(post, id=request.POST.get('post_id'))
is_liked = False
if posts.likes.filter(id=request.user.id).exists():
posts.likes.remove(request.user)
is_liked = False
else:
posts.likes.add(request.user)
is_liked = True
return render(request, 'blog/home.html')
def post_likes(request, pk):
posts = get_object_or_404(post, pk=pk)
post_likes = posts.likes.all()
context = {'post_likes': post_likes,}
return render(request, 'blog/post_likes.html', context)
in urls.py:
path('post/<int:pk>/postlikes/', views.post_likes, name='post-likes'),
and in post_like.html:
{% extends "blog/base.html" %}
{% block content %}
{% for likes in posts %}
<p>{{ posts.likes.user.all }}</p>
{% endfor %}
{% endblock content %}
How can i see the usernames who liked the particular post?
You iterate over the post_likes, which are User objects, and then you render the user.username:
{% extends "blog/base.html" %}
{% block content %}
{% for user in post_likes %}
<p>{{ user.username }}</p>
{% endfor %}
{% endblock content %}
Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.
Related
I am attempting to add a form for comments to a DetailView. The DetailView displays notes for specific projects. So the comments have a foreign key that is the specific note and the note has a foreign key for the specific project.
I am attempting to use FormMixin with DetailView. So far I have not bee successful. Currently I can get the form to display but it does not save and in the terminal I see the following error Method Not Allowed (POST): /projects/project/1/note/1/
I can get these to work separately but not with the form in the DetailView.
Here are my models:
class ProjectNotes(models.Model):
title = models.CharField(max_length=200)
body = tinymce_models.HTMLField()
date = models.DateField(auto_now_add=True)
project = models.ForeignKey(Project, default=0, blank=True, on_delete=models.CASCADE, related_name='notes')
def __str__(self):
return self.title
class ProjectNoteComments(models.Model):
body = tinymce_models.HTMLField()
date = models.DateField(auto_now_add=True)
projectnote = models.ForeignKey(ProjectNotes, default=0, blank=True, on_delete=models.CASCADE, related_name='comments')
The View:
class ProjectNotesDetailView(DetailView, FormMixin):
model = ProjectNotes
id = ProjectNotes.objects.only('id')
template_name = 'company_accounts/project_note_detail.html'
comments = ProjectNotes.comments
form_class = NoteCommentForm
def form_valid(self, form):
projectnote = get_object_or_404(ProjectNotes, id=self.kwargs.get('pk'))
comment = form.save(commit=False)
comment.projectnote = projectnote
comment.save()
return super().form_valid(form)
def get_success_url(self):
return reverse('project_detail', args=[self.kwargs.get('pk')])
The form:
class NoteCommentForm(forms.ModelForm):
class Meta:
model = ProjectNoteComments
fields =['body',]
widgets = {
'body': forms.TextInput(attrs={'class': 'form-control'})
}
The template:
% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<div class="section-container container">
<div class="project-entry">
<h2>{{ projectnotes.title }}</h2>
<p>{{ projectnotes.body | safe }}</p>
</div>
<div><b>Comments on {{projectnotes.title}}</b></div>
{% if projectnotes.comments.all %}
{% for comment in projectnotes.comments.all %}
<div class="notecomments" style="padding: 10px;">
{{ comment.body | safe }}
</div>
{% endfor %}
{% else %}
<p>No comments have been have been added yet.</p>
{% endif %}
<h2>add note</h2>
<h1>Add Comment</h1>
<form action="" method="post">
{% csrf_token %}
{{ form.media }}
{{ form|crispy }}
<input type="submit" value="save">
</form>
{% endblock content %}
Try to change the order between DetailView and FormMixin in ProjectNotesDetailView then implement the post method (enabled by the `FormMixin):
class ProjectNotesDetailView(FormMixin, DetailView):
model = ProjectNotes
id = ProjectNotes.objects.only('id')
template_name = 'company_accounts/project_note_detail.html'
comments = ProjectNotes.comments
form_class = NoteCommentForm
def form_valid(self, form):
projectnote = get_object_or_404(ProjectNotes, id=self.kwargs.get('pk'))
comment = form.save(commit=False)
comment.projectnote = projectnote
comment.save()
return super().form_valid(form)
def get_success_url(self):
return reverse('project_detail', args=[self.kwargs.get('pk')])
def post(self, request, *args, **kwargs):
if not request.user.is_authenticated:
return HttpResponseForbidden()
self.object = self.get_object()
form = self.get_form()
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
Check how to use formmixin with detailview (documentation).
I have two models with one being a foreign key to another. A user can only submit an answer. am trying to use the if statement to check if an answer exit for a user then the submit answer button should change the update button the template.
class Assignment(models.Model):
title = models.CharField(max_length=120)
slug = models.SlugField(max_length=500)
course = models.ForeignKey(Course, on_delete=models.CASCADE)
class_or_level = models.ForeignKey(StudentClass, on_delete=models.CASCADE)
teacher = models.ForeignKey(Teacher, on_delete=models.CASCADE)
file = models.FileField(upload_to='assignment', blank=True, null=True)
Text = models.TextField()
date_added = models.DateTimeField(auto_now_add=True)
date_expire = models.DateTimeField()
class Answer(models.Model):
slug = models.SlugField(max_length=500)
assignment = models.ForeignKey(Assignment, on_delete=models.CASCADE)
student = models.ForeignKey(User, on_delete=models.CASCADE)
file = models.FileField(upload_to='assignment')
date_added = models.DateTimeField(auto_now_add=True)
My View
class AssignmentView(LoginRequiredMixin, ListView):
template_name = 'assignment.html'
context_object_name = 'all_couses'
now = timezone.now()
queryset = Course.objects.all()
def get_context_data(self, **kwargs):
now = timezone.now()
context = super(AssignmentView, self).get_context_data(**kwargs)
context.update({
'assignment_list': Assignment.objects.filter(class_or_level=self.request.user.student.class_or_level, date_expire__gte=now).order_by('-date_expire'),
})
return context
this the template> What the users submitted answer to show if he does submit one else show the form like to submit answer
{% for assignment in assignment_list %}
<h4>{{ assignment.title|truncatewords:12 }}</h4>
{% if assignment.answer %}
{{ assignment.answer.file }}
<button> Update Answer</button>
{% else %}
<button> Summit Answer</button>
{% endif %}
{% endfor %}
You can change your view or create a template tag to identify if an assignment has a response of a specific user, I decided to change the view and add a new variable to the assignment object that will have the information of if the user who requested the page has an answer to that assignment:
class AssignmentView(LoginRequiredMixin, ListView):
template_name = 'assignment.html'
context_object_name = 'all_couses'
now = timezone.now()
queryset = Course.objects.all()
def get_context_data(self, **kwargs):
now = timezone.now()
context = super(AssignmentView, self).get_context_data(**kwargs)
assignment_list = Assignment.objects.filter(
class_or_level=self.request.user.student.class_or_level,
date_expire__gte=now
).order_by('-date_expire')
for assignment in assignment_list:
try:
assignment.student_answer = Answer.objects.get(
assignment=assignment,
student=self.request.user
)
except Answer.DoesNotExist:
pass
context.update({
'assignment_list': assignment_list,
})
return context
Then, inside of your template you can do the following:
{% for assignment in assignment_list %}
<h4>{{ assignment.title|truncatewords:12 }}</h4>
{% if assignment.student_answer %}
{{ assignment.student_answer.file }}
<button> Update Answer</button>
{% else %}
<button> Summit Answer</button>
{% endif %}
{% endfor %}
By doing that you'll achieve what you're looking for.
lets's say that i have three categories (tutorials, news, jobs).
and i have class based views to list all posts, list posts by category and create new posts.
and sure post is the same model and fields to all categories.
my problem is :
if user was in category list template (let's say tutorial) .. i want the user when he create new post .. it is saved directly to tutorial category .. and if user was in list template (let's say news) .. he will create new post which will be saved directly to news category.
i mean create new post saved directly to current category.
i believe i will use (pass url parameter to class based views) but actually i failed to do that .. and i searched tonnage of questions without got what i want.
can any body help .. with sample please.
models.py
class Category(models.Model):
name = models.CharField(max_length=50)
slug = models.SlugField(max_length=50, unique=True)
def save(self, *args, **kwargs):
if not self.slug and self.name:
self.slug = slugify(self.name)
super(Category, self).save(*args, **kwargs)
class Post(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
category = models.ForeignKey(Category, on_delete=models.CASCADE, null=True)
author = models.ForeignKey(User, on_delete=models.CASCADE)
views.py
def PostListView(request, category_slug=None):
category = None
posts = Post.objects.all().prefetch_related().annotate(commentscountperpost=Count('comments'))
categories = Category.objects.prefetch_related().annotate(total_product_category=Count('post'))
if category_slug:
category = Category.objects.get(slug=category_slug)
posts = posts.filter(category=category)
context = {
'title': 'Home Page',
'posts': posts,
'total_posts': total_posts,
'categories': categories,
'category': category,}
return render(request, 'blog/index.html', context)
class PostCreateView(LoginRequiredMixin, CreateView):
model = Post
template_name = 'blog/new_post.html'
form_class = PostCreateForm
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
forms.py
class PostCreateForm(forms.ModelForm):
title = forms.CharField(label='Title')
content = forms.CharField(label='Content', widget=forms.Textarea)
class Meta:
model = Post
fields = ['title', 'content']
urls.py
path('index_list/', PostListView, name='list'),
path('<slug:category_slug>', PostListView, name='post_category_list'),
path('new_post/', PostCreateView.as_view(), name='new_post'),
new_post.html template
{% extends 'base.html' %}
{% block content %}
{% load crispy_forms_tags %}
<div class="border p-4 mb-5">
<legend class="border-bottom pb-1 mb-3">New Post </legend>
<form method="POST">
{% csrf_token %}
{{form|crispy}}
<input class="btn btn-secondary mt-4" type="submit" value="Add New Post">
</form>
</div>
{% endblock content %}
list.html template
{% for category in categories %}
<h5><a class="text-primary" href="{% url 'post_category_list' category.slug %}">
{{ category.name }} ({{ category.total_product_category }})</a></h5>
{% endfor %}
<h5>{{ total_posts }} Total Posts </h5>
{% if category %}
New {{ category }}
{% endif %}
You can try like this:
class PostCreateView(generic.CreateView):
model = Post
template_name = 'blog/new_post.html'
form_class = CreatePostForm
slug_url_kwarg = 'slug'
def form_valid(self, form):
category = Category.objects.get(slug=self.kwargs['slug'])
form.instance.category = category
form.instance.author = self.request.user
return super(PostCreateView, self).form_valid(form)
And in the urls
path('new_post/<slug>/', PostCreateView.as_view(), name='new_post'),
yes i found it , depending on arjun answer, greate thanks for arjun
in list posts per category template change :
New {{ category }}
to:
New {{ category }}
and it works fine,
thanks.
I build a Blogpost App with Django and want comments under the blogpost. I can already post new comments, and see comments, but I see every comment under every blogpost. .
class blogpost(models.Model):
user = models.ForeignKey(User, default=1, null=True, on_delete=models.SET_NULL)
title = models.TextField()
slug = models.SlugField(unique=True)
content = models.TextField(null=True, blank=True)
class blogcommment(models.Model):
user = models.ForeignKey(User, default=1, null=True, on_delete=models.SET_NULL)
post = models.ForeignKey(blogpost, default=1, null=True, on_delete=models.SET_NULL)
title = models.TextField()
content = models.TextField(null=True, blank=True)
def blogpost_detail_view (request, slug):
# Blogeintrag anzeigen
obj = blogpost.objects.get(slug=slug)
form = blogcommentform(request.POST or None)
qs = blogcommment.objects.filter(***What should stay here and why?***)
if form.is_valid():
comment = blogcommment.objects.create(**form.cleaned_data)
form = blogcommentform
template_name = 'blogpost_detail.html'
context = {"object": obj,'form': form,'object_list': qs}
return render(request, template_name, context)
{% extends "base.html" %}
{% block content %}
<h1>{{ object.title }}</h1>
<p>{{ object.content }}</p>
<form method="POST" action=""> {% csrf_token %}
{{ form.as_p }}
<button type='submit'>Senden</button>
</form>
{% for object in object_list %}
{{ object.content }}
{% endfor %}
{% endblock %}
class blogcommentform(forms.Form):
title = forms.CharField()
content = forms.CharField(widget=forms.Textarea)
Try this
qs = blogcommment.objects.filter(post_id=obj.id)
In blogcommment model you have a reference to blogpost. So, you can easily filter comment for which blog post related to it.
qs = blogcommment.objects.filter(post=obj)
This will tell the queryset to filter all blogcomments that have the current specific blogpost as their post reference.
I broke something. The error reads: Reverse for 'wiki_article_detail' with arguments '(u'',)' and keyword arguments '{}' not found. I don't know where the 'u' came from in arguments. here is the model:
class Article(models.Model):
"""Represents a wiki article"""
title = models.CharField(max_length=100)
slug = models.SlugField(max_length=50, unique=True)
text = models.TextField()
author = models.ForeignKey(User)
is_published = models.BooleanField(default=False, verbose_name="Publish?")
created_on = models.DateTimeField(auto_now_add=True)
objects = models.Manager()
published = PublishedArticlesManager()
country = models.CharField(max_length=100)
category = models.CharField(max_length=100)
def __unicode__(self):
return self.title
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.title)
super(Article, self).save(*args, **kwargs)
#models.permalink
def get_absolute_url(self):
return ('wiki_article_detail', (), { 'slug': self.slug })
The template is:
<body>
{% if object_list %}
<h2 class="articlePageTitle">All Articles</h2>
<h3>Filter by country</h3>
<h3>Filter by category</h3>
<ul>
{% for article in object_list %}
<li>
{{ article.title }}
</li>
{% endfor %}
</ul>
{% else %}
<h2>No articles have been published yet.</h2>
{% endif %}
<a href="{% url wiki_article_add %}">Create new article</a
</body>
the debugger is indicating the error in this line:
{{ article.title }}
This was all working fine before, I had some db problems and had to recreate the db file, but there wasn't much in there. But now, I can write an article and view it, but I can't get to the /all list.
urls.py snippet:
url(r'^all/$',
'django.views.generic.list_detail.object_list',
{
'queryset': Article.published.all(),
},
name='wiki_article_index'),
the urls.py snippet that is referenced in the error:
url(r'^article/(?P<slug>[-\w]+)$',
'django.views.generic.list_detail.object_detail',
{
'queryset': Article.objects.all(),
},
name='wiki_article_detail'),
Try this one:
{{ article.title }}