To tell you quite frankly, I never got to use an inbuilt manipulator while coding for Hackzor. I guess the primary reason being that my forms either had optional fields or i had to deal with two models at a time. I still could have avoided going custom, i guess i didn’t want to clutter the view with manipulation code.
So, on my path to custom manipulatorness, i missed this one HUGE turn called custom change manipulators. The docs didn’t say much about them and the comments weren’t too explicit either. After many hours of torturing unsuspecting victims on #Django, i finally found out that custom manipulators are really ‘custom’ – you’re responsible to storing the object and creating a dictionary for the form wrapper. It kinda sounds dumb right now, but it felt as hard the Da Vinci Code when i didn’t know the solution. So, in aid of all those poor, lost souls like me out there, Here’s how to make your own Custom Change Manipulator
The example i’m going to show you is naturally from Hackzor. I needed a custom change manipulator inorder to be able to put out a form where each contestant can edit his/her team details. List below, is the custom change manipulator that i wrote for the form:
class ChangeDetails (forms.Manipulator):
''' Change Membership details '''
def __init__(self, user_id):
try:
self.original_object = User.objects.get(id=user_id)
except User.DoesNotExist:
from django.http import Http404
raise Http404
self.fields = (
forms.EmailField(field_name='email',
length=30,
maxlength=30,
is_required=True,
validator_list=[self.isValidUsername]),
forms.TextField(field_name='first_name',
length=20, maxlength=20,
is_required=True),
forms.TextField(field_name='last_name',
length=20, maxlength=20,
is_required=True),
)
def isValidEmail (self, field_data, all_data):
""" Checks if there is an already existing email and raises error if so"""
try:
User.objects.get(email=field_data)
except User.DoesNotExist:
return
raise validators.ValidationError('The email "%s"
is already registered.' % field_data)
def save(self, new_data):
""" Saves The user object into the database
with score set to 0 and is_active set to false"""
self.original_object.first_name = new_data['first_name']
self.original_object.last_name = new_data['last_name']
self.original_object.email = new_data['email']
print 'Saving UserProfile updation'
self.original_object.save()
return self.original_object
def flatten_data(self):
return {
'username' : self.original_object.username,
'email' : self.original_object.email,
'first_name' : self.original_object.first_name,
'last_name' : self.original_object.last_name,
}
Points where it differs from an add manipulator:
1. The __init__ function of my manipulator has an extra argument from which i get the primary key of the object to be changed and assign the object to self.original_object
2. save is implemented like in the custom add manipulator, expect that it meddles with the existing object rather than creating a new one.
3. flatten_data is the function that will return a dict of the variables that will eventually be passed to the formwrapper to be loaded on the page. I will be calling this function from my view
Now lets take a look at the view to complete the picture
@login_required
def change_details(request):
''' Change details of existing users '''
manipulator = ChangeDetails(request.user.id)
if request.method == 'POST':
new_data = request.POST.copy()
print 'By post', new_data
errors = manipulator.get_validation_errors(new_data)
if not errors:
manipulator.do_html2python(new_data)
new_user = manipulator.save(new_data)
return render_to_response('simple_message.html',
{'message' : 'Your Details have been updated'}, RequestContext(request))
else:
print 'Errors'
else:
errors = {}
new_data = manipulator.flatten_data()
print new_data
form = forms.FormWrapper(manipulator, new_data, errors)
return render_to_response('change_profile.html',
{'form': form}, RequestContext(request))
return render_to_response('register.html', {'form':form}, RequestContext(request))