Why is the likes system not working? Аfter clicking on the "like" button I get an error.
class ImageDetail(DetailView):
model=Image
template_name='images/image/detail.html'
context_object_name='image'
def get_queryset(self):
return Image.objects.filter(id=self.kwargs.get('id'),slug=self.kwargs['slug'])
def get_context_data(self, **kwargs):
data = super().get_context_data(**kwargs)
likes_connected=get_object_or_404(Image, id=self.kwargs['id'],slug=self.kwargs['slug'])
liked=False
if likes_connected.users_like.filter(id=self.request.user.id).exists():
liked=True
data['number_of_likes']=likes_connected.number_of_likes()
data['post_is_liked']=liked
return data
def ImagePostLike(request,id,slug):
image=get_object_or_404(Image, id=request.POST.get('image_id'), slug=request.POST.get('image_slug'))
if image.users_like.filter(id=request.user.id).exists():
image.users_like.remove(request.user)
else:
image.users_like.add(request.user)
return HttpResponseRedirect(reverse('image_detail', args=[self.id, self.slug]))
Why is the likes system not working? Аfter clicking on the "like" button I get an error.
urls.py
from django.urls import path,include
from . import views
app_name = 'images'
urlpatterns = [
path('create/', views.image_create, name='create'),
path('detail/<int:id>/<slug:slug>/', views.ImageDetail.as_view(), name='image_detail'),
path('image_like/<int:id>/<slug:slug>/', views.ImagePostLike, name='image_like'),
]
Why is the likes system not working? Аfter clicking on the "like" button I get an error.
detail.html
{% extends 'base.html' %}
{% load thumbnail %}
{% block title %}{{image.title}}{% endblock title %}
{% block content %}
<h1>{{ image.title }}</h1>
<img src="{{ image.url }}" class="image-detail">
{% if user.is_authenticated %}
<form action="{% url 'images:image_like' image.id image.slug%}">
{% csrf_token %}
{% if post_is_liked %}
<button type="submit" name="image_id" value="{{image.id}}" class="btn btn-info">Unlike</button>
{% else %}
<button type="submit" name="image_id" value="{{image.id}}" class="btn btn-info">Like</button>
{% endif %}
</form>
{% else %}
<a class="btn btn-outline-info" href="{% url 'login' %}?next={{request.path}}">>Log in to like this article!</a><br>
{% endif %}
<strong class="text-secondary">{{ number_of_likes }} Like</strong>
{% endblock content %}
models.py
# Create your models here.
class Image(models.Model):
user=models.ForeignKey(settings.AUTH_USER_MODEL,
related_name='images_created', on_delete=models.CASCADE)
title=models.CharField(max_length=50)
slug=models.SlugField(max_length=200, blank=True)
url=models.URLField()
image=models.ImageField(upload_to='images/%Y/%m/%d/')
description = models.TextField(blank=True)
created = models.DateField(auto_now_add=True,
db_index=True)
users_like=models.ManyToManyField(User,
related_name='image_like')
def __str__(self):
return self.title
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.title)
super().save(*args, **kwargs)
def get_absolute_url(self):
return reverse('images:detail', args=[self.id, self.slug])
def number_of_likes(self):
return self.users_like.count()
As I understand it, the problem lies in the slug.
Related
I follow a tutorial in youtube just to add a like button to my Blog application, but the number of likes is not increasing in the template. but its increase when I highlight a user and hit save in the admin area. I mean its working fine in the admin but not in template.
How can I set that ?
the model:
class Photo(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
category = models.CharField(max_length=30,null=True, blank=False)
image = models.ImageField(null=False, blank=False)
description = models.TextField(null=True)
date_added = models.DateTimeField(auto_now_add=True)
likes = models.ManyToManyField(User, related_name='blog_posts')
def total_likes(self):
return self.likes.count()
def __str__(self):
return str(self.category)
the view:
def like(request, pk):
post = get_object_or_404(Photo, id=request.GET.get('post_id'))
post.Likes.add(request.user)
return HttpResponseRedirect(reverse('view', args=[str(pk)]))
def viewPhoto(request, pk):
post = get_object_or_404(Photo, id=pk)
photo = Photo.objects.get(id=pk)
stuff = get_object_or_404(Photo, id=pk)
total_likes = stuff.total_likes()
return render(request, 'photo.html', {'photo': photo, 'post': post, 'total_likes':
total_likes})
the templates:
<form action="{% url 'Photo' photo.id %}" method="POST">
{% csrf_token %}
{{ total_likes }}
<button type="submit", name="post_id" value="{{ post.id }}">Touch</button>
</form>
the urls:
path('', views.login, name='login'),
path('home', views.home, name='home'),
path('view/<str:pk>/', views.viewPhoto, name='Photo'),
path('post/create', views.PostCreativeView.as_view(), name='post_create'),
path('register', views.register, name='register'),
path('comment/<str:pk>/', views.comment, name='comment'),
path('like/<str:pk>/', views.like, name='like_post'),
Well it's very simple to get the number of liked objects in your form by simple doing something like this :
# In your view add s to the post variable
def viewPhoto(request, pk):
posts = get_object_or_404(Photo, id=pk)
photo = Photo.objects.get(id=pk)
stuff = get_object_or_404(Photo, id=pk)
total_likes = stuff.total_likes()
return render(request, 'photo.html', {'photo': photo, 'posts': posts, 'total_likes':
total_likes})
{% for post in posts %}
<form action="{% url 'like_post' photo.id %}" method="POST">
{% csrf_token %}
{{ post.likes.count }} # this would count and give you the total number of likes
<button type="submit", name="post_id" value="{{ post.id }}">Touch</button>
</form>
{% endfor %}
# OR
{% for post in posts %}
<form action="{% url 'like_post' photo.id %}" method="POST">
{% csrf_token %}
{{ total_likes }} # this would count and give you the total number of likes
<button type="submit", name="post_id" value="{{ post.id }}">Touch</button>
</form>
{% endfor %}
I am creating a small system that has two users, both of these users need singup forms.
To allow social accounts and ease of use i have used django_allauth. But i ran into a problem of creating two custom signin forms with different fields.
i have used multiple stackoverflow answers but unfortunately none have helped if anything they are now adding to the confusion ...
Multiple user type sign up with django-allauth
Multiple signup, registration forms using django-allauth
I find it hard to believe that this is not a use case that comes up a lot, someone must have done this before. My current code has 2 custom signup forms, 2 custom sign-up views and two custom URLs where the forms should be rendered. But they are both using the same form and I have no idea why.
can anyone shed any light on the situation?
from .models import GraduateUserProfile
from django import forms
from allauth.account.forms import SignupForm
import datetime
def year_choices():
return [(r, r) for r in range(2015, datetime.date.today().year + 1)]
def current_year():
return datetime.date.today().year
class GraduateUserSignupForm(SignupForm):
def __init__(self, *args, **kwargs):
super(GraduateUserSignupForm, self).__init__(*args, **kwargs)
self.fields['first_name'] = forms.CharField(required=True)
self.fields['last_name'] = forms.CharField(required=True)
self.fields['phone_number'] = forms.CharField(required=True)
self.fields['degree_course_name'] = forms.CharField(required=True)
self.fields['graduation_year'] = forms.TypedChoiceField(coerce=int, choices=year_choices, initial=current_year)
def save(self, request):
user = super(GraduateUserSignupForm, self).save(request)
user.first_name = self.cleaned_data.get('first_name')
user.last_name = self.cleaned_data.get('last_name')
user.is_graduate = True
user.save()
graduate = GraduateUserProfile.objects.create(user=user)
graduate.phone_number = self.cleaned_data.get('phone_number')
graduate.graduation_year = self.cleaned_data.get('phone_number')
graduate.degree_course = self.cleaned_data.get('degree_course')
graduate.save()
return user
class CompanyUserSignupForm(SignupForm):
def __init__(self, *args, **kwargs):
super(CompanyUserSignupForm, self).__init__(*args, **kwargs)
self.fields['degree_course_name'] = forms.CharField(required=True)
self.fields['degree_course_test'] = forms.CharField(required=True)
def save(self, request):
user = super(CompanyUserSignupForm, self).save(request)
return user
from .forms import CompanyUserSignupForm, GraduateUserSignupForm
from allauth.account.views import SignupView
class CompanyUserSignupView(SignupView):
template_name = 'account/company_signup.html'
form_class = CompanyUserSignupForm
redirect_field_name = 'next'
view_name = 'company_signup'
success_url = None
def get_context_name(self, **kwargs):
ret = super(CompanyUserSignupView, self).get_context_data(**kwargs)
ret.update(self.kwargs)
return ret
company_signup = CompanyUserSignupView.as_view()
class GraduateUserSignupView(SignupView):
template_name = 'account/graduate_signup.html'
form_class = GraduateUserSignupForm
redirect_field_name = 'next'
view_name = 'graduate_signup'
success_url = None
def get_context_name(self, **kwargs):
ret = super(GraduateUserSignupView, self).get_context_data(**kwargs)
ret.update(self.kwargs)
return ret
grad_signup = GraduateUserSignupView.as_view()
urlpatterns = [
path('business/signup', view=company_signup, name='company_signup'),
path('graduate/signup', view=grad_signup, name='graduate_signup'),
]
{% load i18n %}
{% block head_title %}{% trans "Signup" %}{% endblock %}
{% block content %}
<h1>{% trans "Sign Up" %}Grad Sign up</h1>
<p>{% blocktrans %}Already have an account? Then please sign in.{% endblocktrans %}</p>
<form class="signup" id="company_signup_form" method="post" action="{% url 'graduate_signup' %}">
{% csrf_token %}
{{ form.as_p }}
{% if redirect_field_value %}
<input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}" />
{% endif %}
<button type="submit">{% trans "Sign Up" %} »</button>
</form>
{% endblock %}
{% extends "account/base.html" %}
{% load i18n %}
{% block head_title %}{% trans "Signup" %}{% endblock %}
{% block content %}
<h1>{% trans "Sign Up" %}BUSINESS LOGIN</h1>
<p>{% blocktrans %}Already have an account? Then please sign in.{% endblocktrans %}</p>
<form class="signup" id="graduate_signup_form" method="post" action="{% url 'company_signup' %}">
{% csrf_token %}
{{ form.as_p }}
{% if redirect_field_value %}
<input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}" />
{% endif %}
<button type="submit">{% trans "Sign Up" %} »</button>
</form>
{% endblock %}
I have just figure it out. If you remove 'signup': 'accounts.forms.GraduateUserSignupForm', my forms are appearing correctly
EDIT: After a few days i found that the original allauth sign up view is still available to view. So i used this little peice of code
path('accounts/signup/', page_not_found, {'exception': Exception('Not Found')}, name="default_signup"),
to throw a 404 if anyone tried to view it
I am building an e-commerce store with Django, and I have added some products to a collection. I want to be able to display each collection separately with the products that have been added to it.
Here is my models.py code
#Collections model Fields
class Collections(models.Model):
title = models.CharField(max_length=100)
products = models.ManyToManyField(Product)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('collections', kwargs={'slug': self.slug})
Here is my Views.py:
def collectionsPage(request, slug):
collections = Collections.objects.get(slug=slug)
products = Product.objects.all()
context = {"products": products, "collections":collections,}
return render(request, "collections.html", context)
Here is my urls.py:
urlpatterns = [
path('collections/<slug:slug>', views.collectionsPage, name="collections"),
]
Here is my HTML Code:
{% for collection in collections %}
<form action="{{collection.products.get_absolute_url}}" method="post">
{% csrf_token %}
<button class="polaroid" style="background-color:white; border:none">
<div>
<img src="{{collection.products.imageURL}}" alt="iPhone image">
<h3 class="container">{{collection.products.title}}</h3>
<h4 class="container">{{collection.products.price}}</h4>
</div>
</button>
</form>
{% endfor %}
I have been able to solve the problem as follows:
#Nothing to change in Models.py
#Views.py
def collectionsPage(request, slug):
collections = Collections.objects.get(slug=slug).products.all() ###
data = cartData(request)
cartItems = data["cartItems"]
context = {"collections":collections, "cartItems":cartItems}
return render(request, "collections.html", context)
#HTML code:
{% for product in collections %}
<form action="{{product.get_absolute_url}}" method="post">
{% csrf_token %}
<button class="polaroid" style="background-color:white; border:none">
<div>
<img src="{{product.imageURL}}" alt="iPhone image">
<h3 class="container">{{product.title}}</h3>
<h4 class="container">{{product.price}}</h4>
</div>
</button>
</form>
{% endfor %}
Django2.1
I want to create a button that will be displayed when the user saves data in the past.
I thought it could be done with {% if object %}, but it seemed different.
Here is the failed code.
{% if user.is_authenticated %}
{% if object %}
<a class="btn" href="{% url 'detail' user.id %}">Check</a>
{% else %}
<a class="btn" href="{% url 'create' %}">Create</a>
{% endif %}
{% else %}
#models.py
class Mymodel(models.Model):
user = models.OneToOneField(get_user_model(), on_delete=models.CASCADE)
title = models.CharField(max_length=20)
content = models.TextField(max_length=5000)
posted_date = models.DateTimeField(auto_now=True)
I will create data in CreateView.
class MyCreateView(LoginRequiredMixin, CreateView):
model = Mymodel
form_class = MyForm
def form_valid(self, form):
obj = form.save(commit=False)
obj.user = self.request.user
return super(MyCreateView, self).form_valid(form)
def get_success_url(self):
return reverse_lazy('detail', kwargs={"pk": self.object.pk})
thank you for reading it until the very end.
I think it should be like this:
{% if user.is_authenticated %}
{% if user.mymodel %}
<a class="btn" href="{% url 'detail' user.id %}">Check</a>
{% else %}
<a class="btn" href="{% url 'create' %}">Create</a>
{% endif %}
{% else %}
Because, Mymodel and User has OneToOne relation, so you can get the Mymodel value using:
user.mymodel # class name all lower case
And also get user data from my model using:
mymodel = Mymodel.objects.get(id=1)
mymodel.user
I have a situation where I want to have published functionality for articles, and I have it. The problem is that I can't get my unit test to work properly, trying to post True to the published field.
Here's what my tests look like.
class ArticleDetailViewTest(TestCase):
def setUp(self):
email = 'testuser#gmail.com'
first_name = 'test'
last_name = 'user'
password = 'test15146'
user = User.objects.create_user(email, first_name, last_name, password)
self.client = Client()
self.client.login(username='testuser#gmail.com', password='test15146')
def test_can_publish_article_from_POST(self):
other_article_two = Article.objects.create(name='Test Name One', author=User.objects.get(email='testuser#gmail.com'))
correct_article_two = Article.objects.create(name='Test Name Two', author=User.objects.get(email='testuser#gmail.com'))
response = self.client.post(reverse('publish_article', kwargs={'pk' : correct_article_two.pk}))
self.assertEqual(response.status_code, 302)
self.assertRedirects(response, f'/articles/{correct_article_two.pk}/')
self.assertEqual(correct_article_two.published, True)
Here's what my publish article view looks like.
def publish_article(request, pk):
article = get_object_or_404(models.Article, pk=pk)
if request.method == "POST":
article.published = True
article.save(update_fields=['published'])
return redirect('article_detail_view', pk=article.pk)
else:
raise Http404
Here are my urls.
from django.urls import path
from . import views
urlpatterns = [
path('', views.HomePageView.as_view(), name='home'),
path('new/', views.ArticleCreateView.as_view(), name='article_new'),
path('<int:pk>/', views.ArticleDetailView.as_view(), name='article_detail_view'),
path('<int:pk>/publish/', views.publish_article, name='publish_article'),
path('<int:pk>/unpublish/', views.unpublish_article, name='unpublish_article'),]
Here are my models.
from django.conf import settings
from django.db import models
from django.urls import reverse
from django import forms
class Article(models.Model):
name = models.CharField(max_length=255, blank=False)
author = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
)
published = models.BooleanField(default=False)
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('article_detail_view', args=[str(self.id)])
class ArticleForm(forms.ModelForm):
class Meta:
model = Article
fields = ['name',]
Lastly, here is the template.
{% extends 'base.html' %}
{% block title %}{{ article.name }}{% endblock %}
{% block content %}
{% if article.author_id == user.pk %}
<div class="row">
<div class="col-6 col-centered">
<h2 class="text-center">{{ article.name }}</h2>
<p class="text-center">by {{ article.author.first_name }} {{ article.author.last_name }}</p>
{% if article.published %}
<small class="form-text text-muted mb-1">This article is public.</small>
<form method="post" action="/articles/{{ article.pk }}/unpublish/">
{% csrf_token %}
<input type="submit" name="unpublish" value="Unpublish Article" id="id_unpublish_button" class="btn btn-primary btn-md"/>
</form>
{% else %}
<small class="form-text text-muted mb-1">This article is private.</small>
<form method="post" action="/articles/{{ article.pk }}/publish/">
{% csrf_token %}
<input type="submit" name="publish" value="Publish Article" id="id_publish_button" class="btn btn-primary btn-md"/>
</form>
{% endif %}
</div>
</div>
{% elif article.published %}
<div class="row">
<div class="col-6 col-centered">
<h2 class="text-center">{{ article.name }}</h2>
<p class="text-center">by {{ article.author.first_name }} {{ article.author.last_name }}</p>
</div>
</div>
{% else %}
<div class="row">
<div class="col-6 col-centered">
<p class="text-center">This article is private.</p>
</div>
</div>
{% endif %}
{% endblock %}
This is the error message I'm getting from my test. The issue seems to be I can post to the URL with self.client.post . Any help would be greatly appreciated.
FAIL: test_can_publish_article_from_POST (articles.tests.ArticleDetailViewTest)
Traceback (most recent call last):
File "/Users/christopher.chough/article_directory/articles/tests.py", line 126, in test_can_publish_article_from_POST
self.assertEqual(correct_article_two.published, True)
AssertionError: False != True
Ran 17 tests in 2.340s
FAILED (failures=1)
Object in your test method not updated. You can use refresh_from_db method to update it after changes:
def test_can_publish_article_from_POST(self):
other_article_two = Article.objects.create(name='Test Name One', author=User.objects.get(email='testuser#gmail.com'))
correct_article_two = Article.objects.create(name='Test Name Two', author=User.objects.get(email='testuser#gmail.com'))
response = self.client.post(reverse('publish_article', kwargs={'pk' : correct_article_two.pk}))
correct_article_two.refresh_from_db() # Add this line
self.assertEqual(response.status_code, 302)
self.assertRedirects(response, f'/articles/{correct_article_two.pk}/')
self.assertEqual(correct_article_two.published, True)