问题
When attempting to register a custom built user class, which has a OneToOneField relationship with a django user class, an exception is raised, with no file or line # information.
Exception Value: 'str' object has no attribute 'get'
The django error page points this to the views.py line 'if form.is_valid(),' although I don't understand how this causes the exception listed.
my models.py user class:
""" User Model """
class ShedUser( models.Model ):
"""
Class Name: ShedUser
Attributes:
user - OneToOne relation with django User
zipcode - User's Zipcode
community - community related to user's zipcode
"""
user = models.OneToOneField( User )
zipcode = models.CharField( max_length = 5 )
community = models.ForeignKey( 'Community', related_name='community' )
# Returns user's username
def __str__(self):
return self.user.username
my views.py UserRegistration:
""" UserRegistration
to Register a new User account """
def UserRegistration(request):
if request.user.is_authenticated():
return HttpResponseRedirect('/')
if request.method == 'POST':
form = UserRegistrationForm( request.POST )
if form.is_valid():
# empty initiated objects
community = Community()
sheduser = ShedUser()
# Full community list
communities = Community.objects.all()
# Boolean for new user's community existence
community_exists = False
# Parse through existing communities to assign new user to a community
for current_community in communities:
# If the new user's zipcode matches an existing zipcode
if current_community.zipcode == form.cleaned_data['zipcode']:
community = current_community
community_exists = True
# If no community exists with this zipcode:
if not community_exists:
# Generate a new stat object for the new community
new_stats = Stats( user_count=0, tool_count=0, machinery_count=0, electronic_count=0, borrow_count=0 )
new_stats.save()
# Create the new community
community.zipcode = form.cleaned_data['zipcode']
community.stats = new_stats
community.save()
# Create the django user object
user = User.objects.create_user( username = form.cleaned_data['username'], email = form.cleaned_data['email'], password = form.cleaned_data['password'], first_name=form.cleaned_data['first_name'], last_name=form.cleaned_data['last_name'])
user.save()
# Create the ShedUser object
sheduser.user = user
sheduser.zipcode = form.cleaned_data['zipcode']
sheduser.community = community
sheduser.community.stats.user_count += 1
sheduser.community.save()
sheduser.save()
return HttpResponseRedirect('/login')
else:
return render_to_response('register.html', {'form':form}, context_instance=RequestContext(request))
else:
form = UserRegistrationForm()
context = {'form': form}
return render_to_response('register.html', context, context_instance=RequestContext(request))
and finally my forms.py :
""" UserRegistrationForm """
class UserRegistrationForm( ModelForm ):
username = forms.CharField( label=('User Name'))
email = forms.EmailField( label=('Email Address'))
password = forms.CharField( label=('Password'), widget = forms.PasswordInput( render_value=False ) )
password1 = forms.CharField( label=('Verify Password'), widget = forms.PasswordInput( render_value=False ) )
first_name = forms.CharField( label=('First Name'))
last_name = forms.CharField( label=('Last Name'))
class Meta:
model = ShedUser
exclude = ('user', 'community')
# Clean the Username
def clean_username(self):
username = self.cleaned_data['username']
# Ensure username doesn't exist
try:
User.objects.get( username=username )
except User.DoesNotExist:
return username
raise forms.ValidationError("That username is already taken.")
# Clean the form passwords
def clean(self):
# verify passwords match
password = self.cleaned_data['password']
password1 = self.cleaned_data['password1']
if not password1:
raise forms.ValidationError("You must confirm your password!")
if password != password1:
raise forms.ValidationError("Your passwords did not match.")
return password1
Full traceback:
Environment:
Request Method: POST
Request URL: http://127.0.0.1:8000/register/
Django Version: 1.5.4
Python Version: 3.2.3
Installed Applications:
('django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.admin',
'models')
Installed Middleware:
('django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware')
Traceback:
File "C:\Python32\lib\site-packages\django\core\handlers\base.py" in get_response
115. response = callback(request, *callback_args, **callback_kwargs)
File "C:\ToolShare\R2\Code\Release-2\toolshare\models\views.py" in UserRegistration
104. if form.is_valid():
File "C:\Python32\lib\site-packages\django\forms\forms.py" in is_valid
126. return self.is_bound and not bool(self.errors)
File "C:\Python32\lib\site-packages\django\forms\forms.py" in _get_errors
117. self.full_clean()
File "C:\Python32\lib\site-packages\django\forms\forms.py" in full_clean
274. self._post_clean()
File "C:\Python32\lib\site-packages\django\forms\models.py" in _post_clean
317. exclude = self._get_validation_exclusions()
File "C:\Python32\lib\site-packages\django\forms\models.py" in _get_validation_exclusions
303. field_value = self.cleaned_data.get(field, None)
Exception Type: AttributeError at /register/
Exception Value: 'str' object has no attribute 'get'
Please let me know whether more code is required, or you need any more information.
回答1:
you need to return the cleaned_data and not the password1 on the form validation.
your clean should look like the following:
def clean(self):
# Runs the super methods clean data to validate the form (ensure required fields are filled out and not beyond max lens)
cleaned_data = super(UserRegistrationForm, self).clean()
# verify passwords match
password = cleaned_data['password']
password1 = cleaned_data['password1']
if not password1:
# raise forms.ValidationError("You must confirm your password!")
# instead of raising exceptions you should put an error on the form itself.
self._errors['password1'] = self.error_class(['you must confirm your password'])
if password != password1:
# raise forms.ValidationError("Your passwords did not match.")
# instead of raising exceptions you should put an error on the form itself.
self._errors['password1'] = self.error_class(['Your passwords did not match'])
return cleaned_data # return that cleaned data
EDIT
I also want to add, you should absolutely de-couple the form from the models, i know you can tie them in together as you have, but you should separate that logic out into a separate controller.
Your form validations should be pretty lightweight, any additional validations should happen in a separate controller - it makes the code much more re-usable.
also, i can't remember, but i'm positive your additional clean method will never be called. Stick that in the main def clean
defition and separate calls out to obtain objects...etc into a User object controller.
来源:https://stackoverflow.com/questions/19716196/django-user-registration-attributeerror