diff options
-rw-r--r-- | account/admin.py | 3 | ||||
-rw-r--r-- | account/forms.py | 64 | ||||
-rw-r--r-- | account/models.py | 65 | ||||
-rw-r--r-- | account/views.py | 45 |
4 files changed, 164 insertions, 13 deletions
diff --git a/account/admin.py b/account/admin.py index b5ec5b6..ee568fc 100644 --- a/account/admin.py +++ b/account/admin.py @@ -2,9 +2,10 @@ from django.contrib import admin -from account.models import UserProfile +from account.models import UserProfile, UserFile admin.site.register(UserProfile) +admin.site.register(UserFile) diff --git a/account/forms.py b/account/forms.py index c7e15d3..cb0b6b2 100644 --- a/account/forms.py +++ b/account/forms.py @@ -5,6 +5,7 @@ account/forms.py for skaschool """ from django import forms +from django.forms.models import inlineformset_factory from django.contrib.auth.models import User from django.contrib.sites.models import Site, RequestSite from django.utils.translation import ugettext_lazy as _ @@ -12,7 +13,7 @@ from django.utils.translation import ugettext_lazy as _ from registration.forms import RegistrationFormUniqueEmail from captcha.fields import ReCaptchaField -from account.models import UserProfile +from account.models import UserProfile, UserFile class UserRegForm(RegistrationFormUniqueEmail): @@ -104,6 +105,65 @@ class UpdateProfileForm(forms.ModelForm): class Meta: model = UserProfile - fields = ('realname', 'gender', 'institute', 'identify') + fields = ( + 'user', + 'realname', + 'gender', + 'institute', + 'identify', + 'reason', + 'transcript', + 'supplement', + ) + widgets = { + 'user': forms.HiddenInput, + } + + def __init__(self, *args, **kwargs): + super(UpdateProfileForm, self).__init__(*args, **kwargs) + # reorder fields, append 'email' just after 'realname' + self.fields.keyOrder = [ + 'user', + 'realname', + 'email', + 'gender', + 'institute', + 'identify', + 'reason', + 'transcript', + 'supplement', + ] + def clean(self): + """ + check if 'transcript' is needed and provided + """ + form_data = self.cleaned_data + user = form_data.get('user') + profile = user.userprofile_set.get(user=user) + profile.identify = form_data.get('identify', profile.identify) + transcript = self.cleaned_data.get('transcript', False) + if (profile.is_transcript_required() and (not transcript)): + raise forms.ValidationError(_("Transcript is required."), code='required') + # not save 'profile' here + return self.cleaned_data + + +class UserFileForm(forms.ModelForm): + """ + form of UserFile, empty_permitted=True + """ + class Meta: + model = UserFile + + def __init__(self, *args, **kwargs): + super(UserFileForm, self).__init__(*args, **kwargs) + self.empty_permitted = True + + +### formset ### +# UserFileFormSet: parent_model -> User +UserFileFormSet = inlineformset_factory(User, + UserFile, form=UserFileForm, + extra=1, can_delete=True) diff --git a/account/models.py b/account/models.py index f3f12f8..257477d 100644 --- a/account/models.py +++ b/account/models.py @@ -6,12 +6,15 @@ from django.db import models from django.contrib.auth.models import User - +from django.conf import settings from django.utils.translation import ugettext_lazy as _ from registration.signals import user_registered +from account.extra import ContentTypeRestrictedFileField + +###### account models ###### class UserProfile(models.Model): """ custom user profile @@ -38,7 +41,8 @@ class UserProfile(models.Model): # choices for identify IDENTIFIES = ( ('OT', _("Other")), - ('UG', _("Undergraudate")), + ('UG', _("Undergraudate (junior and below)")), + ('U4', _("Undergraudate (senior)")), ('MG', _("Master graudate")), ('PG', _("PhD graudate")), ('PD', _("Post-doctoral")), @@ -53,11 +57,21 @@ class UserProfile(models.Model): ) # model fields # FK default backward manager name 'userprofile_set' - user = models.ForeignKey(User, unique=True, verbose_name=_("Username")) + user = models.ForeignKey(User, unique=True, verbose_name=_("User")) realname = models.CharField(_("Name"), max_length=30) gender = models.CharField(_("Gender"), max_length=1, choices=GENDERS) institute = models.CharField(_("Institute"), max_length=100) - identify = models.CharField(_("Identify"), max_length=2, choices=IDENTIFIES) + identify = models.CharField(_("Identify"), max_length=2, + choices=IDENTIFIES) + # reasons to participate + reason = models.TextField(_("Why attend")) + # transcript: needed if undergraudate (junior and below) + transcript = ContentTypeRestrictedFileField(upload_to=lambda instance, filename: u'account/{0}/{1}'.format(instance.user.username, filename), + verbose_name=_("Transcript"), blank=True, null=True, + content_types=settings.ALLOWED_CONTENT_TYPES, + max_upload_size=settings.ALLOWED_MAX_UPLOAD_SIZE) + # supplement: record additional information + supplement = models.TextField(_("Supplement"), blank=True) # store the infomation about approval and sponsorship is_approved = models.CharField(_("Is approved"), max_length=1, choices=APPROVED_STATUS, default='C') @@ -69,7 +83,17 @@ class UserProfile(models.Model): verbose_name_plural = _('user profiles') def __unicode__(self): - return u'UserProfile for %s' % self.user + return u'UserProfile for %s' % self.user.username + + def is_transcript_required(self): + """ + if 'identify' is UG (undergraduate junior and below); then + transcript is required, return True. Otherwise, return False + """ + if (self.identify == 'UG'): + return True + else: + return False def get_approved(self, *args, **kwargs): """ @@ -111,6 +135,37 @@ class UserProfile(models.Model): identifies_dict = dict((k, v) for k, v in self.IDENTIFIES) return identifies_dict.get(self.identify) + def get_userfiles(self): + """ + return the UserFile objects related to this user + NOTE: transcript is not included here. + """ + return self.user.userfile_set.all() + + +class UserFile(models.Model): + """ + model to deal with user uploaded files + """ + user = models.ForeignKey(User, verbose_name=_("User")) + title = models.CharField(_("Title"), max_length=100) + description = models.TextField(_("Description"), blank=True) + file = ContentTypeRestrictedFileField(upload_to=lambda instance, filename: u'account/{0}/{1}'.format(instance.user.username, filename), + verbose_name=_("File"), + content_types=settings.ALLOWED_CONTENT_TYPES, + max_upload_size=settings.ALLOWED_MAX_UPLOAD_SIZE) + created_at = models.DateTimeField(_("Created time"), + auto_now_add=True) + modified_at = models.DateTimeField(_("Modified time"), auto_now=True) + + class Meta: + verbose_name = _('user file') + verbose_name_plural = _('user files') + ordering = ['user', 'id'] + + def __unicode__(self): + return u'UserFile of %s: %s' % (self.user.username, self.title) + ###### signal callback ###### def user_registered_callback(sender, user, request, **kwargs): diff --git a/account/views.py b/account/views.py index a4c3337..432a8fc 100644 --- a/account/views.py +++ b/account/views.py @@ -12,7 +12,7 @@ from django.core.urlresolvers import reverse_lazy from django.http import HttpResponseRedirect from account.models import UserProfile -from account.forms import ResendEmailForm, UpdateProfileForm +from account.forms import ResendEmailForm, UpdateProfileForm, UserFileFormSet ###### Class-based views ###### @@ -60,7 +60,8 @@ class UpdateProfileView(UpdateView): def get(self, request, *args, **kwargs): """ - Returns the keyword arguments for instantiating the form. + Returns the keyword arguments for instantiating the form + and related formsets. modify this method to add 'email' data """ self.object = self.get_object() @@ -69,18 +70,52 @@ class UpdateProfileView(UpdateView): # initialize form 'email' field user = self.request.user form.fields['email'].initial = user.email - return self.render_to_response(self.get_context_data(form=form)) + # formset + formset = UserFileFormSet() + return self.render_to_response( + self.get_context_data(form=form, formset=formset)) - def form_valid(self, form): + def post(self, request, *args, **kwargs): + """ + handle POST requests, instantiating a form instance and + related formset with passed POST data and then validate. + """ + self.object = self.get_object() + form_class = self.get_form_class() + form = self.get_form(form_class) + # formset + formset = UserFileFormSet(self.request.POST, self.request.FILES) + user = self.request.user + # set instance for formset first, otherwise cannot generate + # right upload_to due to the empty of user + formset.instance = user # UserFileFormSet parent_model + if (form.is_valid() and formset.is_valid()): + return self.form_valid(form, formset) + else: + return self.form_invalid(form, formset) + + def form_valid(self, form, formset): """ modify 'form_valid' to update email field """ form_data = form.cleaned_data + # save object + self.object = form.save() # update email and save user = self.request.user user.email = form_data.get('email', user.email) user.save() - return super(UpdateProfileView, self).form_valid(form) + # formset + formset.instance = user # UserFileFormSet parent_model + formset.save() + return HttpResponseRedirect(self.get_success_url()) + + def form_invalid(self, form, formset): + """ + re-render the context data with the data-filled forms and errors + """ + return self.render_to_response( + self.get_context_data(form=form, formset=formset)) class ListApprovedView(ListView): |