I have a user registration form in my Django application which collects additional data while a user is trying to register such as address, city, country, phone number etc.
This data is saved in the Account model class through post_save
signal. The user creation process goes something like this :
# Function to Create user Account/Profile def create_user_account(sender, instance, created, **kwargs): if created: models.Account.objects.create(user=instance) # Create User / User Registration def UserRegistration(request): if request.method == 'POST': username = request.POST['fn'].capitalize() + ' ' + request.POST['ln'].capitalize() # CREATE USER newuser = User.objects.create_user(username=username, email=request.POST['email'], password=request.POST['pw']) newuser.first_name = request.POST['fn'].capitalize() newuser.last_name = request.POST['ln'].capitalize() newuser.save() return HttpResponse(username) #Post Save handler to create user Account/Profile post_save.connect(create_user_account, sender=User)
Here the UserRegistration
function is called when a user posts a form and under this function, I can get the POST data, what I want is to pass that data to create_user_account
method so that it fills in the fields in the Account
model.
Right now, I do see Account
objects created in the database, but all the fields except the user field are empty. Obviously, because the POST variables are not being passed to the create_user_account
method.
What I do is to set some '_attrs' to the instance and then use them in the signal handler.
I imagine your case could be:
# Function to Create user Account/Profile def create_user_account(sender, instance, created, **kwargs): if created: attrs_needed = ['_language', '_field', '_otherfield'] if all(hasattr(instance, attr) for attr in attr_needed): models.Account.objects.create( user=instance, language=instance._language, field=instance._field, otherfield=instance._otherfield) # Create User / User Registration def UserRegistration(request): if request.method == 'POST': username = request.POST['fn'].capitalize() + ' ' + request.POST['ln'].capitalize() # CREATE USER newuser = User.objects.create_user( username=username, email=request.POST['email'], password=request.POST['pw']) newuser.first_name = request.POST['fn'].capitalize() newuser.last_name = request.POST['ln'].capitalize() # Set some extra attrs to the instance to be used in the handler. newuser._language = request.POST['language'] newuser._field = request.POST['field'] newuser._otherfield = request.POST['otherfield'] newuser.save() return HttpResponse(username) #Post Save handler to create user Account/Profile post_save.connect(create_user_account, sender=User)
I hate to do this, and I imagine it can breaks in horrible ways, and is hard to debug sometimes, also there is no a strict way to force the data needed for the handler, one could define a signal_data(data, signal, instance)
to define the data needed for the signal handler for a particular instance.
A nice option that I haven't tried is to use methods of the instance as signal's handlers and maybe we can use a more structured way to pass the data.
Bye.
Both User.objects.create_user
and User.objects.create
immediately triggers the post_save
handler, because the save
is called in the UserManager
create_user
. So I cannot imagine how Jorge's answer can work (at least if you want the save to be triggered only once - why would you trigger it twice???). What you want to do is to look into what create_user
does, dissect it and this way you can really control when the save
is called:
# Function to Create user Account/Profile def create_user_account(sender, instance, created, **kwargs): if created: attrs_needed = ['_language', '_field', '_otherfield'] if all(hasattr(instance, attr) for attr in attr_needed): models.Account.objects.create( user=instance, language=instance._language, field=instance._field, otherfield=instance._otherfield) # Create User / User Registration def UserRegistration(request): if request.method == 'POST': username = request.POST['fn'].capitalize() + ' ' + request.POST['ln'].capitalize() # CREATE USER newuser = User( username=username, email=request.POST['email'], first_name=request.POST['fn'].capitalize() last_name = request.POST['ln'].capitalize() ) newuser.set_password(request.POST['pw']) # Set some extra attrs to the instance to be used in the handler. newuser._language = request.POST['language'] newuser._field = request.POST['field'] newuser._otherfield = request.POST['otherfield'] newuser.save() # Now this will be really the first save which is called return HttpResponse(username) #Post Save handler to create user Account/Profile post_save.connect(create_user_account, sender=User, weak=False)
Note that I also use the weak=False
when I hook up the handler.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With