So I've extended my user with the field score
like this:
models.py:
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
score = models.IntegerField(default=0);
which seemed to be along the lines of the recommended way.
Then I tried to access the user's userprofile
in my views:
views.py:
player = request.user.userprofile
which seemed to align with the recommended way as well, but that is where I get my error:
RelatedObjectDoesNotExist
User has no userprofile.
If I change userprofile
to something else I get another error:
AttributeError
'User' object has no attribute 'flowerpot'
When I try the following code:
print request.user
print UserProfile.objects.all()
I get the console output:
post_test1
[]
EDIT
I have two superusers, seven users I created before extending the user, and one user (post_test1) that I created after extending the user.
EDIT 2
It seams clear that what I need is to create a post_save
handler that creates a new profile whenever the User object is created.
This seemed simple enough when I read it, went to the page that was linked to, which was a list of all the signals Django sends. I looked up post_save
and it said:
Like pre_save, but sent at the end of the save() method.
Alright, so I look up pre_save
and it says:
This is sent at the beginning of a model’s save() method.
I've interpreted it like this: When I create my user (in my views.py
) the save()
method should be called, which hasn't been the case up until now, and after that a post_save
should be sent(?), which will create a new profile whenever the User object is created!
So now I'm ready to start looking at examples, so I google:
django post save example
Here it looks like I'm supposed to add something that looks like a decorator @receiver(post_save, ...
Here it looks like I'm supposed to alter multiple files and write a signal definition?
This one also seems to imply multiple files (including a signals.py
)
It looks like there's a lot more to it than I first thought. Could anyone here either explain how I'm to do this or show me to some good resources on how signals work?
Right now my create_user
view look like this:
def create_user(request):
if request.method == "POST":
form = UserCreationForm(request.POST)
if form.is_valid():
username = form.cleaned_data["username"]
password = form.cleaned_data["password1"]
new_user = User.objects.create_user(username=username, password=password)
return redirect('play')
else:
form = UserCreationForm()
return render(request, 'antonymapp/create_user.html', {'form': form})
Should I call new_user.save()
before returning? If yes, why has it worked up until now? I have a bunch of users that I've created while testing this view. It also looks like somewhere around here post_save.connect(create_profile, sender=User)
should be added?
You have to create a userprofile
for the user first:
profile = UserProfile.objects.create(user=request.user)
In your views.py you can use get_or_create
so that a userprofile is created for a user if the user doesn't have one.
player, created = UserProfile.objects.get_or_create(user=request.user)
UPDATE: For automatically creating user profiles every time a new user is made, use singals. In myapp/signals.py
do something like this:
@receiver(post_save, sender=User, dispatch_uid='save_new_user_profile')
def save_profile(sender, instance, created, **kwargs):
user = instance
if created:
profile = UserProfile(user=user)
profile.save()