I am currently working on a Django project. This is my first introduction to Python / Django, so I'm currently learning the ropes. Hope you all can help!
I'm currently trying to update some custom fields I have setup in my UserProfile model via the Models, View, and Template. Right now it seems that no matter what I do to the View, the returning form is always coming back as not valid. I've been staring at this for quite some time, so that probably doesn't help. Here is the code:
models.py:
class UserProfile(models.Model):
#inherit the base User model
user = models.OneToOneField(User)
#custom fields to be in the User model
phoneNumber = models.IntegerField(null=True)
about = models.TextField(null=True)
gitHubLink = models.URLField(null=True)
linkedInLink = models.URLField(null=True)
gravitarLink = models.URLField(null=True)
facebookLink = models.URLField(null=True)
rating = models.PositiveSmallIntegerField(default=0)
def __unicode__(self):
return u'Profile of user: %s' % self.user.username
User.profile = property(lambda u: UserProfile.objects.get_or_create(user=u)[0])
def create_user_profile(sender, instance, created, **kwargs):
if created:
UserProfile.objects.create(user=instance)
post_save.connect(create_user_profile, sender=User)
views.py:
@login_required
def edit_profile(request):
profile = request.user.get_profile()
if request.method == 'POST':
form = UserProfileForm(request.POST, instance=profile)
if form.is_valid():
userprofile = form.save(commit=False)
userprofile.user = request.user
userprofile.save()
messages.success(request, "Account Updated!")
return render_to_response('profile/edit.html', {"form": form}, context_instance=RequestContext(request))
else:
form = UserProfileForm()
messages.error(request, "There are form errors.")
return render_to_response('profile/edit.html', {"form": form}, context_instance=RequestContext(request))
else:
form = UserProfileForm(instance=profile)
return render_to_response('profile/edit.html', {"form": form}, context_instance=RequestContext(request))
forms.py:
class UserProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
fields = ('phoneNumber', 'about', 'gitHubLink', 'linkedInLink', 'gravitarLink', 'facebookLink')
def save(self, commit=True):
userprofile = super(UserProfileForm, self).save(commit=False)
userprofile.phoneNumber = self.cleaned_data['phoneNumber']
if commit:
userprofile.save()
return userprofile
edit.html(template):
<form action="/profile/edit/" method="post" class="form-signin">
{% csrf_token %}
<div class="form-group">{{ form.phoneNumber|add_class:"form-control"|attr:"placeholder:Phone Number" }} </div>
<div class="form-group">{{ form.gitHubLink|add_class:"form-control"|attr:"placeholder:GitHub Account URL" }} </div>
<div class="form-group">{{ form.facebookLink|add_class:"form-control"|attr:"placeholder:Facebook Account URL" }} </div>
<div class="form-group">{{ form.linkedInLink|add_class:"form-control"|attr:"placeholder:LinkedIn Account URL" }} </div>
<div class="form-group">{{ form.about|add_class:"form-control"|attr:"placeholder:About Yourself. Interests, Hobbies, etc.." }} </div>
<button class="btn btn-lg btn-success btn-block" type="submit">Save Changes</button>
</form>
Appreciate you taking the time to read this. Any help / pointers are much appreciated!
Your template doesn't include your gravitarLink
field. Because the model field is not declared with blank=True
, this field is required, so your form can never be valid.
Note that it's generally considered a better practice not to use null=True
with character fields, of which URLField
is a subset. Instead, if you want them to be optional set blank=True
and leave null
at its default value of False
so that the empty string is the empty value. blank=True
is required for them to be optional; null
just controls what database representations are valid.
Also, it is a better practice to pass the bound form
object back to the template when there are errors rather than creating a new empty one. That not only includes the values you previously submitted, so that the user doesn't have to reenter the valid ones, but it can show the errors per field. The Django docs on "using a form in a view" demonstrate the usual pattern.