Say I wanted to have a project, and one-to-many with to-do items, and wanted to re-order the to-do items arbitrarily?
In the past, I\'ve added a numbered order field, a
I have had this problem with two projects I've worked on in the last little while. For my example solution I have a "Form" that has many "Variables" assigned to it and the order of the variables on the form needs to be sortable. So I have implemented the following:
models.py
class Form(models.Model):
FormName = models.CharField(verbose_name="Form Name:", max_length=40)
VariableOrder = models.CommaSeparatedIntegerField(default="[]", editable=False)
def __unicode__(self):
return "%s" % (self.FormName)
class Variable(models.Model):
FormID = models.ForeignKey(Form, default=0, editable=False, related_name="Variable")
VarName = models.CharField(max_length=32, verbose_name="Name of variable in the database:")
def __unicode__(self):
return "%s" % self.VarName
The key from above is the VariableOrder CommaSeparatedIntegerField is where we are going to store the order of the Variables on the Form, and we are going to be using it as a python list, which is why the default is [].
For the template I render my Variables in an that we are going to make drag and drop sortable (the list elements I actually use have a ton more CSS related styling and information about the Variable).
{% for Variable in VarList %}
- {{ Variable }}
{% endfor %}
Now we are going to make the list drag and drop for the changing of order. For this to work you need to have the AJAX CSRF snippet from Django site in the head
$(function() {
$("#sortable" ).sortable({
placeholder: "ui-state-highlight",
update: function(event, ui){
$.ajax({
type:"POST",
url:"{% url builder.views.variableorder %}",
data: {Order: JSON.stringify($('#sortable').sortable('toArray')) },
success: function(data){
// Do stuff here - I don't do anything.
}
});
}
});
$( "#sortable" ).disableSelection();
});
The important part above is that "update" calls the function every time there is a position change of any of the variables, which sends the AJAX. toArray on sortable along with the JSON stringify gets us sending the top to bottom id's of each variable, which is used by the view as follows. Note: I keep the active Form object as a session variable, but in another case you would just need to call the Form object you were wanting to change the order of.
def variableorder(request):
if request.is_ajax():
Order = request.POST['Order']
updateOrder = request.session['FormID']
updateOrder.VariableOrder = newOrder
updateOrder.save()
request.session['FormID'] = Form.objects.get(id=updateOrder.id)
return HttpResponse("Order changed.")
else:
pass
The key of all of this is that you can use this CommaSeparatedIntegerField as a list by evaluating the string. For example:
Adding a Variable:
aForm = Form.objects.get(id=1)
currentOrder = aForm.VariableOrder
currentOrder = eval(currentOrder)
newVar = Variable(stuff in here)
newVar.save()
currentOrder.append(newVar.id)
aForm.VariableOrder = currentOrder
aForm.save()
Removing a Variable:
aForm = Form.objects.get(id=1)
currentOrder = aForm.VariableOrder
currentOrder = eval(currentOrder)
# Variable ID that we want to delete = 3
currentOrder.remove(3)
aForm.VariableOrder = currentOrder
aForm.save()
Rendering the Variables in Order:
aForm = Form.objects.get(id=1)
currentOrder = aForm.VariableOrder
currentOrder = eval(currentOrder)
VarList = []
for i in currentOrder:
VarList.append(Variable.objects.get(id=i))
This is a rough first draft of what I am going to use, but it is working well for me. The obvious first improvement being the evaluation to python list being a method in the class. eg.
def getVarOrder(self):
return eval(self.VariableOrder)
and then just call Form.getVarOrder() when want to manipulate the list. In any case hopefully this helps out.
JD