I have been looking for a way to allow the user to easily change the order of entries in a formset. I found a StackOverflow question that addresses this subject, with the accepted answer referencing a Django Snippet that uses a JQuery tool to allow drag ‘n drop of the entries. This is nifty and cool, but I have a problem with ‘extra’ entries. If an ‘extra’ entry is modified and then dragged I get an error on the submit:
(1048, "Column 'order' cannot be null")
I believe Django keeps the ‘extra’ entries separate, since they have to be inserted instead of updates. So the reordering probably confuses matters. Is there a way to make this work, or are there other suggestions for reordering and/or adding new entries?
Edit: Added some relevant code excerpts. I’m trying this out in the admin, as the snippet shows. I’d like to put it in my own page ultimately, however.
models.py:
class Section(models.Model):
section_id = models.AutoField(primary_key=True)
section_name = models.CharField(max_length=135)
score_order = models.IntegerField()
def __unicode__(self):
return self.section_name
class Meta:
db_table = u'section'
ordering = [u"score_order"]
class Chair(models.Model):
chair_id = models.AutoField(primary_key=True)
member = models.ForeignKey(Member, null=True, blank=True,
limit_choices_to={'current_member': True})
section = models.ForeignKey(Section)
description = models.CharField(max_length=135)
order = models.IntegerField(blank=True, null=True)
def __unicode__(self):
return "%s - %s" % (self.description, self.member)
class Meta:
db_table = u'chair'
ordering = (u'section', u'order')
admin.py
class SectionForm(forms.ModelForm):
model = Section
class Media:
js = (
'/scripts/jquery.js',
'/scripts/ui.core.js',
'/scripts/ui.sortable.js',
'/scripts/section-sort.js',
)
class ChairInline(admin.StackedInline):
model = Chair
admin.site.register(Section,
inlines = [ChairInline],
form = SectionForm,
)
I found my own solution. The snippet was setting the order for every row that had a non-empty primary key value. But the extra rows have an empty primary key, and I believe they have to stay empty for Django to know that they are to be inserted instead of updated. I modified the function to check for the other fields being empty (fortunately, I only have a couple) as well as the primary key:
This did the trick for me. I could maybe improve it by adding a hidden field to the form that gets set whenever any field on a row gets modified. But at this point I’m still a jQuery n00b, so this will do. If anybody has better ideas, feel free to comment or add another answer.