J'ai donc étendu mon utilisateur avec le champ score
comme ceci:
models.py:
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
score = models.IntegerField(default=0);
qui semblait aller dans le sens de la manière recommandée .
Ensuite, j'ai essayé d'accéder au userprofile
de l'utilisateur dans mes vues:
views.py:
player = request.user.userprofile
qui semblait également correspondre à la méthode recommandée, mais c'est là que je reçois mon erreur:
RelatedObjectDoesNotExist
User has no userprofile.
Si je change userprofile
en quelque chose d'autre, j'obtiens une autre erreur:
AttributeError
'User' object has no attribute 'flowerpot'
Lorsque j'essaie le code suivant:
print request.user
print UserProfile.objects.all()
J'obtiens la sortie console:
post_test1
[]
[~ # ~] modifier [~ # ~]
J'ai deux superutilisateurs, sept utilisateurs que j'ai créés avant d'étendre l'utilisateur et un utilisateur (post_test1) que j'ai créé après avoir étendu l'utilisateur.
EDIT 2
Il semble clair que ce dont j'ai besoin est de créer un gestionnaire post_save
Qui crée un nouveau profil chaque fois que l'objet User est créé.
Cela semblait assez simple quand je l'ai lu, je suis allé à la page à laquelle était lié, qui était une liste de tous les signaux Django envoie. J'ai recherché post_save
Et il a dit:
Comme pre_save, mais envoyé à la fin de la méthode save ().
Très bien, donc je recherche pre_save
Et ça dit:
Il est envoyé au début de la méthode save () d'un modèle.
Je l'ai interprété comme ceci: lorsque je crée mon utilisateur (dans mon views.py
), La méthode save()
doit être appelée, ce qui n'a pas été le cas jusqu'à présent, et après cela un post_save
doit être envoyé (?), ce qui créera un nouveau profil à chaque création de l'objet Utilisateur!
Alors maintenant, je suis prêt à commencer à regarder des exemples, alors je google:
Django post save example
Ici on dirait que je suis censé ajouter quelque chose qui ressemble à un décorateur @receiver(post_save, ...
Ici on dirait que je suis censé modifier plusieurs fichiers et écrire une définition de signal?
Celui-ci semble également impliquer plusieurs fichiers (y compris un signals.py
)
Il semble qu'il y ait beaucoup plus que je ne le pensais au départ. Quelqu'un ici pourrait-il expliquer comment je dois procéder ou me montrer de bonnes ressources sur le fonctionnement des signaux?
En ce moment, ma vue create_user
Ressemble à ceci:
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})
Dois-je appeler new_user.save()
avant de revenir? Si oui, pourquoi cela a-t-il fonctionné jusqu'à présent? J'ai un groupe d'utilisateurs que j'ai créés en testant cette vue. Il semble également quelque part ici post_save.connect(create_profile, sender=User)
devrait être ajouté?
Vous devez d'abord créer un userprofile
pour l'utilisateur:
profile = UserProfile.objects.create(user=request.user)
Dans votre views.py, vous pouvez utiliser get_or_create
pour qu'un profil utilisateur soit créé pour un utilisateur s'il n'en a pas.
player, created = UserProfile.objects.get_or_create(user=request.user)
UPDATE : Pour créer automatiquement des profils utilisateur chaque fois qu'un nouvel utilisateur est créé, utilisez des singals. Dans myapp/signals.py
faites quelque chose comme ceci:
@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()
Rien dans ce que vous avez fait ne force la création d'un objet UserProfile
lorsqu'un User
est créé. Il existe deux méthodes de base pour gérer cela:
Si vous voulez toujours qu'un UserProfile
existe (ce qui semble être le cas lorsque vous donnez une valeur de default
à score
, créez un post_save
gestionnaire qui crée un nouveau profil chaque fois que l'objet User
est créé (mais pas à chaque fois qu'il est enregistré, assurez-vous donc de vérifier l'argument created
dans le gestionnaire).
S'il est prévu qu'un utilisateur ne dispose pas d'un profil, vous devez intercepter l'exception UserProfile.DoesNotExist
Lorsque vous essayez d'y accéder. Si vous le faites fréquemment, créez une sorte de fonction d'assistance.
MISE À JOUR DE LA RÉPONSE À LA QUESTION DE SIGNAL
Il semble également quelque part ici
post_save.connect(create_profile, sender=User)
devrait être ajouté?
Vous devez définir une fonction appelée create_profile
, Puis la câbler comme vous l'avez montré. Je le fais généralement dans le fichier models.py
Qui inclut le sender
mais dans ce cas où l'expéditeur est un modèle intégré Django et vous êtes déjà en train d'importer ce modèle dans le fichier où vous définissez votre UserProfile
c'est l'endroit où le faire. Cela ressemblerait à quelque chose comme:
def create_profile(sender, instance, created, *args, **kwargs):
# ignore if this is an existing User
if not created:
return
UserProfile.objects.create(user=instance)
post_save.connect(create_profile, sender=User)
Si vous obtenez cette erreur même si vous avez essayé les suggestions ci-dessus, cela peut être dû au fait que le premier utilisateur que vous avez créé (avec la commande createuperuser) n'a pas de profil.
J'obtenais cette erreur lorsque j'ai essayé de me connecter avec cet utilisateur. Je l'ai résolu de cette façon:
-Créer un nouvel utilisateur.
- Annulez les changements. (Effacez le code que vous avez écrit pour Profile ou faites-en des lignes de commentaires)
- Connectez-vous à votre superutilisateur.
-Donner l'autorisation d'administrateur à l'utilisateur nouvellement créé.
Vous pouvez maintenant supprimer le premier utilisateur. (L'utilisateur sans profil)
Enregistrez d'abord le modèle de profil dans admin.py si ce n'est déjà fait.
Créez un nouveau superutilisateur à l'aide de ./manage.py createuperuser.
Connectez-vous avec le nouveau superutilisateur.
Dans le panneau d'administration, cliquez sur Profil et ajoutez une nouvelle entrée et sélectionnez l'utilisateur dans la liste déroulante des utilisateurs et enregistrez.
Répondre à votre question mise à jour. Il existe déjà une méthode save () dans les modèles et elle est appelée à chaque fois que vous enregistrez un modèle (dans votre cas, lorsque vous appelez create_user ()). Il vous suffit donc de définir une fonction de gestionnaire et de la connecter au signal post_save.
def create_extension (expéditeur, instance, créé, * args, ** kwargs): si créé: # faites votre truc modèles .signals.post_save.connect (create_extension, sender = User, dispatch_uid = 'create_extension')
Je place généralement les fonctions de gestionnaire dans un fichier séparé signaux.py et ajoute des instructions connect () à la fin de models.py
Essayez simplement de créer un nouvel utilisateur à l'aide de Shell pour accéder à la page d'administration, puis créez un profil à partir de la page d'administration pour l'ancien utilisateur: python manage.py createuperuser
Pour accéder à Shell, dans votre projet d'annuaire, entrez le type de terminall: python manage.py Shell