views:

363

answers:

1

I have found here on stackoverflow a solution to extend django-registration with new fields using signals. Here's the link : http://dmitko.ru/?p=546 .
I have created extended profile model, extended form, added required options to settings , defined urls and the proper form is displayed but only normal User (from auth module) is created. Why is that happening ?

account.models :

from django.db import models
from django.contrib.auth.models import User
from registration.signals import user_registered
import hashlib

class InheritedProfile(models.Model):
    first_name = models.CharField("Name", max_length=50, blank=True, null=True)
    last_name = models.CharField("Last name", max_length=50, blank=True, null=True)
    pid = models.CharField("PESEL", max_length=11, blank=True, null=True)
    street = models.CharField("Street", max_length=50, blank=True, null=True)
    number = models.CharField("Flat/house number", max_length=10, blank=True, null=True)
    code = models.CharField("Zip ", max_length=6, blank=True, null=True)
    city = models.CharField("City", max_length=50, blank=True, null=True) 
    class Meta:
        abstract=True

class UserProfile(InheritedProfile, User):
    def upload_path(self, field_attname):
        filename = hashlib.md5(field_attname).hexdigest()[:4] + "_" + field_attname
        return "uploads/users/%s" % (filename,)

    image = models.ImageField(upload_to=upload_path, verbose_name="Image", blank=True, null=True)

    def user_created(sender, user, request, **kwargs):
        form = ExtendedRegistrationForm(request.POST)
        extended_user = UserProfile(user=user)
        extended_user.is_active = False
        extended_user.first_name = form.extended_user['first_name']
        extended_user.last_name = form.extended_user['last_name']
        extended_user.pid = form.extended_user['pid']
        extended_user.image = form.extended_user['image']
        extended_user.street = form.extended_user['street']
        extended_user.number = form.extended_user['number']
        extended_user.code = form.extended_user['code']
        extended_user.city = form.extended_user['city']
        extended_user.save()

    user_registered.connect(user_created)

I need this InheritedProfile to be abstract as other models will use the same fields.

account.forms

from django import forms
#import strings
from registration.forms import RegistrationForm
from models import UserProfile, InheritedProfile

class ExtendedRegistrationForm(RegistrationForm):
    first_name = forms.CharField(widget=forms.TextInput(attrs=dict(attrs_dict, maxlength=50)), label="First name")
    last_name = forms.CharField(widget=forms.TextInput(attrs=dict(attrs_dict, maxlength=50)), label="Last name")
    pid = forms.RegexField(regex=r'^\d{11}', max_length=11 ,widget=forms.TextInput(attrs=dict(attrs_dict, maxlength=50)))
    image = forms.ImageField(label="Image",)
    street = forms.CharField(widget=forms.TextInput(attrs=dict(attrs_dict, maxlength=50)), label="Street")
    number = forms.CharField(widget=forms.TextInput, label="House/flat number")
    code = forms.RegexField(regex=r'^\d{2}[-]\d{3}', max_length=6, widget=forms.TextInput(attrs=attrs_dict), label="Postal code")
    city = forms.CharField(widget=forms.TextInput, label="City")

and options added to settings :

AUTH_PROFILE_MODULE = 'account.UserProfile'
ACCOUNT_ACTIVATION_DAYS = 7

finally this is how the registration signal looks like :

from django.dispatch import Signal
# A new user has registered.
user_registered = Signal(providing_args=["user", "request"])

EDIT: Indentation of user_created changes nothing until I've tried changing

user_registered.connect(user_created) 

to

user_registered.connect(user_created, sender=UserProfile)

Now I was getting :
"SMTPServerDisconnected
Exception Location: /bin/python-2.6.1/lib/python2.6/smtplib.py in getreply, line 340 "
Traceback:

File "/home/fandrive/site-packages/django/core/handlers/base.py" in get_response
  92.                 response = callback(request, *callback_args, **callback_kwargs)
File "/home/fandrive/registration/views.py" in register
  47.             new_user = backend.register(request, **form.cleaned_data)
File "/home/fandrive/registration/backends/default/__init__.py" in register
  20.                                                                     password, site)
File "/home/fandrive/site-packages/django/db/transaction.py" in _commit_on_success
  240.                 res = func(*args, **kw)
File "/home/fandrive/registration/models.py" in create_inactive_user
  80.             registration_profile.send_activation_email(site)
File "/home/fandrive/registration/models.py" in send_activation_email
  256.         self.user.email_user(subject, message, settings.DEFAULT_FROM_EMAIL)
File "/home/fandrive/site-packages/django/contrib/auth/models.py" in email_user
  271.         send_mail(subject, message, from_email, [self.email])
File "/home/fandrive/site-packages/django/core/mail.py" in send_mail
  390.                         connection=connection).send()
File "/home/fandrive/site-packages/django/core/mail.py" in send
  266.         return self.get_connection(fail_silently).send_messages([self])
File "/home/fandrive/site-packages/django/core/mail.py" in send_messages
  172.             sent = self._send(message)
File "/home/fandrive/site-packages/django/core/mail.py" in _send
  186.                     email_message.message().as_string())
File "/bin/python-2.6.1/lib/python2.6/smtplib.py" in sendmail
  708.             self.rset()
File "/bin/python-2.6.1/lib/python2.6/smtplib.py" in rset
  438.         return self.docmd("rset")
File "/bin/python-2.6.1/lib/python2.6/smtplib.py" in docmd
  363.         return self.getreply()
File "/bin/python-2.6.1/lib/python2.6/smtplib.py" in getreply
  340.                 raise SMTPServerDisconnected("Connection unexpectedly closed")

Exception Type: SMTPServerDisconnected at /user/register/
Exception Value: Connection unexpectedly closed

Even though I'm using dummy email backend at the moment. Commenting out sending mail function upon registration solved this problem but still my extended user is not created.

+2  A: 

Hi, May be the problem is in the way how you connect to the signal? In my solution in was:

def user_created(sender, user, request, **kwargs):
    form = UserRegistrationForm(request.POST)
    data = profile.Profile(user=user)
    data.city_id = form.data["city"]
    data.save()

from registration.signals import user_registered
user_registered.connect(user_created)

and in yours:

from django.dispatch import Signal
# A new user has registered.
user_registered = Signal(providing_args=["user", "request"])

Also, I would switch on logging to ensure that your method is called. My solution works fine in the production, if you need I can look for other details.

dmitko
no no, look carefully. My function connects in the same way. I've just provided tho code of user_registered signal. I've switched from inheritance to relation method with my user here : http://stackoverflow.com/questions/3124052/models-does-not-create-tables-when-synched and code of this function somehow blocks creation of my tables. Where have you put this function? And shouldn't it provide sender when connecting with this signal ?
crivateos
I've moved this function to a different file. Now my tables are created but still I'm getting no extended userprofile created.
crivateos
this code is in file 'regbackend.py' which is on the same level as urls.py and is imported in urls.py just before the match patterns. This code is copied directly from regbackend.py (so sender is provided) and this file does not contain anything else.
dmitko
and I did not get - what do you mean when saying 'my tables are created'? In my case the model contains all necessary tables - all I do is adding data to them.
dmitko
okay, so that was the problem. When I imported this create_user function in the urls it was at last called (you could add it in your tutorial at ditku.ru). Could you just explain me what is happening in this line when we set data.city_id = form.data['city']. Why we're not using form.cleaned_data ? Is this data from left side the same as that on the right side ? Or is this on the right side some parameter of form ?
crivateos
Oh, there's one more thing. In my model I have image field for avatar. How can I store it using your method ? Code of my regbackend is like this : http://paste.pocoo.org/show/230329/ And when saving new user I'm getting MultiValueDictKeyError and Key 'image' not found in <QueryDict...> . Do you know any workaround solution for this ?
crivateos
data on the left side is an instance of Profile class which is model (data table) and data on the right side is a property of the form. So, no - datas are different. I guess, it's worth trying to use cleaned_data, so the code will look like:data.city = form.cleaned_data['city'].Thank you for your comment - I'll fix my blog post and mention where to import the file.
dmitko
To store images try to use cleaned_data - this might help.
dmitko