How to Restricting one like per post in Django - python

I am a beginner in Django currently. I want to restrict one like per post in my so Posting kind of app, where you can post a text and user can like or dislike the same. Now I enabled Login and I want a logged in user to like a post only once and I am unsuccessful in doing so.
Models.py
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Todo(models.Model):
text = models.CharField(max_length=100)
complete = models.BooleanField(default=False)
like=models.IntegerField(default=0)
user = models.ForeignKey(User)
def __str__(self):
return self.text
Views,py
def like(request,todo_id):
if Todo.objects.filter(todo_id = todo_id, user_id=request.user.id).exists():
return redirect('index')
else:
todo = Todo.objects.get(pk=todo_id)
todo.like += 1
todo.save()
return redirect('index')

What basically I was missing is saving the likes corresponding to user. And this problem is easily solved by creating a model with User and main model as Foreign Key's as pointed out by Paolo.
models.py
from django.db import models
from django.contrib.auth.models import User
class Todo(models.Model):
text = models.CharField(max_length=100)
complete = models.BooleanField(default=False)
def __str__(self):
return self.text
class Todo_likes(models.Model):
todo = models.ForeignKey(Todo, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
views.py
from django.shortcuts import render,redirect
from .models import Todo,Todo_likes
from .forms import TodoForm
def like(request,todo_id):
user = request.user
todo = Todo.objects.get(id=todo_id)
like, created = Todo_likes.objects.get_or_create( # get_or_create will
# itself do the job of
# finding and creating if not exist
user = user,
todo = todo
)
if not created:
return redirect('index') #I don't wanted to show any error if existed earlier.
#I just wanted to redirect.
else:
return redirect('index')
And then counting my number of likes by simply going to my Index view and inserted
def index(request):
form = TodoForm()
todo_list = Todo.objects.order_by('id')
likes = Todo_likes.objects.count() # Adding this line
context= {'todo' : todo_list, 'form':form, 'likes' : likes}
return render(request,'todolistapp/index.html',context)
And displaying 'likes' object in my template.

I would like to give it a try and expand on my comment.
My suggestion is, to create a new model Todo_Likes which will have both Todo and User model as Foreign Keys to be able to track who liked a Todo.
models.py
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Todo(models.Model):
text = models.CharField(max_length=100)
complete = models.BooleanField(default=False)
# Got rid of the user FK and like since I would count likes using
# Todo_Like.objects.count()
def __str__(self):
return self.text
class Todo_Like(models.Model):
todo = models.ForeignKey(Todo)
user = models.ForeignKey(User)
views.py
def like(request,todo_id):
# Get user
user = request.user
# Get Todo object
todo = Todo.objects.get(id=todo_id)
# Check/Validate if current user has already liked the Todo.
# If not create a new Todo_Like object.
todo_like = Todo_Like.objects.get(todo=todo, user=user)
if not todo_like:
# If the user haven't like the Todo object yet create a Todo_Like object.
t = Todo_Like (
todo=todo,
user=user
)
t.save()
else:
# If the user has already liked the Todo then proceed to do
# Whatever you want, redirect? message?
I would also like to answer a question in advance.
You might ask how would you count the likes now? Answer: Make use of Todo_Like.objects.count(), and make sure you count it by Todo.

Related

How to search a Django database using a field saved in the model?

I am trying to create a search bar that searches for users in my Journal app. I want to redirect the search to the appropriate page if the user exists. I have created the view function, template and URL for the feature.
As a test, I imported the User class from django.contrib.auth.models and I was able to display a personalised message if the user existed.
def search_user(request):
"""Search for users."""
if request.method == "POST":
searched = request.POST["searched"]
usernames = User.objects.filter(username__icontains=searched)
context = {"searched": searched, "usernames": usernames}
return render(request, "journals/search_user.html", context)
In the main model, the Journal class has a ForeignKey relation with User and it is saved to a field called "owner". I would like to somehow check if the searched username matches with this "owner" field. When I try to make a search this way, it cannot find any data.
The reason I want the search to refer to "owner" is so that I can access the other fields in the table.
Could someone point out the mistake I am doing here?
from django.db import models
from django.contrib.auth.models import User
class Journal(models.Model):
"""A particular subject the user may want to write about."""
name = models.CharField(max_length=100)
date_added = models.DateTimeField(auto_now_add=True)
owner = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
"""Return a string representation of the model."""
return self.name
class Entry(models.Model):
"""Something specific the user may want to add to the journal."""
journal = models.ForeignKey(Journal, on_delete=models.CASCADE)
text = models.TextField()
date_added = models.DateTimeField(auto_now_add=True)
date_edited = models.DateTimeField(auto_now=True)
**View Function:**
def search_user(request):
"""Search for users."""
if request.method == "POST":
searched = request.POST["searched"]
usernames = Journal.objects.filter(owner=searched)
context = {"searched": searched, "usernames": usernames}
return render(request, "journals/search_user.html", context)
searched is just a text string, and Journal.owner is actually a User, so nothing will match here.
Match the related username instead ...
usernames = Journal.objects.filter(owner__username=searched)

How to set dynamic initial values to django modelform field

I'm kinda new to django, I need to set a dynamic initial value to my modelform field. I have a database field in my model name 'author' it has a foreignkey that connects it to the django user model. I need to automatically set this to the current user anytime a user fills in information into the form.
from what I gathered about this problem, I'd have to define an __init__ function inside the MyHouseEditForm below, I'm new to django and all the examples I've seen a pretty confusing.
forms.py
from django import forms
from django.contrib.auth.models import User
from .models import Myhouses
class MyHouseEditForm(forms.ModelForm):
class Meta:
model = Myhouses
fields = ('author','name_of_accomodation', 'type_of_room', 'house_rent', 'availability', 'location', 'nearest_institution', 'description', 'image')
i need to set the value of 'author' to the current user anytime a user logs in.
models.py
from django.db import models
from django.contrib.auth.models import User
class Myhouses(models.Model):
author = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, related_name='author')
Available = 'A'
Not_Available = 'NA'
Availability = (
(Available, 'Available'),
(Not_Available, 'Not_Available'),
)
name_of_accomodation = models.CharField(max_length=200)
type_of_room = models.CharField(max_length=200)
house_rent = models.IntegerField(null=True)
availability = models.CharField(max_length=2, choices=Availability, default=Available,)
location = models.CharField(max_length=200)
nearest_institution = models.CharField(max_length=200)
description = models.TextField(blank=True)
image = models.ImageField(upload_to='profile_image')
def __str__(self):
return self.name_of_accomodation
views.py
#login_required
def addlisting(request):
if request.method == 'POST':
form = MyHouseEditForm(request.POST, files=request.FILES)
if form.is_valid():
Houses = form.save(commit=False)
Houses.save()
return redirect('addlisting')
else:
form = MyHouseEditForm()
return render(request, 'houses/addlisting.html', {'form':form })
No need to show author field in form. It would automatically populate with logged in user.
request.user gives you logged in user object. So, you may remove 'author' filed from forms field section and do this:
Houses = form.save(commit=False)
Houses.author = request.user
Houses.save()
I did something like this in the serializer.
I defined a custom create method like this:
class MyhousesSerializer(FlexFieldsModelSerializer):
...
def create(self, validated_data):
validated_data['author'] = self.context['request'].user
newhouse = Myhouses.objects.create(**validated_data)
return newhouse
It shouldn't matter if you use a more regular model serializer.

How to get currently logged user id in form model in Django 1.7?

Let's say I have a webpage that displays songs. And let's say there are public and private songs. Public songs are available for everyone to see, while private songs are songs that a certain user has created and are only available for him to see. So the user should only see those songs with the owner_id == NULL and owner_id == currently_logged_in_user_id (his own id)
Model:
import ....
class Song(models.Model):
name = models.CharField(max_length=100)
duration = models.IntegerField(max_length=15)
owner = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True)
def __unicode__(self):
return self.name
View:
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth.decorators import login_required
from songapp.models import Song
from songapp.forms import SongInfoForm
#login_required
def song_info(request):
song = get_object_or_404(Box)
song_status = song.get_status()
form = SongInfoForm(initial={'song_list': song.song_list})
return render(request, 'songapp/song_info.html',
{'form': form, 'song': song, 'song_status': song_status})
Form:
from django import forms
from django.forms import ModelChoiceField
from songapp.models import Song
class SongInfoForm(forms.Form):
--> selected_songs = Song.objects.filter(owner=None) | Song.objects.filter(owner=3)
song_list = ModelChoiceField(queryset=selected_songs, required=False)
Note the line with the arrow in the Form file. This is where the problem lies. The code works now, but the
(owner = 3)
is hardcoded. I know for a fact that my users id is 3. But I want it to work properly. It should be something like this:
(owner = currently_logged_in_user.id)
I'm still very new to Django and Python and I don't know how to pass the users id to the SongInfoForm FormModel.
I've figured it out.
In views.py change:
form = SongInfoForm(initial={'song_list': song.song_list}, user=request.user)
And thanks to the answers before and this example
django form: Passing parameter from view.py to forms gives out error
I've came up with this, and it works like a charm.
In forms.py
class SongInfoForm(forms.Form):
def __init__(self, *args, **kwargs):
user = kwargs.pop('user')
super(SongInfoForm, self).__init__(*args, **kwargs)
self.fields['song_list'] = forms.ModelChoiceField(queryset=Song.objects.filter(owner=None) | Song.playlist.objects.filter(owner=user), required=False)
OK, my bad. Didn't read enought to see problem lies in the form, But according to this post: https://stackoverflow.com/a/5122029/2695295 you could rewrite your for like this:
class SongInfoForm(forms.Form):
def __init__(self, user, *args, **kwargs):
self.user = user
super(SongInfoForm, self).__init__(*args, **kwargs)
selected_songs = Song.objects.filter(owner=None) | Song.objects.filter(owner=user.id)
song_list = ModelChoiceField(queryset=selected_songs, required=False)
and then in view create your form like this:
form = SongInfoForm(request.user, initial={'song_list': song.song_list})
this way form object should have access to user.

Auto Inserting Logged In Users Username in Django

In the Django Administrative Interface I'd like to Automatically Insert a logged in users username along with a blog post when the publish it, currently I have it displaying every user in a drop down to select from but obviously this is not great so I'd like it to automatically input this.
Here is my code:
models.py
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Post(models.Model):
title = models.CharField(max_length=200)
body = models.TextField()
published_date = models.DateTimeField('date published')
author = models.ForeignKey(User, db_column="published_who")
def __unicode__(self):
return self.title
admin.py
from blog.models import Post
from django.contrib import admin
class PostAdmin(admin.ModelAdmin):
def save_model(self, request, obj, form, change):
obj.author = request.user
obj.save()
admin.site.register(Post, PostAdmin)
Many Thanks!
As I understand issue you need to exclude author from admin form:
class PostAdmin(admin.ModelAdmin):
exclude = ['author']
What you should use is in the Django docs: https://docs.djangoproject.com/en/1.3/ref/contrib/admin/#django.contrib.admin.ModelAdmin.formfield_for_foreignkey
You can overwrite the default behaviour of a ForeignKeyField in the admin with this.
Something along the lines of:
def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
if db_field.name == "author":
kwargs["initial"] = request.user
return super(PostAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
*This is untested
EDIT:
I didn't know whether you wanted to entirely disable the dropdown. With this method you wont. Instead you will have a default value of request.user but still be able to select another user.
If you want to make it a drop down with only one selection (weird behaviour :P) you could add:
kwargs["queryset"] = Post.objects.filter(author=request.user)

Connect to User Model in Django

Quick (probably foolish) question. This is the flow of my site: User logs in and is redirected to a custom admin page. On this admin page they have the ability to make a 'Profile'. I want to associate the Profile they create with their User data such that 1 User associates to 1 Profile.
For some reason the following isn't working (simply trying to associate
UserAdmin.Models
from django.db import models
from django.contrib.auth.models import User
class Profile(models.Model):
username = models.ForeignKey(User)
firstname = models.CharField(max_length=200)
lastname = models.CharField(max_length=200)
email = models.EmailField(max_length=200)
def __unicode__(self):
return self.username
UserAdmin.Views
def createprofile(request):
user = User.objects.get(id=1)
profile = Profile(username=user, firstname='Joe', lastname='Soe', email='Joe#Soe.com')
profile.save()
I keep getting: table useradmin_profile has no column named username_id
Any ideas? Appreciated.
EDIT:
Deleted my db and ran a fresh syncdb, changed to username = models.OneToOneField(User). Now I cam getting Cannot assign "u'superuser'": "Profile.username" must be a "User" instance.
UserAdmin.Models
from django.db import models
from django.contrib.auth.models import User
class Profile(models.Model):
user = models.OneToOneField(User)
def __unicode__(self):
return self.user.get_full_name()
UserAdmin.Views
def createprofile(request):
user_ = User.objects.get(pk=1)
profile = Profile(user=user_)
profile.user.first_name = 'Joe'
profile.user.last_name = 'Soe'
profile.user.email = 'Joe#Soe.com'
profile.user.save()
profile.save()
You syncdb'ed the Profile model before you had a username ForeignKey field. Django will only create tables but will not alter them once they have been created. Here an answer listing your options:
https://stackoverflow.com/a/7693297/990224.
And you should think about renaming username to user.

Categories

Resources