Creating and updating a Django Model in the front-end¶
We can now apply what we’ve built so far to edit a specific Django model from the front-end.
Note
Check sample code at: (7) Creating and updating a Django Model in the front-end
Creating a new model¶
This is the view:
@login_required
def artist_create(request):
if not request.user.has_perm('backend.add_artist'):
raise PermissionDenied
# Either render only the modal content, or a full standalone page
if request.is_ajax():
template_name = 'frontend/includes/generic_form_inner.html'
else:
template_name = 'frontend/includes/generic_form.html'
object = None
if request.method == 'POST':
form = ArtistCreateForm(data=request.POST)
if form.is_valid():
object = form.save()
if not request.is_ajax():
# reload the page
next = request.META['PATH_INFO']
return HttpResponseRedirect(next)
# if is_ajax(), we just return the validated form, so the modal will close
else:
form = ArtistCreateForm()
return render(request, template_name, {
'form': form,
'object': object,
})
and this is the form:
class ArtistCreateForm(forms.ModelForm):
class Meta:
model = Artist
fields = [
'description',
'notes',
]
Note that we’re using a generic template called frontend/includes/generic_form_inner.html;
Chances are we’ll reuse it unmodified for other Models as well.
{% load i18n bootstrap3 %}
<div class="row">
<div class="col-sm-8">
<form method="post" class="form" novalidate>
{% csrf_token %}
{% bootstrap_form form %}
<input type="hidden" name="object_id" value="{{ object.id|default:'' }}">
{% buttons %}
<div class="form-submit-row">
<button type="submit" class="btn btn-primary">
{% bootstrap_icon "star" %} {% trans 'Send' %}
</button>
</div>
{% endbuttons %}
</form>
</div>
</div>
On successful creation, we might want to update the user interface; in the example, for simplicity, we just reload the entire page, but before doing that we also display with an alert the new object id retrieved from the hidden field ‘object_id’ of the form; this could be conveniently used for in-place page updating.
<script language="javascript">
function afterModalCreateSuccess(modal) {
var object_id = modal.find('input[name=object_id]').val();
alert('New artist created: id=' + object_id);
location.reload(true);
}
</script>
Updating an existing object¶
We treat the update of an existing object in a similar fashion, but binding the form to the specific database record.
The view:
@login_required
def artist_update(request, pk):
if not request.user.has_perm('backend.change_artist'):
raise PermissionDenied
# Either render only the modal content, or a full standalone page
if request.is_ajax():
template_name = 'frontend/includes/generic_form_inner.html'
else:
template_name = 'frontend/includes/generic_form.html'
object = get_object_by_uuid_or_404(Artist, pk)
if request.method == 'POST':
form = ArtistUpdateForm(instance=object, data=request.POST)
if form.is_valid():
form.save()
if not request.is_ajax():
# reload the page
next = request.META['PATH_INFO']
return HttpResponseRedirect(next)
# if is_ajax(), we just return the validated form, so the modal will close
else:
form = ArtistUpdateForm(instance=object)
return render(request, template_name, {
'object': object,
'form': form,
})
and the form:
class ArtistUpdateForm(forms.ModelForm):
class Meta:
model = Artist
fields = [
'description',
'notes',
]
Finally, here’s the object id retrival after successful completion:
<script language="javascript">
function afterModalUpdateSuccess(modal) {
var object_id = modal.find('input[name=object_id]').val();
alert('Artist updated: id=' + object_id);
location.reload(true);
}
</script>
Possible optimizations¶
In the code above, we can detect at list three redundancies:
- the two model forms are identical
- the two views are similar
- and, last but not least, we might try to generalize the views for reuse with any Django model
We’ll investigate all these opportunities later on; nonetheless, it’s nice to have a simple snippet available for copy and paste to be used as a starting point anytime a specific customization is in order.