'How to Enforce Consecutive Numbering in "Through" Model Field
I'm using Python 3.7 with Django 3.1.
I have two models: Text and Edition. There are a fixed number of texts, and users will be able to create editions in which they place these texts in whatever order they want. This is accomplished by means of a "through" model, EditionTextThrough, which keeps track of the position of a given text in a given edition:
class EditionTextThrough(models.Model):
text = models.ForeignKey(Text, on_delete=models.CASCADE)
edition = models.ForeignKey(Edition, on_delete=models.CASCADE)
position = models.PositiveSmallIntegerField(
validators=[MinValueValidator(1), MaxValueValidator(372)])
class Meta:
ordering = ['edition', 'position']
unique_together = ['edition', 'position']
This works fine. However, I want to enforce consecutive numbering for the "position" attribute, relative to the Edition it is paired with. Django's auto-generated IDs won't do this, because they are simply assigned to each row in the table, and don't start over with each Edition that is contained in it. Django's IDs can't do what I want for another reason as well: I want the "position" numbers to remain consecutive, even when some of them are deleted:
position | edition_id | text_id
1 | uuid | 4
2 | uuid | 22
3 | uuid | 128
4 | uuid | 16
5 | uuid | 3
Now, if the third entry is deleted, I don't want to see 1, 2, 4, 5, but rather this:
position | edition_id | text_id
1 | uuid | 4
2 | uuid | 22
3 | uuid | 16
4 | uuid | 3
The position values are not important on their own, but are only supposed to indicate the position of a given text within a given edition. I don't want to end up with gaps like 1, 2, 4, 5, so I need a way to enforce consecutive, ascending numbers for this column (again, relative to the edition uuid). I realize this might not be trivial to accomplish, but it is basic to the functioning of my program, so I think it is worth taking the time to sort it out.
Solution 1:[1]
I realized that this was a stupid question. I don't want to knock Django or other frameworks like it, but they do tend to instill a mentality in which you expect the framework to have a ready way of handling everything for you, and you just need to find out what it is in a given case.
The obvious solution was to override the delete() method of the EditionTextThrough model, so that whenever an instance was deleted, it would loop through the remaining instances for that edition and reassign their "position" numbers beginning consecutively from 1. As a programming problem, this is obvious. As a "Django problem" it was not so obvious to me.
Solution 2:[2]
I try to overriding save_model() method in ModelAdmin class. Maybe can help you.
def save_model(self, request, obj, form, change):
# check for update method
if obj.id is not None:
obj.save()
else: # check for create, delete method
id_li = list(EquipmentCategory.objects.values_list('id', flat=True))
if len(id_li) > 0:
max_id = max(id_li)
else:
max_id=0
obj.id = max_id+1
obj.save()
super(EquipmentCategoryAdmin, self).save_model(request, obj, form, change)
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 | gorgias |
| Solution 2 | Jimit Vaghela |
