'Save Django Model when list_editable fields are changed in Django Admin change_list view
I have a Django Model which I'm trying to update from the Admin change_list view when a field that is listed in list_editable has a change event fired. Right now the only way to save the updates is by clicking a "Save" button and then the page reloads. I don't want the page to reload at all. I just want it to update the model asynchronously.
For example I have the following model.
class Example(models.Model):
name = models.CharField()
hide = models.BooleanField(default=False)
In the Admin Form I have
class ExampleAdmin(admin.ModelAdmin):
list_display = [
"name",
"hide"
]
list_editable = [
"name",
"hide"
]
When viewing the change list for Examples now I will see the values listed out with an editable text input for name and a checkbox for hide.
I would like to listen for events on those inputs and when they are fired send an async request to update the specific model.
UPDATE
This is what I have right now.
window.addEventListener("load", function() {
(function($) {
$(".field-name .vTextField").on("change",function (event) {
$('#changelist-form').submit()
})
$('#changelist-form').submit(function(event) { // On form submit event
$.ajax({ // create an AJAX call...
data: $(this).serialize(), // get the form data
type: "POST", // GET or POST
url: $(this).attr('action'), // the file to call
success: function(response) { // on success..
console.log(response)
},
error: function(e, x, r) { // on error..
console.log(e)
}
});
event.preventDefault()
return false;
});
})(django.jQuery);
})
I can see this firing in the network requests and can verify that the serialized data being sent is updated. The response is a 200, but when I refresh the page the data has not been updated.
UPDATE At this point I'm giving up on sending this data to Django and will be sending the serialized data to a custom endpoint and parse through and save the data in a custom save function.
Solution 1:[1]
Within your Admin Model add the following
class ExampleAdmin(admin.ModelAdmin):
class Media:
js = ("js/admin/example.js")
list_display = [
"name",
"hide"
]
list_editable = [
"name",
"hide"
]
example.js
window.addEventListener("load", function() {
(function($) {
$(".field-name .vTextField").on("change",function (event) {
submit()
})
function getFormData($form){
var unindexed_array = $form.serializeArray();
var indexed_array = {};
$.map(unindexed_array, function(n, i){
indexed_array[n['name']] = n['value'];
});
return indexed_array;
}
function submit(){
$.ajax({
data: getFormData($('#changelist-form')),
type: "POST",
url: '/api/save-example',
success: function(response) {
console.log(response)
},
error: function(e, x, r) {
console.log(e)
}
});
}
})(django.jQuery);
})
I'm using Django Rest Framework so I created a POST endpoint, but you could also do this in a Django View that is listening for a POST.
When you execute the post Django will send the data categorized by the row number and field name, like so.
form-0-id : 1
form-0-name: example-name
form-0-hide: false
form-0-example_parent: 100
form-1-id : 2
form-1-name: example-name-two
form-1-hide: true
form-1-example_parent: 200
@api_view(["POST"])
def save_example(request):
try:
total_rows = int(request.POST.get("form-TOTAL_FORMS"))
prefix = "form-"
form_fields = {
"id": "id",
"name": "name",
"hide": "hide",
"example_parent": "example_parent_id",
}
for x in range(total_rows):
item = {}
for key, val in form_fields.items():
post_field = prefix + str(x) + "-" + key
field = val
if key == "id":
id = request.POST.get(post_field)
else:
item[field] = request.POST.get(post_field)
Example.objects.filter(id=id).update(**item)
return Response(status=status.HTTP_200_OK)
except Exception as e:
return Response(status=status.HTTP_404_NOT_FOUND)
Note
total_rows = int(request.POST.get("form-TOTAL_FORMS")) which lets you know how to loop through all the form data that is passed back.
This doesn't take different values into consideration. (i.e. Checkboxes will return an on value but no value if not checked.
You will need to update your save_example function accordingly.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
