Reputation: 5010
Django's noob question:
I use dango.contrib.auth for managing users of my site. But now, I'm developing the 'settings page', where an user can edit his first name, last name, and email address. But in the settings page I want also a checkbox for "newsletter".
Questions are: 1) Where should I put newsletter field in the database? 2) How can I create a form for editing these informations?
Thanks.
-- UPDATE --
Now I've this in models.py:
class UserProfile(models.Model):
user = models.ForeignKey(User, unique = True)
favourite_color = models.CharField(max_length = 40)
and this in forms.py:
class UserSettingsForm(forms.ModelForm):
class Meta:
model = User
exclude = ('password',)
def save(self, commit=False):
user = super(UserSettingsForm,self).save(commit)
favourite_color = self.cleaned_data.get('favourite_color', '')
if favourite_color and user.favourite_color is None:
UserProfile(user=user).save()
if not slug:
UserProfile.objects.filter(user=user).delete()
if not commit:
user.save()
return user
I'm a bit confused. I would edit informations like first name, last name, email and favourite color in the settings form but actually I'm doing it wrong.
Upvotes: 1
Views: 339
Reputation: 6764
I don't know if this is a good way. But you can not to create special class for you User profile (or you have one more table in database so user search is slower).
I tried to do the next:
{ utils.py }
class Utils:
class ClassContributor:
@staticmethod
def contribute_fields( object_class, *fields ):
for val in fields:
field_name = val[ 0 ]
field = val[ 1 ]
field.contribute_to_class( object_class, field_name )
{ models.py }
user_contributor = Utils.ClassContributor.contribute_fields(
User,
( 'country', models.ForeignKey( Country, null = True ) ),
( 'region', models.ForeignKey( Region, null = True ) ),
( 'city', models.ForeignKey( City, null = True ) ),
)
In this case we have only one table in a database (problem is: added fields is not visible in django admin).
I will search a decision of the problem.
Upvotes: 0
Reputation: 5010
SOLVED:
this in forms.py:
class UserProfileForm(forms.ModelForm):
first_name = forms.CharField(label = 'First name', max_length = 40)
last_name = forms.CharField(label = 'Last name', max_length = 40)
email = forms.CharField(label = 'Email', max_length = 40)
def __init__(self, *args, **kw):
super(UserProfileForm, self).__init__(*args, **kw)
self.fields['first_name'].initial = self.instance.user.first_name
self.fields['last_name'].initial = self.instance.user.last_name
self.fields['email'].initial = self.instance.user.email
def save(self, *args, **kw):
profile = super(UserProfileForm, self).save(*args, **kw)
u = self.instance.user
u.first_name = self.cleaned_data['first_name']
u.last_name = self.cleaned_data['last_name']
u.email = self.cleaned_data['email']
u.save()
return profile
class Meta:
model = UserProfile
exclude = ('user', )
and in the views.py:
def settings(request):
user = request.user.get_profile()
if request.method == 'POST':
form = UserProfileForm(request.POST, instance = user)
if form.is_valid():
form.save()
return HttpResponseRedirect('')
form = UserProfileForm(instance = user)
return render(request, "settings.html", {'form': form})
Upvotes: 0
Reputation: 48730
Create a new model with a reference to the User model, and create a ModelForm based on the User, but includes additional fields.
class Subscription(models.Model):
user = models.OneToOneField(User, null=True, blank=True, related_name='subscription')
class UserSettingsForm(forms.ModelForm):
subscribed = forms.BooleanField(default=False)
class Meta:
model = User
exclude = ('password',)
def save(self, commit=False)
user = super(UserSettingsForm,self).save(commit)
subscribed = self.cleaned_data.get('subscribed', False)
if subscribed and user.subscription is None:
Subscription(user=user).save()
if not subscribed:
Subscription.objects.filter(user=user).delete()
if not commit:
user.save()
return user
You'll also want to pass in initial data regarding subscription information to the form creation:
subscribed = user.subscription is not None
form = UserSettingsForm(instance=user, initial={subscribed=subscribed})
That should take care of it. I don't have a personal example right next to me at the moment, but that's done from memory. I'll try and update it later today if I've missed anything.
Upvotes: 0
Reputation: 673
You can also use inheritance and let django manage the saving.
class UserProfile(User):
favourite_color = models.CharField(max_length = 40)
class UserProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
exclude = ('password',)
This will create a one-to-one field on UserProfile pointing to User. The User fields will be saved in the User model and the other field in the UserProfile model.
Upvotes: 0
Reputation: 42825
You want to look at user profiles.
EDIT: Regarding the forms, is there anything stopping you from using two forms? I think Django ignores fields in the HTTP request that don't match up to a form, so you could feed the request to two forms. When rendering a template, Django doesn't generate the <form>
tags or the submit button, so you just put both forms in the same <form>
. Something like this in your view (modifying a Django example):
def edit_user_view(request):
if request.method == 'POST': # If the form has been submitted...
# Two forms bound to the POST data
userForm = UserForm(request.POST)
profileForm = ProfileForm(request.POST)
if userForm.is_valid() and userForm.is_valid():
# All validation rules pass
# Process the data in userForm. and profileForm.cleaned_data
# ...
return HttpResponseRedirect('/thanks/') # Redirect after POST
else:
# Unbound forms
userForm = UserForm()
profileForm = ProfileForm()
return render_to_response('edit_user.html', {
'userForm': userForm,
'profileForm': profileForm,
})
And in the template:
<form action="/contact/" method="post">{% csrf_token %}
{{ userForm.as_p }}
{{ profileForm.as_p }}
<input type="submit" value="Submit" />
</form>
This is really just a starting point, but I don't see any reason it can't work.
Upvotes: 6