Suppose my models.py is much like so:
class Character(models.Model): name = models.CharField(max_length=255) is_the_chosen_one = models.BooleanField()
I would like just one of my
Character instances to possess
is_the_chosen_one == True and all sorts of others to possess
is_the_chosen_one == False . How do i best ensure this originality constraint is respected?
Top marks to solutions that consider the significance of improving the constraint in the database, model and (admin) form levels!
Whenever I have needed to do this task, what I have done is override the save way of the model and also have it see if every other model has got the flag already set (and power it down).
class Character(models.Model): name = models.CharField(max_length=255) is_the_chosen_one = models.BooleanField() def save(self): if self.is_the_chosen_one: try: temp = Character.objects.get(is_the_chosen_one=True) if self != temp: temp.is_the_chosen_one = False temp.save() except Character.DoesNotExist: pass super(Character, self).save()
class Character(models.Model): name = models.CharField(max_length=255) is_the_chosen_one = models.BooleanField() def save(self, *args, **kwargs): if self.is_the_chosen_one: qs = Character.objects.filter(is_the_chosen_one=True) if self.pk: qs = qs.exclude(pk=self.pk) if qs.count() != 0: # choose ONE of the next two lines self.is_the_chosen_one = False # keep the existing "chosen one" #qs.update(is_the_chosen_one=False) # make this obj "the chosen one" super(Character, self).save(*args, **kwargs) class CharacterForm(forms.ModelForm): class Meta: model = Character # if you want to use the new obj as the chosen one and remove others, then # be sure to use the second line in the model save() above and DO NOT USE # the following clean method def clean_is_the_chosen_one(self): chosen = self.cleaned_data.get('is_the_chosen_one') if chosen: qs = Character.objects.filter(is_the_chosen_one=True) if self.instance.pk: qs = qs.exclude(pk=self.instance.pk) if qs.count() != 0: raise forms.ValidationError("A Chosen One already exists! You will pay for your insolence!") return chosen
You should use the above mentioned form for admin too, only use
class CharacterAdmin(admin.ModelAdmin): form = CharacterForm admin.site.register(Character, CharacterAdmin)
will i get points for responding to my question?
problem maybe it was was finding itself informed, fixed by:
# is this the testimonial image, if so, unselect other images if self.testimonial_image is True: others = Photograph.objects.filter(project=self.project).filter(testimonial_image=True) pdb.set_trace() for o in others: if o != self: ### important line o.testimonial_image = False o.save()