Django 信号通过监听 User 创建 UserProfile,但它是空的?

问题描述 投票:0回答:0

我是 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)

python django django-views django-signals django-custom-user
© www.soinside.com 2019 - 2024. All rights reserved.