I'm a beginner and I'm trying to create a small network project in which users can follow each other. I have implemented the follow button right, so it updates my models and displays proper info to users, but I can't get unfollow to work properly. I'm guessing it's something to do with the way I implemented follow model (with many to many field), but I'd like to implement it this way for practice... Anyhow, here's the code:
Models:
class User(AbstractUser):
pass
class Follow(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="user_follow")
following = models.ManyToManyField(User, blank=True, related_name="followers")
And view:
def users(request, username):
"""Displaying user profiles"""
if request.method == "POST":
user = request.user
profile = User.objects.get(username=username)
follow = Follow(user=user)
follow.save()
if "unfollow" in request.POST:
profile.followers.remove(user)
follow.following.remove(profile)
return HttpResponseRedirect(reverse('users', args=(username,)))
elif "follow" in request.POST:
follow.following.add(profile)
return HttpResponseRedirect(reverse('users', args=(username,)))
This code yields in: "ValueError at /users/test
Cannot query "admin": Must be "Follow" instance." at the profile.followers.remove(user) line...
Playing with it in shell I found out (at least I think so) that the line under it (follow.following.remove(profile) - which by the way was there before I tried with the profile.followers.remove(user)) removes the profile from Follow model, but for some reason it is not by itself updated in the Users model (for followers) ???
from django.db import models
# Create your models here.
class User(models.Model):
name = models.CharField(max_length=40)
pwd = models.CharField(max_length=40)
def __str__(self):
return self.name
class Follow(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
another_user = models.ManyToManyField(User, related_name='another_user')
def __str__(self):
return self.user.name
============================================================================
views.py
from django.shortcuts import render, redirect
from django.http import HttpResponse
from .models import User, Follow
# Create your views here.
def index(request):
if 'user' in request.session:
return render(request, 'index.html')
else:
return redirect('login')
def profile(request, user_name):
user_obj = User.objects.get(name=user_name)
session_user = User.objects.get(name=request.session['user'])
session_following, create = Followers.objects.get_or_create(user=session_user)
following, create = Followers.objects.get_or_create(user=session_user.id)
check_user_followers = Followers.objects.filter(another_user=user_obj)
is_followed = False
if session_following.another_user.filter(name=user_name).exists() or following.another_user.filter(name=user_name).exists():
is_followed=True
else:
is_followed=False
param = {'user_obj': user_obj,'followers':check_user_followers, 'following': following,'is_followed':is_followed}
if 'user' in request.session:
return render(request, 'profile.html', param)
else:
return redirect('index')
def follow_user(request, user_name):
other_user = User.objects.get(name=user_name)
session_user = request.session['user']
get_user = User.objects.get(name=session_user)
check_follower = Followers.objects.get(user=get_user.id)
is_followed = False
if other_user.name != session_user:
if check_follower.another_user.filter(name=other_user).exists():
add_usr = Followers.objects.get(user=get_user)
add_usr.another_user.remove(other_user)
is_followed = False
return redirect(f'/profile/{session_user}')
else:
add_usr = Followers.objects.get(user=get_user)
add_usr.another_user.add(other_user)
is_followed = True
return redirect(f'/profile/{session_user}')
return redirect(f'/profile/{session_user}')
else:
return redirect(f'/profile/{session_user}')
=============================================================================
User This For Reference...Follow And Unfollw Logic
I'm making a stock portfolio app as a personal project. I have a form StockSymbolForm used for buying stocks. It has the fields: username, stock_symbol, and stock_qty.
I've set username to be the current user that's currently using the app - so they only need to fill stock_symbol and stock_qty.
After a valid form is submitted, I go to my admin page to check, but I don't see my new stock_symbol and stock_qty added to my model.
Here's my code:
views.py:
class PortfolioStockListView(ListView):
model = StockPortfolio
template_name = 'stocks.html'
def post(self, request):
current_user = StockPortfolioUser.objects.filter(username=request.user).first()
if request.method == 'POST':
symbol_form = StockSymbolForm(request.POST, initial={'username': current_user})
if symbol_form.is_valid():
symbol_form = StockSymbolForm(request.POST, instance=current_user)
model_instance = symbol_form.save(commit=True)
model_instance.timestamp = timezone.now()
model_instance.save()
return redirect('/')
else:
return render(request, 'stocks.html', {'symbol_form': symbol_form})
else:
symbol_form = StockSymbolForm()
return render(request, 'stocks.html', {'symbol_form': symbol_form})
models.py:
class StockPortfolioUser(models.Model):
username = models.OneToOneField(User, on_delete=models.CASCADE)
usercash = models.PositiveIntegerField(default=100000)
class StockPortfolio(models.Model):
username = models.ForeignKey(StockPortfolioUser, on_delete=models.CASCADE)
stock_symbol = models.CharField(max_length=5)
stock_qty = models.PositiveIntegerField(default=0)
forms.py:
class StockSymbolForm(ModelForm):
class Meta:
model = StockPortfolio
fields = ('stock_symbol' , 'stock_qty')
labels = {'stock_symbol': 'Stock Symbol', 'stock_qty': 'Quantity'}
How do I save the model instance properly? and why is it not saving at the moment?
In your views.py file change this
model_instance = symbol_form.save(commit=False)
model_instance.username = request.user.id
model_instance.timestamp = timezone.now()
model_instance.save()
In StockSymbolForm change this
fields = ('username', 'stock_symbol' , 'stock_qty')
Well, you don't ever seem to be setting the username. You set a timestamp, which doesn't exist as a field, but not the actual username field.
model_instance = symbol_form.save(commit=True)
model_instance.userame = request.user
model_instance.save()
As an aside, that field should be called user, as it points to the whole User object not just the username.
I trying to make auto increment of user_id after the form is filled.
It did appear in cleaned_data, but I still can't make register an account.
forms.py
class RegForm(forms.ModelForm):
password=forms.CharField(widget=forms.PasswordInput())
password_confirm = forms.CharField(widget=forms.PasswordInput())
class Meta:
model = models.UserProfile
fields = ['user_name','password','email','birthday','address']
def clean(self):
user_id = models.UserProfile.user_id
cleaned_data = super(RegForm, self).clean()
password = cleaned_data["password"]
password_confirm = cleaned_data["password_confirm"]
if user_id == None:
self.cleaned_data['user_id'] = 1
else:
self.cleaned_data['user_id'] = models.UserProfile.objects.count() + 1
if password != password_confirm:
raise forms.ValidationError("wrong password")
return self.cleaned_data
def clean_asset_code(self):
user_name = self.cleaned_data['user_name']
if models.UserProfile.objects.filter(user_name=user_name).exists():
raise forms.ValidationError("This user_name already exist.")
return user_name
views.py
def regist(request):
if request.method == 'POST':
register_form = forms.RegForm(request.POST)
if register_form.is_valid():
register_form.save()
return HttpResponseRedirect('/')
else:
register_form = forms.RegForm()
messages.get_messages(request)
template = get_template('regist.html')
request_context = RequestContext(request)
request_context.push(locals())
html = template.render(request_context)
return HttpResponse(html)
You are trying to increase user_id before form is getting validated, I don't think that is a good idea.
To make an auto increment of user_id
What you can do is make user_id a primary key field.
Django Documentation
import uuid
from django.db import models
class UserProfile(models.Model):
user_id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False,serialize=True)
In this way whenever your form passes all validity pass and when submitted the user_id is automatically incremented.
I want to collect the login user's data while using Django. But i don't know how to locate the unique login username when i use django-registration-redux
I have tried to do this, here's my views.py:
from django.shortcuts import render
from yigu.models import Gw, user_data
from django.contrib.auth.models import User
def index(request):
Gw_list = Gw.objects.all()
context_dict = {'cyshici': Gw_list}
return render(request, 'yigu/base.html', context_dict)
def search(request):
if 'gw' in request.GET:
words_1 = request.GET['gw']
result_list = Gw.objects.filter(field_1=words_1)
result_list2 = user_data.objects.filter(word=words_1)
result_list3 = user_data.objects.filter(user=User.username)
# For basic search match and display content
if result_list:
context_dict = {'result_list': result_list}
words = Gw.objects.get(field_1=words_1)
words.views = words.views + 1
words.save()
# For words_information Model
if result_list2 & result_list3:
words2 = user_data.objects.get(word=words_1)
words2.click_times = words2.click_times + 1
words2.save()
else:
words2 = user_data(user=User.username, word=words_1, click_times=words.views)
words2.save()
return render(request, 'yigu/search.html', context_dict)
here's my models.py:
class user_data(models.Model):
user = models.CharField(max_length=255)
word = models.CharField(max_length=255)
click_times = models.IntegerField(default=0)
class Meta:
ordering = ('click_times',)
def __unicode__(self):
return self.user
But the all the username is something like this <class 'django.contrib.auth.models.User'>
Could anyone give me some tips?
User models of using Redux:
from django.contrib.auth.models import User
And add an OneToOneField to user_data:
class UserData(models.Model):
user = models.OneToOneField(User)
clicks = models.IntegerField(default = 0)
def __str__(self):
return self.user.username
I've been struggling with this all week long, and I need to put it to rest once and for all. This might look like a lot of code, but at the core is a simple conceptual question.
I have a model, UserProfile, that has the following fields:
user = models.OneToOneField(User)
weekOne = models.OneToOneField(WeekOne)
weekTwo = models.OneToOneField(WeekTwo)
WeekOne and WeekTwo are both models with their own unique fields (models.Model) that inherit from a custom class called Week. Week just has a few custom functions to save some re-typing of methods for each week and the following code to make it an abstract class:
class Meta:
abstract = True
Basically, I want every user to have a unique weekOne and weekTwo (and beyond) field that has custom fields with values that are unique to the user.
When I first create a user (i.e., when they sign up), I use the following code in views.py:
def signup(request):
user_form = UserCreateForm(data=request.POST)
if request.method == 'POST':
if user_form.is_valid():
username = user_form.clean_username()
password = user_form.clean_password2()
user_form.save()
user = authenticate(username=username, password=password)
login(request, user)
return redirect('/')
else:
return index(request, user_form=user_form)
return redirect('/')
Basic form signup stuff, everything has always worked fine here.
Now, here's where things get dicey. I have a view for weekOne that makes sure a user's profile has been created and creates one if not, the code for which is as follows:
#login_required
def workout1(request):
template = "workout1.html"
weekOne = WeekOne()
weekOne.save()
user, created = UserProfile.objects.get_or_create(user=request.user,
defaults = {'weekOne': weekOne})
name = weekOne.__unicode__()
if created:
context = {'user': user}
return render(request, template, context)
# Grab already existing User Profile
weekOne.delete() # Was never used
context = {'user': user, 'name': name}
return render(request, template, context)
Okay. So that's cool. But when I try to go to the page for week one, I get the following error:
workout_game_app_userprofile.weekTwo_id may not be NULL
This is where I'm lost. Should I be initializing every single week variable for every single week view? I.e., for the week one view, should I be doing code like this:
weekOne = WeekOne()
weekTwo = WeekTwo()
weekThree = WeekThree()
etc.? This seems absurdly repetitive if I have to do it for all 12 weeks I'm planning on implementing.
Btw, my models were functioning perfectly well before I implemented the second week.
Also, is OneToOne the right kind of key to use? I want to do things like access user.weekOne.item1, user.weekOne.item2, etc. and change and save their values only for that user.
UPDATE: For Sidharth Shah, here's the rest of the code from my views and models:
views.py:
from django.shortcuts import render, redirect
from django.contrib.auth import login, authenticate, logout
from django.contrib.auth.models import User
from workout_game_app.forms import AuthenticateForm, UserCreateForm
from workout_game_app.models import WeekOne, WeekTwo, UserProfile
from django.http import Http404, HttpResponse
from django.contrib.auth.decorators import login_required
from django.views.decorators.csrf import csrf_exempt
from django.core import serializers
import simplejson
def index(request, auth_form=None, user_form=None):
if request.user.is_authenticated():
user = request.user
name = "Missions Overview"
context = {'user': user, 'name': name}
template = 'workouts.html'
return render(request, template, context)
else:
auth_form = auth_form or AuthenticateForm()
user_form = user_form or UserCreateForm()
template = 'index.html'
context = {'auth_form': auth_form, 'user_form': user_form}
return render(request, template, context)
def login_view(request):
if request.method == 'POST':
form = AuthenticateForm(data=request.POST)
if form.is_valid():
login(request, form.get_user())
return redirect('/')
else:
return index(request, auth_form=form)
return redirect('/')
def signup(request):
user_form = UserCreateForm(data=request.POST)
if request.method == 'POST':
if user_form.is_valid():
username = user_form.clean_username()
password = user_form.clean_password2()
user_form.save()
user = authenticate(username=username, password=password)
login(request, user)
return redirect('/')
else:
return index(request, user_form=user_form)
return redirect('/')
#login_required
def submitWorkout1(request):
if request.method == 'POST':
exercise = request.POST['exercise']
try:
amount = request.POST['amount']
except KeyError: # No amount field on form
amount = ""
user = UserProfile.objects.get(user=request.user)
week = user.weekOne
exercise, amount, exerciseComplete, allComplete = user.updateExercise(week, exercise, amount)
data = simplejson.dumps({
'result': 'success',
'exercise': exercise,
'amount': amount,
'exerciseComplete': exerciseComplete,
'allComplete': allComplete
}, indent=4)
return HttpResponse(data)
#login_required
def workout2(request):
template = "workout2.html"
weekTwo = WeekTwo()
weekTwo.save()
user, created = UserProfile.objects.get_or_create(user=request.user,
defaults = {'weekTwo': weekTwo})
name = weekTwo.__unicode__()
if created:
context = {'user': user}
return render(request, template, context)
# Grab already existing User Profile
weekTwo.delete() # Was never used
context = {'user': user, 'name': name}
return render(request, template, context)
#login_required
def submitWorkout2(request):
if request.method == 'POST':
exercise = request.POST['exercise']
try:
amount = request.POST['amount']
except KeyError: # No amount field on form
amount = ""
user = UserProfile.objects.get(user=request.user)
week = user.weekTwo
exercise, amount, exerciseComplete, allComplete = user.updateExercise(week, exercise, amount)
data = simplejson.dumps({
'result': 'success',
'exercise': exercise,
'amount': amount,
'exerciseComplete': exerciseComplete,
'allComplete': allComplete
}, indent=4)
return HttpResponse(data)
and models.py:
from django.db import models
from django.contrib.auth.models import User
class Week(models.Model):
# List of exercises by name for the week
exercises = []
# Week name in unicode
name = u''
# Running count of benchmarks met.
completeCount = models.PositiveSmallIntegerField(default=0)
# Set to true if benchmarks reached.
weekComplete = models.BooleanField(default=False)
# A bunch of methods
class WeekOne(Week):
name = u'Mission One'
exercises = ['squats', 'lunges', 'stairDaysCount', 'skipStairs']
# Required benchmarks for given exercises
squatBenchmark = 1000
lungeBenchmark = 250
stairDaysCountBenchmark = 3
totalGoals = 4
squats = models.PositiveIntegerField(default=0)
lunges = models.PositiveIntegerField(default=0)
skipStairs = models.BooleanField(default=False)
stairDaysCount = models.PositiveSmallIntegerField(default=0)
# A bunch of methods
class WeekTwo(Week):
name = u'Mission Two'
exercises = ['up3Levels', 'noHands', 'treadmill', 'vagMachine', 'extendedStairs']
totalGoals = 5
up3Levels = models.BooleanField(default=False)
noHands = models.BooleanField(default=False)
treadmill = models.BooleanField(default=False)
vagMachine = models.BooleanField(default=False)
extendedStairs = models.BooleanField(default=False)
# A bunch of methods
class UserProfile(models.Model):
user = models.OneToOneField(User)
weekOne = models.OneToOneField(WeekOne, null=True, default=None)
weekTwo = models.OneToOneField(WeekTwo, null=True, default=None)
# Some methods
and, though it works fine, my forms.py for good measure:
from django.contrib.auth.forms import AuthenticationForm, UserCreationForm
from django.contrib.auth.models import User
from django import forms
from django.utils.html import strip_tags
class UserCreateForm(UserCreationForm):
username = forms.CharField(required=True,
widget = forms.widgets.TextInput(attrs={'placeholder': 'Username'}))
password1 = forms.CharField(required=True,
widget = forms.widgets.PasswordInput(attrs={'placeholder': 'Password'}))
password2 = forms.CharField(required=True,
widget = forms.widgets.PasswordInput(attrs={'placeholder': 'Password'}))
def is_valid(self):
form = super(UserCreateForm, self).is_valid()
for f, error in self.errors.iteritems():
if f != '__all_':
self.fields[f].widget.attrs.update({'class':'error', 'value':strip_tags(error)})
return form
class Meta:
fields = ['username', 'password1', 'password2']
model = User
class AuthenticateForm(AuthenticationForm):
username = forms.CharField(
widget = forms.widgets.TextInput(attrs={'placeholder':'Username'}))
password2 = forms.CharField(
widget = forms.widgets.PasswordInput(attrs={'placeholder': 'Password'}))
You might want to have following model
user = models.OneToOneField(User)
weekOne = models.OneToOneField(WeekOne, null=True, default=None)
weekTwo = models.OneToOneField(WeekTwo, null=True, default=None)
Try that out, it should work. Looking at the code above you're defining fields weekOne, weekTwo etc. What I am not sure of is if you're assigning all necessary fields weekOne object while creating it.