Situation

Using Django 1.5, I am using forms.ModelForm s to let the user edit database contents. However I can't get the form to update the database upon form.save() .

Each of my models correspond to a setting form (the application is a the direct porting of a desktop software in which the user can store several settings). I needed to implement a Reset to default feature, so I thought of having a default object (imported with Django fixtures) which I would use only to reset a second one. The user would only interact with the second model.

pk=1 refers to the base object

refers to the base object pk=2 refers to the custom object

I have several forms on the same page (only foobar here), so basically this what I planned to do:

No POST data Building form from either pk=1 or pk=2 , depending pk=2 has been found or not Rendering the forms to the template

AJAX request, with POST datas Getting form content Checking whether or not the user has permission to edit the model (checksum) Update the model form POST datas Returning AJAX response



Code

I have put two debug print s to illustrate the issue I am facing. The form I fetch doesn't seem to be bound to my model.

# Response codes to use in the template RESPONSES = { 200: {'code':'0xB16B00B5', 'message':'Success'}, 400: {'code':'0x8BADF00D', 'message':'Form is not valid'}, 403: {'code':'0xBAADF00D', 'message':'No permission to edit the database'}, 501: {'code':'0xDEADC0DE', 'message':'POST datas not found'}, } # Those are the setting labels TYPES = { 'foobar': {'model':FooBar, 'form':FooBarForm }, }

def index(request): # Handling form datas if request.method == 'POST': response = HttpResponse(simplejson.dumps({'code':RESPONSES[501]['code']}), 'application/json') for label in TYPES: # Filtering the right form to handle if label in request.POST: model = _fetch_setting(label, mode='model') form = _fetch_setting(label, mode='form', post=request.POST) checksum = model.checksum # Somehow, 'form.is_valid()' is altering 'model', need to backup the checksum if form.is_valid(): # The user has permission to edit the model if form.cleaned_data['checksum'] == checksum: if form.has_changed(): print form.cleaned_data['foo'] # Outputs the form data, as expected form.save() print model.foo # Outputs the old data model.checksum = str(uuid4()).replace('-', '') model.save() response = HttpResponse(simplejson.dumps({'code':RESPONSES[200]['code']}), 'application/json') # This one does not else: response = HttpResponse(simplejson.dumps({'code':RESPONSES[403]['code']}), 'application/json') break # We are still inside the label loop # The form is not valid else: response = HttpResponse(simplejson.dumps({'code':RESPONSES[400]['code']}), 'application/json') # Form not submitted yet, building the HTML forms else: forms = {} label = 'foobar' for label in TYPES: forms[label] = _fetch_setting(label, mode='form') context = {'errors':RESPONSES, 'forms':forms} response = render(request, 'home/index.html', context) return response

# Return a setting object (model or form) corresponding to the given label def _fetch_setting(label, mode='model', post=None): try: result = None default = TYPES[label]['model'].objects.get(pk=1) try: model = TYPES[label]['model'].objects.get(pk=2) except TYPES[label]['model'].DoesNotExist: model = TYPES[label]['model'].objects.create( checksum = default.checksum, foo = default.foo, bar = default.bar, ) if mode == 'model': result = model if mode == 'form': print model result = TYPES[label]['form'](data=post, instance=model) # The 'instance' attribute doesn't seem to be applied except KeyError: result = None finally: return result

Update

07.10

It does work when I pass the instance to bound with to _fetch_setting . So I guess this issue is coming from the form validation.

def _fetch_setting(label, mode='model', post=None, instance=None): # ... if mode == 'form': if instance: model = instance result = TYPES[label]['form'](data=post, instance=model) # ...

As I commented in my code, form.is_valid() seems to alter the object.

Will flag as answered if no one come with a clean solution.