Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1# Imports 

2 

3from django import forms 

4from django.conf import settings 

5from django.contrib.auth import get_user_model 

6from django.core.exceptions import ImproperlyConfigured 

7from django.utils.translation import ugettext_lazy as _ 

8from superdjango.conf import SUPERDJANGO 

9from superdjango.html.library import Fieldset 

10from superdjango.contrib.i18n.timezones import COMMON_TIMEZONE_CHOICES 

11from ..utils import get_profile_model, get_user_profile 

12 

13ProfileModel = get_profile_model() 

14UserModel = get_user_model() 

15 

16# Exports 

17 

18__all__ = ( 

19 "ProfileForm", 

20) 

21 

22# Constants 

23 

24DEFAULT_REDIRECT_TO_CHOICES = ( 

25 ("/", _("Home")), 

26 ("/accounts/profile/", _("My Account")), 

27) 

28 

29LOGIN_REDIRECT_URL = getattr(settings, "LOGIN_REDIRECT_URL", "/") 

30 

31# Forms 

32 

33 

34class ProfileForm(forms.ModelForm): 

35 """A base form for user profiles based on the ``ProfileModel``.""" 

36 

37 field_order = [ 

38 "prefix", 

39 "first_name", 

40 "last_name", 

41 "suffix", 

42 "address", 

43 "phone_number", 

44 "email", 

45 "username", 

46 "redirect_to", 

47 "time_zone", 

48 "gravatar_enabled", 

49 "photo", 

50 ] 

51 

52 address = forms.CharField( 

53 label=_("Address"), 

54 help_text=_("Enter your mailing address."), 

55 widget=forms.Textarea, 

56 required=False 

57 ) 

58 

59 email = forms.EmailField( 

60 label=_("Email Address"), 

61 help_text=_("Enter your email address."), 

62 required=False 

63 ) 

64 

65 first_name = forms.CharField( 

66 label=_("First Name"), 

67 help_text=_("Your given name."), 

68 max_length=128, 

69 required=True 

70 ) 

71 

72 gravatar_enabled = forms.BooleanField( 

73 help_text=_("Indicates whether to use gravatar.com for your profile photos."), 

74 label=_("Enable Gravatar") 

75 ) 

76 

77 last_name = forms.CharField( 

78 label=_("Last Name"), 

79 help_text=_("Your family name."), 

80 max_length=128, 

81 required=True 

82 ) 

83 

84 middle_name = forms.CharField( 

85 label=_("Middle Name"), 

86 help_text=_("Your middle name or initial."), 

87 max_length=128, 

88 required=False 

89 ) 

90 

91 phone_number = forms.CharField( 

92 label=_("Phone Number"), 

93 help_text=_("Enter your phone number."), 

94 required=False 

95 ) 

96 

97 photo = forms.FileField( 

98 label=_("Photo"), 

99 help_text=_("Upload a photo to use for your profile picture."), 

100 required=False 

101 ) 

102 

103 prefix = forms.CharField( 

104 label=_("Prefix"), 

105 help_text=_("Enter a prefix to appear before your name or leave blank for nothing."), 

106 max_length=64, 

107 required=False 

108 ) 

109 

110 # Default redirect choices will be overridden by account settings. 

111 redirect_to = forms.ChoiceField( 

112 choices=SUPERDJANGO.REDIRECT_TO_CHOICES or DEFAULT_REDIRECT_TO_CHOICES, 

113 initial=LOGIN_REDIRECT_URL, 

114 help_text=_("By default, go to this page after logging in."), 

115 label=_("Redirect To"), 

116 required=True 

117 ) 

118 suffix = forms.CharField( 

119 label=_("Suffix"), 

120 help_text=_("Enter a suffix to appear after your name or leave blank for nothing."), 

121 max_length=64, 

122 required=False 

123 ) 

124 

125 # Default choices will be overridden by account settings. 

126 time_zone = forms.ChoiceField( 

127 choices=SUPERDJANGO.TIMEZONE_CHOICES or COMMON_TIMEZONE_CHOICES, 

128 label=_("Timezone"), 

129 help_text=_("Select the timezone in which you reside or work."), 

130 required=False 

131 ) 

132 

133 username = forms.CharField( 

134 label=_("User Name"), 

135 max_length=150, 

136 required=True 

137 ) 

138 

139 class Meta: 

140 model = ProfileModel 

141 fields = [ 

142 "address", 

143 "email", 

144 "first_name", 

145 "gravatar_enabled", 

146 "last_name", 

147 "middle_name", 

148 "phone_number", 

149 "photo", 

150 "prefix", 

151 "redirect_to", 

152 "suffix", 

153 "time_zone", 

154 "username", 

155 ] 

156 

157 def __init__(self, *args, **kwargs): 

158 """Initialize with a user keyword argument, add redirect and time zone choices, and set defaults.""" 

159 # Get the user or die trying. 

160 self.user = kwargs.pop("user", None) 

161 if self.user is None: 

162 raise ImproperlyConfigured("user is a required kwarg.") 

163 

164 # This allows view logic to pass the redirect choices but still default to those supplied by the accounts app. 

165 redirect_to_choices = kwargs.pop( 

166 "redirect_to_choices", 

167 SUPERDJANGO.REDIRECT_TO_CHOICES or DEFAULT_REDIRECT_TO_CHOICES 

168 ) 

169 

170 # This allows view logic to pass time zone choices but still default to configured or common choices. 

171 time_zone_choices = kwargs.pop( 

172 "time_zone_choices", 

173 SUPERDJANGO.TIMEZONE_CHOICES or COMMON_TIMEZONE_CHOICES 

174 ) 

175 

176 # Initialize the form. 

177 super(ProfileForm, self).__init__(*args, **kwargs) 

178 

179 # Set the value of fields that come from the user. 

180 self.fields['email'].initial = self.user.email 

181 self.fields['username'].initial = self.user.username 

182 

183 # First and last name may have been entered if the user account was created manually or (for example) through a 

184 # registration process that did not create a profile record. These will be blank during the first load of a 

185 # profile form, but we can attempt to display them as initial values. Note that email and username above work 

186 # because the values are not bound to profile. However, 

187 # self.fields['first_name'].initial = profile.user.first_name will *not* work because those fields are bound 

188 # in the call to super() above. 

189 profile = kwargs['instance'] 

190 if not profile.first_name: 

191 self.initial['first_name'] = profile.user.first_name 

192 

193 if not profile.last_name: 

194 self.initial['last_name'] = profile.user.last_name 

195 

196 # Set choices. 

197 self.fields['redirect_to'].choices = redirect_to_choices 

198 self.fields['time_zone'].choices = time_zone_choices 

199 

200 def clean_email(self): 

201 """Email addresses must be unique. This checks to see if the current address is different than the submitted 

202 address and makes sure a new address is not already taken. 

203 """ 

204 current_profile = get_user_profile(self.user) 

205 

206 if current_profile.user.email != self.cleaned_data['email']: 

207 if UserModel.objects.filter(email__iexact=self.cleaned_data['email']).exists(): 

208 raise forms.ValidationError(_("This email address is already in use.")) 

209 

210 return self.cleaned_data['email'] 

211 

212 def clean_username(self): 

213 """User names must be unique. This checks to see if the current name is different than the submitted 

214 name and makes sure a new name is not already taken. 

215 """ 

216 current_profile = get_user_profile(self.user) 

217 

218 current_username = getattr(current_profile.user, UserModel.USERNAME_FIELD) 

219 

220 if current_username != self.cleaned_data['username']: 

221 criteria = { 

222 UserModel.USERNAME_FIELD: self.cleaned_data['username'] 

223 } 

224 if UserModel.objects.filter(**criteria).exists(): 

225 raise forms.ValidationError(_("This user name is already in use.")) 

226 

227 return self.cleaned_data['username'] 

228 

229 @property 

230 def fieldsets(self): 

231 """Alias of ``get_fieldsets()``.""" 

232 return self.get_fieldsets() 

233 

234 def get_fieldsets(self): 

235 """Get the field sets to be included in the form. 

236 

237 :rtype: list[superdjango.html.library.Fieldset] 

238 

239 """ 

240 a = list() 

241 

242 contact = Fieldset(_("Contact"), fields=[ 

243 self["prefix"], 

244 self["first_name"], 

245 self["middle_name"], 

246 self["last_name"], 

247 self["suffix"], 

248 self["address"], 

249 self["phone_number"], 

250 self["email"], 

251 ]) 

252 a.append(contact) 

253 

254 user = Fieldset(_("User"), fields=[ 

255 self["username"], 

256 self["photo"], 

257 ]) 

258 a.append(user) 

259 

260 prefs = Fieldset(_("Preferences"), fields=[ 

261 self["gravatar_enabled"], 

262 self["redirect_to"], 

263 self["time_zone"] 

264 ]) 

265 a.append(prefs) 

266 

267 return a 

268 

269 @property 

270 def has_fieldsets(self): 

271 """Indicates the form has fieldsets. 

272 

273 :rtype: bool 

274 

275 """ 

276 return True 

277 

278 def save(self, commit=True): 

279 """Process user fields.""" 

280 

281 # Email is saved to the user account. 

282 email = self.cleaned_data.pop('email') 

283 

284 # User names are also saved to the user account. 

285 first_name = self.cleaned_data['first_name'] 

286 last_name = self.cleaned_data['last_name'] 

287 username = self.cleaned_data.pop('username') 

288 

289 user = UserModel.objects.get(pk=self.instance.user_id) 

290 user.email = email 

291 user.first_name = first_name 

292 user.last_name = last_name 

293 setattr(user, UserModel.USERNAME_FIELD, username) 

294 user.save() 

295 

296 return super(ProfileForm, self).save(commit=commit)