How to create a like functionality in django for a blog - python

I have to build a blog for my chess club and I would like to make a like functionality for the posts. When the user likes the post the like count increases and the post its shown in the user profile.
Here is what I made so far:
This is my post model:
class Post(models.Model):
title = models.CharField(max_length=100)
overview = models.TextField()
timestamp = models.DateTimeField(auto_now_add=True)
content = HTMLField()
is_aproved = models.BooleanField(default=False)
# comment_count = models.IntegerField(default = 0)
# view_count = models.IntegerField(default = 0)
slug = models.SlugField(unique=True, blank=True)
likes = models.ManyToManyField(
settings.AUTH_USER_MODEL, blank=True, related_name='post_likes')
author = models.ForeignKey(Author, on_delete=models.CASCADE)
thumbnail = models.ImageField()
categories = models.ManyToManyField(Category)
featured = models.BooleanField()
previous_post = models.ForeignKey(
'self', related_name='previous', on_delete=models.SET_NULL, blank=True, null=True)
next_post = models.ForeignKey(
'self', related_name='next', on_delete=models.SET_NULL, blank=True, null=True)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('post-detail', kwargs={
'id': self.id
})
def get_update_url(self):
return reverse('post-update', kwargs={
'id': self.id
})
def get_delete_url(self):
return reverse('post-delete', kwargs={
'id': self.id
})
#property
def get_comments(self):
return self.comments.all().order_by('-timestamp')
#property
def comment_count(self):
return Comment.objects.filter(post=self).count()
#property
def view_count(self):
return PostView.objects.filter(post=self).count()
And this is my view:
def post(request, id):
category_count = get_category_count()
most_recent = Post.objects.order_by('-timestamp')[:3]
post = get_object_or_404(Post, id=id)
if request.user.is_authenticated:
PostView.objects.get_or_create(user=request.user, post=post)
form = CommentForm(request.POST or None)
if request.method == "POST":
if form.is_valid():
form.instance.user = request.user
form.instance.post = post
form.save()
return redirect(reverse("post-detail", kwargs={
'id': post.pk
}))
context = {
'form': form,
'post': post,
'most_recent': most_recent,
'category_count': category_count,
'form': form
}
return render(request, 'post.html', context)
could you help me to implement this like functionality

You need another model to get liking functionality in Django. Create a like model like this-
class PostLikes(models.Model):
user = models.ForeignKey(User)
post = models.ForeignKey(Post)
created = models.DateTimeField(auto_now_add=True)
then create a view to add the instance to the PostLikes model-
def like_others_post(request, post_id):
new_like, created = PostLikes.objects.get_or_create(user=request.user,
post_id=post_id)
if not created:
# you may get and delete the object as the user may already liked this
post before
We are using get or create to avoid duplication of likes. So a user may click multiple times but, a like instance is stored only once.
then add a method to Post model for getting the number of likes-
def Post(models.Model):
...
...
#property
def view_count(self):
return PostLikes.objects.filter(post=self).count()
To find out if the current user already likes the displayed post or not, in your post view-
def post(request, id):
....
....
already_liked = PostLikes.objects.filter(user=request.user, post=post).count()
if number_of_likes > 0:
already_liked = True # pass this variable to your context
else:
already_liked = False # you can make this anything other than boolean
Then by use of Javascript and {{already_liked}}, change your animation of like button in your template.

Related

Incorrect display of children's models on the form in django

I tried to make a creation form for vacancy on my job search site, but i faced with problem. I have User model, company model and vacancy model. They are inherited by foreignkeys. And the problem is that user can use all companies for creation a vacancy instead of created by this user companies(User can create several companies). I tried to change creation form and view by filtering, but it didn't work out for me. I am new at django and i dint find anything to resolve my problem.
Model of company:
class Company(models.Model):
owner = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(('Title of Shop'), blank=True, max_length=255)
info = models.TextField(('Information about Shop'), null=True, blank=True)
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
def __str__(self):
return str(self.title)
Model of vacancy:
class Vacancies(models.Model):
title = models.CharField(('Title of Vacancy'), blank=True, max_length=255)
city = models.ForeignKey(City, on_delete=models.CASCADE, default='363')
description = models.TextField(('Information about Vacancy'), null=True, blank=True)
employer = models.ForeignKey(Company, on_delete=models.CASCADE)
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ['-updated', '-created']
def __str__(self):
return str(self.title)
Create vacancy view:
#login_required(login_url='login')
def createVacancy(request):
form = VacanciesForm()
cities = City.objects.all()
if request.method == 'POST':
form = VacanciesForm(request.POST)
if form.is_valid():
form.save()
return redirect('home')
context = {'form': form, 'cities': cities}
return render(request, 'vacancy_form.html', context)
Vacancy form:
class VacanciesForm(ModelForm):
class Meta:
model = Vacancies
fields = '__all__'
What do I need to change to get the correct display of companies in the vacancy
Try this:
#login_required(login_url='login')
def create_vacancy(request):
user = request.user
cities = City.objects.all()
if request.method == 'POST':
form = VacanciesForm(data=request.POST, instance=user)
if form.is_valid():
form.save()
return redirect('home')
context = {'form': form, 'cities': cities}
return render(request, 'vacancy_form.html', context)
Also you can use in view:
def create_vacancy(request, logined_user_id):
vacancies = Vacancies.objects.filter(owner=logined_user_id)
...
And you can try some logic here:
class VacanciesForm(ModelForm):
vacancies = [some_logic]
class Meta:
model = Vacancies
fields = '__all__'
Finally, you can read docs:
modelforms
This work:
views
def createVacancy(request):
cities = City.objects.all()
form = VacanciesForm(data=request.POST, request=request)
if form.is_valid():
form.save()
return redirect('home')
context = {'form': form, 'cities': cities,}
return render(request, 'vacancy_form.html', context)
forms
class VacanciesForm(ModelForm, forms.Form):
def __init__(self, *args, **kwargs):
self.request = kwargs.pop("request")
super(VacanciesForm, self).__init__(*args, **kwargs)
self.fields['employer'].queryset = EmployerCard.objects.filter(owner=self.request.user)
class Meta:
model = Vacancies
fields = '__all__'

How do I fail the booking if the booked boolean field is set to True in django?

I am having trouble making if/else work in my django app, I want to check if a listing is booked, booked is a boolean field and the listing is a foreign key to the Booking class where the user selects a listing to book. Now I just want to know how that foreign key can be checked if the listing is booked so it fails to book and gives an error.
views.py
#login_required
def profile(request):
if request.method == "GET":
tickets = models.Booking.objects.all().filter(user=request.user)
return render(request, "profile.html", {'form': forms.BookingForm(), 'tickets': tickets})
else:
try:
form = forms.BookingForm(request.POST)
new_ticket = form.save(commit=False)
new_ticket.user = request.user
new_ticket.save()
messages.success(request, 'Booking Created Successfully')
return redirect('profile')
except ValueError:
return render(request, 'profile.html', {'form': forms.BookingForm()})
models.py
class Listing(models.Model):
title = models.CharField(max_length=50)
content = models.TextField(max_length=755)
price = MoneyField(max_digits=5, decimal_places=2)
booked = models.BooleanField(default=False)
seller = models.ForeignKey(User, on_delete=models.CASCADE)
# avail_days = models.ForeignKey(Days, on_delete=models.CASCADE)
def __str__(self):
return self.title
class Booking(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
listing = models.ForeignKey(Listing, on_delete=models.CASCADE) # how to check if listing is booked and deny if it is True ?
# day = models.OneToOneField(Days, on_delete=models.CASCADE)
date_booked = models.DateField(auto_now_add=True)
def __str__(self):
return self.user.username
If you want to use booked field in Listing model, you can do this (you can also render Listing objects with booked=False):
views.py
#login_required
def profile(request):
if request.method == "GET":
tickets = models.Booking.objects.all().filter(user=request.user)
return render(request, "profile.html", {'form': forms.BookingForm(), 'tickets': tickets})
else:
try:
form = forms.BookingForm(request.POST)
new_ticket = form.save(commit=False)
# here you can do something like
if new_ticket.listing.booked:
messages.error(request, 'Booked Already')
return redirect('profile')
new_ticket.user = request.user
new_ticket.save()
messages.success(request, 'Booking Created Successfully')
return redirect('profile')
except ValueError:
return render(request, 'profile.html', {'form': forms.BookingForm()})
models.py
class Listing(models.Model):
title = models.CharField(max_length=50)
content = models.TextField(max_length=755)
price = MoneyField(max_digits=5, decimal_places=2)
booked = models.BooleanField(default=False)
seller = models.ForeignKey(User, on_delete=models.CASCADE)
# avail_days = models.ForeignKey(Days, on_delete=models.CASCADE)
def __str__(self):
return self.title
class Booking(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
listing = models.ForeignKey(Listing, on_delete=models.CASCADE) # how to check if listing is booked and deny if it is True ?
# day = models.OneToOneField(Days, on_delete=models.CASCADE)
date_booked = models.DateField(auto_now_add=True)
def __str__(self):
return self.user.username
def save(self, *args, **kwargs):
self.listing.booked = True
self.listing.save()
super().save(*args, **kwargs)

Django: How to filter ForeignKey choices by request.user with ModelFormSet

I just want to filter select field in a form, regarding a currently logged user. Every user has own categories and budgets - I want to display only a models related with a currently logged user. I've tried stuff with filtering before is_valid field, but with no result. Please, find my code below:
views.py
#login_required
def day_data_multiadd(request, no_of_lines=0):
no_of_lines = int(no_of_lines)
CostFormSet = modelformset_factory(Cost, form=DataAddForm, extra=no_of_lines)
if request.method == 'POST' and 'form' in request.POST:
formset = CostFormSet(request.POST, request.FILES)
if formset.is_valid():
for form in formset.forms:
f = form.save(commit=False)
f.user = request.user
f.save()
else:
formset = CostFormSet(queryset=Cost.objects.none())
if request.method == 'POST' and 'no_line' in request.POST:
generate_form = MultiaddGenerateForm(request.POST)
if generate_form.is_valid():
cd = generate_form.cleaned_data
return HttpResponseRedirect(reverse('core_sm:day_data_multiadd', args=(cd['formy'], )))
else:
generate_form = MultiaddGenerateForm()
return render(request, 'core_sm/costs/multi_add.html', {'formset': formset,
'no_of_lines': no_of_lines,
'generate_form': generate_form})
forms.py
class DataAddForm(forms.ModelForm):
class Meta:
model = Cost
fields = ['title', 'value', 'publish', 'category', 'budget']
exclude = ['user']
labels = {
'title': _('Tytuł'),
'value': _('Wartość'),
'publish': _('Data'),
'category': _('Kategoria'),
'budget': _('Budżet')
}
models.py
class Category(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL)
title = models.CharField(max_length=200)
publish = models.DateField(auto_now_add=True)
updated = models.DateField(auto_now=True)
class Meta:
ordering = ('-publish',)
def __str__(self):
return self.title
def get_absolute_ur(self):
return reverse('core_sm:category_detail', args=[self.id])
class Budget(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL)
title = models.CharField(max_length=200, db_index=True)
value = models.DecimalField(decimal_places=2, max_digits=10)
publish = models.DateField(auto_now_add=True)
updated = models.DateField(auto_now=True)
class Meta:
ordering = ('-publish',)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('core_sm:budget_detail', args=[self.id])
class Cost(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL)
budget = models.ForeignKey(Budget, related_name='cost')
category = models.ForeignKey(Category, related_name='cost')
title = models.CharField(max_length=200, db_index=True)
publish = models.DateField(default=timezone.now)
created = models.DateField(auto_now_add=True)
updated = models.DateField(auto_now=True)
value = models.DecimalField(max_digits=10, decimal_places=2)
class Meta:
ordering = ('-publish',)
def get_absolute_url(self):
return reverse('core_sm:stats_detail', args=[self.publish.year,
self.publish.strftime('%y'),
self.publish.strftime('%m'),
self.publish.strftime('%d')])
def __str__(self):
return self.title
According to the docs you can pass custom parameters to formsets forms.
class DataAddForm(forms.ModelForm):
class Meta:
model = Cost
fields = ['title', 'value', 'publish', 'category', 'budget']
exclude = ['user']
labels = {
'title': _('Tytuł'),
'value': _('Wartość'),
'publish': _('Data'),
'category': _('Kategoria'),
'budget': _('Budżet')
}
def __init__(self, *args, **kwargs):
user = kwargs.pop('user')
self.fields['category'].queryset = Category.objects.filter(user=user)
self.fields['budget'].queryset = Budget.objects.filter(user=user)
super(DataAddForm, self).__init__(*args, **kwargs)
views.py
formset = CostFormSet(queryset=Cost.objects.none(), form_kwargs={'user': request.user})

Django how to change forms or views.py?

i create simple page where i can add article (title, text and category). When i do it on 'site administration everything is ok', but when i add it on page i can't choose category.
http://i.stack.imgur.com/4Nxzb.jpg
I choose category, for example like on this screen but my article do not have this category after i save it (article is uncategorized).
I created forms.py file and i done it like this:
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = ('title', 'text', 'categories')
How must i change 'categories' here to make it usable?
models.py:
from django.db import models
from django.utils import timezone
class Category(models.Model):
name = models.CharField('Nazwa Kategorii', max_length=100)
slug = models.SlugField('Odnośnik', max_length=100)
icon = models.ImageField('Ikonka Kategorii', upload_to='icons',
blank=True)
class Meta:
verbose_name = "Kategoria"
verbose_name_plural = "Kategorie"
def __unicode__(self):
return self.name
class Post(models.Model):
author = models.CharField(max_length=25, blank=True, null=True)
title = models.CharField(max_length=200)
slug = models.SlugField('Odnośnik', max_length=255)
text = models.TextField()
published_date = models.DateTimeField(
default=timezone.now)
categories = models.ManyToManyField(Category, verbose_name='Kategorie')
def publish(self):
self.published_date = timezone.now()
self.save()
def __unicode__(self):
return self.title
And from views.py my view
def post_new(request):
if request.method == "POST":
form = PostForm(request.POST)
if form.is_valid():
post = form.save(commit=False)
post.author = request.user
post.save()
return redirect('blog.views.post_detail', pk=post.pk)
else:
form = PostForm()
return render(request, 'blog/post_edit.html', {'form': form})
When you save a form using commit=False you should call the save_m2m() method of the form:
post = form.save(commit=False)
post.author = request.user
post.save()
form.save_m2m()
Another, more elegant, solution is to pass the instance with preset field to the form's constructor. Is this case you don't need to use the commit=False argument:
form = PostForm(request.POST, instance=Post(author=request.user))
if form.is_valid():
post = form.save()
return redirect('blog.views.post_detail', pk=post.pk)

Update Django Model With Form Field

I am trying to update the quantity of my Inventory model using a Integer form field on the front end. I am able to add a new inventory item, but I want to update existing items. Here is my code:
FROM VIEWS.PY
def view_inventory(request, slug):
if request.method == 'POST':
quantity_add = addQuantity(request.POST)
if quantity_add.is_valid():
cd = quantity_add.cleaned_data
addq=Inventory(quantity = cd.get('quantity'))
addq.save()
quantity_add=addQuantity()
return render(request, 'inv/view_inventory.html', {
'item': get_object_or_404(Inventory.objects.all(), slug=slug),
'form' : quantity_add,
})
FROM MODELS.PY
class Inventory(models.Model):
quantity = models.IntegerField()
name = models.CharField(max_length=150, unique = True)
slug = models.SlugField(unique = True)
date = models.DateTimeField(auto_now_add=True)
description = models.CharField(max_length=250)
category = models.ForeignKey(Category, null=True, blank=True)
def __unicode__(self):
return self.name
#permalink
def get_absolute_url(self):
return ('view_inventory', None, { 'slug' : self.slug })
class Meta:
ordering = ['-date']
FROM URLS.PY
url(r'^(?P<slug>[\w\-]+)/$', 'inv.views.view_inventory', name='view_inventory'),
You only have to get the record and then update it:
def view_inventory(request, slug):
if request.method == 'POST':
quantity_add = addQuantity(request.POST)
if quantity_add.is_valid():
cd = quantity_add.cleaned_data
old_inventory = Inventory.objects.get(id=something here) #id or pk or whatever you want
old_inventory.quantity = cd.get('quantity')
old_inventory.save()
quantity_add=addQuantity()
return render(request, 'inv/view_inventory.html', {
'item': get_object_or_404(Inventory.objects.all(), slug=slug),
'form' : quantity_add,
})

Categories

Resources