Erstellen eines erweiterten Benutzerprofils
-
19-09-2019 - |
Frage
Ich habe ein erweitertes Benutzerprofilmodell in Django:
class UserProfile(models.Model):
user = models.ForeignKey(User, unique=True)
#other things in that profile
Und ein Signale.py:
from registration.signals import user_registered
from models import UserProfile
from django.contrib.auth.models import User
def createUserProfile(sender, instance, **kwargs):
profile = users.models.UserProfile()
profile.setUser(sender)
profile.save()
user_registered.connect(createUserProfile, sender=User)
Ich stelle sicher, dass das Signal registriert wird, indem Sie dies in meinem haben __init__.py
:
import signals
Das sollte mir also ein neues Benutzerprofil für jeden Benutzer erstellen, der sich registriert, oder? Aber es tut es nicht. Ich erhalte immer "userProfile -Matching -Abfrage existiert keine Fehler", wenn ich versuche, mich anzumelden, was bedeutet, dass der Datenbankeintrag nicht vorhanden ist.
Ich sollte sagen, dass ich die Django-Registrierung verwende, die das user_registrierte Signal liefert.
Die Struktur der wichtigen Apps dafür ist, dass ich eine Anwendung namens "Benutzer" habe, dort habe ich: Models.py, signals.py, urls.py und views.py (und einige andere Dinge, die hier keine Rolle spielen sollten ). Die UserProfile -Klasse ist in models.py definiert.
Aktualisieren: Ich habe die Signale geändert.py in:
from django.db.models.signals import post_save
from models import UserProfile
from django.contrib.auth.models import User
def create_profile(sender, **kw):
user = kw["instance"]
if kw["created"]:
profile = UserProfile()
profile.user = user
profile.save()
post_save.connect(create_profile, sender=User)
Aber jetzt bekomme ich einen "IntegrityError":
"Spalten user_id ist nicht eindeutig"
Bearbeiten 2:
Ich habe es gefunden. Sieht so aus, als hätte ich das Signal zweimal registriert. Die Problemumgehung dafür wird hier beschrieben: http://code.djangoproject.com/wiki/signals#helppost_saveseemStookentTwiceforeachsave
Ich musste einen Dispatch_Uid hinzufügen, jetzt sieht meine Signale so aus und wirkt:
from django.db.models.signals import post_save
from django.contrib.auth.models import User
from models import UserProfile
from django.db import models
def create_profile(sender, **kw):
user = kw["instance"]
if kw["created"]:
profile = UserProfile(user=user)
profile.save()
post_save.connect(create_profile, sender=User, dispatch_uid="users-profilecreation-signal")
Lösung
Sie können es mit post_save im Benutzer implementieren:
from django.db.models.signals import post_save
from models import UserProfile
from django.contrib.auth.models import User
def create_profile(sender, **kwargs):
user = kwargs["instance"]
if kwargs["created"]:
profile = users.models.UserProfile()
profile.setUser(sender)
profile.save()
post_save.connect(create_profile, sender=User)
Bearbeiten:
Eine andere mögliche Lösung, die getestet und funktioniert (ich verwende sie auf meiner Website):
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
def create_profile(sender, **kwargs):
user = kwargs["instance"]
if kwargs["created"]:
up = UserProfile(user=user, stuff=1, thing=2)
up.save()
post_save.connect(create_profile, sender=User)
Andere Tipps
Sie können das erweiterte Profil erstellen lassen, wenn er stattdessen zuerst für jeden Benutzer zugegriffen wird:
from django.db import models
from django.contrib.auth.models import User
class UserProfile(models.Model):
user = models.ForeignKey(User, unique=True)
additional_info_field = models.CharField(max_length=50)
User.profile = property(lambda u: UserProfile.objects.get_or_create(user=u)[0])
dann benutze
from django.contrib.auth.models import User
user = User.objects.get(pk=1)
user.profile.additional_info_field
Ref: http://www.codekoala.com/blog/2009/quick-django-tip-user-profiles/
Dies hat mir geholfen: primär_key = true
class UserProfile(models.Model):
user = models.OneToOneField(User, unique=True, primary_key=True, related_name="user")
phone = models.CharField(('phone'),max_length=30, blank=False, null=True)
user_building = models.ManyToManyField(Building, blank=True)
added_by = models.ForeignKey(User, blank=True, null=True, related_name="added")
Wenn du anrufst profile.setUser()
, Ich denke du willst passieren instance
statt sender
als Parameter.
Von dem Dokumentation des user_registered Signal, sender
bezieht sich auf User
Klasse; instance
ist das tatsächliche Benutzerobjekt, das registriert wurde.
Nach meinen neuesten Untersuchungen funktioniert das Erstellen einer separaten Datei, z. B. Singals.py, nicht.
Sie sollten "create_profile" besser mit 'post_save' in deinen Modellen verbinden.
Mein endgültiger Code für Ihre Referenz:
# models.py
# Here goes the definition of class UserProfile.
class UserProfile(models.Model):
...
# Use signal to automatically create user profile on user creation.
# Another implementation:
# def create_user_profile(sender, **kwargs):
# user = kwargs["instance"]
# if kwargs["created"]:
# ...
def create_user_profile(sender, instance, created, **kwargs):
"""
:param sender: Class User.
:param instance: The user instance.
"""
if created:
# Seems the following also works:
# UserProfile.objects.create(user=instance)
# TODO: Which is correct or better?
profile = UserProfile(user=instance)
profile.save()
post_save.connect(create_user_profile,
sender=User,
dispatch_uid="users-profilecreation-signal")
Update für 2018:
Diese Frage hat viele Ansichten gesammelt, vielleicht ist es Zeit für ein Update.
Dies ist die neueste Version für die neueste Django.
from django.dispatch import receiver
from django.db.models.signals import post_save
from django.conf import settings
from models import UserProfile
@receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_user_profile(sender, instance=None, created=False, **kwargs):
if created:
UserProfile.objects.create(user=instance)