Reputation: 993
I am writing a Django application and need to update a model with an AJAX request, which will only contain a subset of the model's fields as keys. So if I have the model
class TheModel(models.Model):
a = models.CharField(max_length=16)
b = models.IntegerField()
c = models.TextField()
d = models.ManyToManyField(AnotherModel)
then I could get requests like
id=7&a=Hello
id=7&a=Test&b=123
id=13&b=14&c=Description&d=6&d=10
that is, I will always get the ID field but any subset of the others.
I can't find a "nice" way to do this in Django 1.5: at first I tried
instance = get_instance_or_404(request["id"])
data = django.forms.models.model_to_dict(instance)
data.update(request.POST)
form = TheModelForm(data, instance=instance)
if form.is_valid():
form.save()
...
else:
...
but this doesn't seem to work well with the m2m field, and moreover model_to_dict feels incredibly ugly to me. So I also did
instance = get_instance_or_404(request["id"])
for k in TheModel._meta.fields:
if k in request:
setattr(instance, k, request[k])
try:
instance.full_clean()
except ValidationError as e:
...
instance.save()
but I don't exactly understand how to handle the m2m fields here either.
Is there an idiomatic way to do this in Django? Thanks in advance for your help.
Upvotes: 1
Views: 820
Reputation: 10312
First of all, GET
requests should never update data. They should only ever read and display data. The HTTP method you need to use is POST
. This answer is worth a read.
Now that's out of the way, the best way to achieve what you want is by using the generic UpdateView
. Here's some sample code:
# urls.py
from views import UpdateTheModelView
urlpatterns = patterns('',
url(r'^update-TheModel/(?P<pk>\d+)/?',
UpdateTheModelView.as_view(),
name='update_the_model'),
)
# forms.py
from django import forms
from models import TheModel
class TheModelForm(forms.ModelForm):
class Meta:
model = TheModel
fields = ('a', 'b', 'c', 'd',)
# views.py
from django.core.urlresolvers import reverse
from django.views.generic import UpdateView
from models import TheModel
from forms import TheModelForm
class UpdateTheModelView(UpdateView):
model = TheModel
form_class = TheModelForm
template_name = 'themodel_form.html'
def get_success_url(self):
"""
Just here to redirect back to the update page when the form is posted
"""
return reverse('update_the_model', args=[self.object.id, ])
And a simple example template to display the form at yourapp/templates/themodel_form.html
:
<form action="." method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Update" />
</form>
So now if you have an instance of TheModel
saved with an id of 1
, you can view the update form loaded with initial data by going to http://your-website.co.uk/update-TheModel/1/
and you can update it by clicking Update
or by sending a POST request to this page's URL (along with the CSRF token), which can easily be done in the background with jQuery or vanilla Javascript.
Upvotes: 1