我是 Django 的新手,正在尝试创建一个信号来监听我构建的自定义用户模型。我的意图是当一个新用户被创建时,他们的配置文件也会自动创建。
对我来说,似乎我的信号本身有效,因为当我使用 /admin 屏幕时,我可以添加一个用户,它会自动创建他们的配置文件。 但是,当我尝试通过应用程序的前端添加新用户时,信号似乎确实检测到正在创建新用户并为他们创建配置文件。但是当我进入 /admin 屏幕查看它时,它是空的。
当我说空时,我的意思是创建了配置文件记录,但没有填充任何字段。这会导致我的应用程序出现更多错误,因为我无法使用用户来提取用户的个人资料并呈现它,因为它是空的并且没有连接到用户。
我做错了什么?我的直觉是我的视图函数有问题。
registerUserParticipant
和 registerUserSupervisor
在前端创建新用户时被调用。 editAccount
目前也抛出错误,因为它是在用户注册后触发的,因为request.user.profileparticipant
找不到用户的个人资料。
userprofiles/models.py
from django.db import models
from django.contrib.auth.models import AbstractUser
import uuid
# Create your models here.
class User(AbstractUser):
is_supervisor = models.BooleanField(default=False)
is_participant = models.BooleanField(default=False)
created = models.DateTimeField(auto_now_add=True) #auto_now_add, creates automatic timestamp
class ProfileParticipant(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, null=True, blank=True) #when a user is deleted a profile is deleted
first_name = models.CharField(max_length=200, blank=True, null=True)
last_name = models.CharField(max_length=200, blank=True, null=True)
username = models.CharField(max_length=200, blank=True, null=True)
email = models.EmailField(max_length=500, blank=True, null=True)
profile_image = models.ImageField(null=True, blank=True, upload_to='profiles/', default='profiles/user-default.png')
created = models.DateTimeField(auto_now_add=True) #auto_now_add, creates automatic timestamp
id = models.UUIDField(default=uuid.uuid4, unique= True,
primary_key=True, editable=False) # UUID is a 16 character string of number and letters, helps with scalability
# organisation
# participant_group
def __str__(self):
return str(self.username)
@property
def imageURL(self):
try:
url = self.profile_image.url
except:
url = ''
return url
class ProfileSupervisor(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, null=True, blank=True) #when a user is deleted a profile is deleted
first_name = models.CharField(max_length=200, blank=True, null=True)
last_name = models.CharField(max_length=200, blank=True, null=True)
username = models.CharField(max_length=200, blank=True, null=True)
email = models.EmailField(max_length=500, blank=True, null=True)
profile_image = models.ImageField(null=True, blank=True, upload_to='profiles/', default='profiles/user-default.png')
title = models.CharField(max_length=200, blank=True, null=True)
short_intro = models.CharField(max_length=200, blank=True, null=True)
description = models.TextField()
created = models.DateTimeField(auto_now_add=True) #auto_now_add, creates automatic timestamp
id = models.UUIDField(default=uuid.uuid4, unique= True,
primary_key=True, editable=False) # UUID is a 16 character string of number and letters, helps with scalability
# org
# supervisor_group
def __str__(self):
return str(self.username)
@property
def imageURL(self):
try:
url = self.profile_image.url
except:
url = ''
return url
userprofiles/signals.py
from django.db.models.signals import post_save, post_delete
from django.dispatch import receiver
from .models import User
from .models import ProfileParticipant, ProfileSupervisor
from django.core.mail import send_mail
from django.conf import settings
#don't forget to register your signals with apps.py
@receiver(post_save, sender=settings.AUTH_USER_MODEL) #listens to user model, we want it to notice if a new user is added and create a profile
def createProfile(sender, instance, created, **kwargs):
print('Profile signal triggered')
if created:
user = instance
if user.is_supervisor == True:
ProfileSupervisor.objects.create(user=user,username=user.username,email=user.email,first_name= user.first_name,last_name = user.last_name).save()
# profile.save()
elif user.is_participant == True:
profile = ProfileParticipant.objects.create(user=user,username=user.username,email=user.email,first_name= user.first_name,last_name = user.last_name)
profile.save()
# subject = 'Welcome to DevSearch'
# message = "We are glad you are here!"
# send_mail(
# subject,
# message,
# settings.EMAIL_HOST_USER,
# [profile.email],
# fail_silently=False,
# )
@receiver(post_save, sender=ProfileParticipant)
def updateUserParticipant(sender, instance, created, **kwargs):
profile = instance
user = profile.user
if created == False: #ensures consistency between user and profile (avoid recursion erorr)
# User.objects.create(username=profile.username, email=profile.username, first_name=profile.first_name, last_name=profile.last_name, is_participant=True)
# else:
user.first_name = profile.first_name
user.last_name = profile.last_name
user.username = profile.username
user.email = profile.email
user.is_participant = True
user.save()
@receiver(post_save, sender=ProfileSupervisor)
def updateUserSupervisor(sender, instance, created, **kwargs):
profile = instance
user = profile.user
if created == False: #ensures consistency between user and profile (avoid recursion erorr)
user.first_name = profile.name
user.username = profile.username
user.email = profile.email
user.save()
@receiver(post_delete, sender=ProfileSupervisor) #listens to profile, we want it to notice if a profile is delete and delete the user too
def deleteUserSupervisor(sender, instance, **kwargs):
try:
user = instance.user
user.delete()
except:
pass
@receiver(post_delete, sender=ProfileParticipant) #listens to profile, we want it to notice if a profile is delete and delete the user too
def deleteUserParticipant(sender, instance, **kwargs):
try:
user = instance.user
user.delete()
except:
pass
# post_save.connect(profileUpdated, sender=Profile) #you can do it like this if you don't want to use the decorator
# post_delete.connect(deleteUser, sender=Profile)
views.py
from django.shortcuts import render, redirect
from .models import ProfileParticipant, ProfileSupervisor
from django.contrib.auth.models import User
from django.contrib.auth import get_user_model
from django.contrib import messages
from django.contrib.auth import login, authenticate, logout
from .forms import CustomUserCreationForm, ProfileFormParticipant, ProfileFormSupervisor
from django.contrib.auth.decorators import login_required #this decorator can sit above any view we want to block
# Create your views here.
def profiles(request):
profilesParticipant = ProfileParticipant.objects.all()
profilesSupervisor = ProfileSupervisor.objects.all()
context = {'profilesParticipant':profilesParticipant, 'profilesSupervisor':profilesSupervisor}
return render(request,'userprofiles/profiles.html', context)
def userProfileParticipant(request, pk):
profile = ProfileParticipant.objects.get(id=pk)
context = {'profile':profile}
return render(request, 'userprofiles/user-profile.html', context)
def userProfileSupervisor(request, pk):
profile = ProfileSupervisor.objects.get(id=pk)
context = {'profile':profile}
return render(request, 'userprofiles/user-profile.html', context)
def loginUser(request):
page = 'login' #get rid of this?
if request.user.is_authenticated: #if the user if logged in, don't let them be seeing the log in page
return redirect('profiles')
if request.method == "POST":
username = request.POST['username'].lower()
password = request.POST['password']
try:
user = User.objects.get(username=username)
except:
messages.error(request, 'Username does not exist')
user = authenticate(request, username=username, password=password) #makes sure the username and password match, if they do it'll return the user instance, if not, it'll return none
if user is not None:
login(request, user) #this will create a session for theuser in the db, it'll add that session into the browser's cookies
return redirect(request.GET['next'] if 'next' in request.GET else 'account')
else:
messages.error(request, 'Username OR password is incorrect') #basically authenticate returned None
context = {'page':page}
return render(request, 'userprofiles/login_register.html', context)
def logoutUser(request):
logout(request)
messages.info(request, 'User was logged out')
return redirect('login')
def registerLanding(request):
return render(request, 'userprofiles/register-landing.html')
def registerUserParticpant(request):
page= "register"
usertype= "participant"
userform = CustomUserCreationForm()
profileform = ProfileFormParticipant()
if request.method == "POST":
userform = CustomUserCreationForm(request.POST) #send form info to back end
profileform = ProfileFormParticipant(request.POST)#send info to back end
if userform.is_valid():
user = userform.save(commit=False) #commit=False lets a temporary instance hang before processing.
user.username = user.username.lower() #could do this from the form directly and not use commit=false
user.save() #at this point the user will be added to the database and saved, the signals we set up will also take care of automatically setting up the profile
# if profileform.is_valid():
# profileform.save()
messages.success(request, 'User account was created!')
login(request, user)
return redirect('edit-account')
else:
messages.error(request, 'An error has occurred during registration')
context = {'userform':userform, 'profileform':profileform, 'page':page, 'usertype':usertype}
return render(request, 'userprofiles/login_register.html', context)
def registerUserSupervisor(request):
page= "register"
usertype= "supervisor"
userform = CustomUserCreationForm()
profileform = ProfileFormSupervisor()
if request.method == "POST":
userform = CustomUserCreationForm(request.POST) #send form info to back end
profileform = ProfileFormSupervisor(request.POST)#send info to back end
if userform.is_valid():
user = userform.save(commit=False) #commit=False lets a temporary instance hang before processing.
user.username = user.username.lower() #could do this from the form directly and not use commit=false
user.save() #at this point the user will be added to the database and saved, the signals we set up will also take care of automatically setting up the profile
if profileform.is_valid():
profileform.save()
messages.success(request, 'User account was created!')
login(request, user)
return redirect('edit-account')
else:
messages.error(request, 'An error has occurred during registration')
context = { 'userform':userform,'profileform':profileform, 'page':page, 'usertype':usertype}
return render(request, 'userprofiles/login_register.html', context)
@login_required(login_url='login')
def userAccount(request):
profile = request.user.profileparticipant #will get you the logged in user
records = profile.feelingsscalerecord_set.all()
context = {'profile':profile, 'records':records}
return render(request, 'userprofiles/account.html', context)
@login_required(login_url='login')
def editAccount(request):
profile = request.user.profileparticipant
form = ProfileFormParticipant(instance=profile)
if request.method == "POST":
form = ProfileFormParticipant(request.POST, request.FILES, instance=profile)
if form.is_valid():
form.save()
return redirect('account')
context = {'form':form}
return render(request, 'userprofiles/profile_form.html', context)