Reputation: 3060
I have a Django model (ChildrenGodfather) that relates 3 other models: Child, Godfather and Edition (2012, 2013, 2014..).
When we create a new ChildrenGodfather, there is no Edition field: it automatically saves it using the latest edition, without showing it to the user (already working)
We can't have the same Child with the same Godfather in the same Edition, but we can have the same Child with the same Godfather in different Editions.
The problem is.. the is no field edition in the forms when creating, so we didn't get a way to validate the edition. So our validation is not allowing us to have Child with the same Godfather in different Editions.
You can get a working code here:
==== models.py ====
class Edition(models.Model):
name = models.CharField(max_length=255, verbose_name=u'Name')
date = models.DateField(verbose_name=u'Date')
class Godfather(models.Model):
name = models.CharField(max_length=255, verbose_name=u'Name')
is_active = models.BooleanField(_('active'), default=True, help_text=u'Is active?')
class Children(models.Model):
name = models.CharField(max_length=255, verbose_name=u'Name')
is_active = models.BooleanField(_('active'), default=True, help_text=u'Is active?')
class ChildrenGodfather(models.Model):
class Meta:
verbose_name = u'Sponsorship'
unique_together = ['child', 'godfather', 'edition']
child = models.ForeignKey(Children, verbose_name=u'Child')
godfather = models.ForeignKey(Godfather, verbose_name=u'Godfather')
edition = models.ForeignKey(Edition)
def save(self, *args, **kwargs):
# if it is creating, don t need to tell edition
if not self.pk:
self.edition = Edition.objects.order_by('-date')[0:1].get()
super(ChildrenGodfather, self).save(*args, **kwargs)
==== forms.py ====
class ChildrenGodfatherForm(forms.ModelForm):
child = forms.ModelChoiceField(label=u'Child', queryset=Children.objects.filter(is_active=True))
godfather = forms.ModelChoiceField(label=u'Godfather', queryset=Godfather.objects.filter(is_active=True))
# TODO improve checking for editions
def clean(self):
try:
ChildrenGodfather.objects.get(child=self.cleaned_data['child'],
godfather=self.cleaned_data['godfather'])
#if we get this far, we have an exact match for this form's data
raise forms.ValidationError(u"This sponsorship already exists. Duplicated sponsorship are not allowed!")
except ChildrenGodfather.DoesNotExist:
#because we didn't get a match
pass
return self.cleaned_data
==== admin.py ====
class ChildrenGodfatherAdmin(admin.ModelAdmin):
form = ChildrenGodfatherForm
fields = ['child', 'godfather']
list_display = ['__unicode__', 'child', 'godfather', 'status']
list_filter = ['child', 'godfather', 'status']
Thanks.
Upvotes: 0
Views: 221
Reputation: 351
You could override the init method of ChildrenGodfatherForm to initialize default edition
def __init__(self, *args, **kwargs):
super(ChildrenGodfatherForm, self).__init__(*args,**kwargs)
instance = kwargs.get('instance')
if instance is not None:
self.edition = instance.edition # updating existing object, use its edition
else:
self.edition = Edition.objects.latest('date') # creating new object, use default edition.
and then modify the query in clean method to use this parameter
ChildrenGodfather.objects.get(child=self.cleaned_data['child'],
godfather=self.cleaned_data['godfather'], edition=self.edition)
Upvotes: 1
Reputation: 11369
def default_edition():
return Edition.objects.latest('date') # or Edition.objects.order_by('-date')[0]
class ChildrenGodfather(models.Model):
class Meta:
verbose_name = u'Sponsorship'
unique_together = ['child', 'godfather', 'edition']
child = models.ForeignKey(Children, verbose_name=u'Child')
godfather = models.ForeignKey(Godfather, verbose_name=u'Godfather')
edition = models.ForeignKey(Edition, default=default_edition)
def save(self, *args, **kwargs):
super(ChildrenGodfather, self).save(*args, **kwargs)
class ChildrenGodfatherAdmin(admin.ModelAdmin):
form = ChildrenGodfatherForm
fields = ['child', 'godfather', 'edition']
list_display = ['__unicode__', 'child', 'godfather', 'edition', 'status']
list_filter = ['child', 'godfather', 'edition', 'status']
if you want the Edition field to be hidden on object creation, but visible on object edition, you can add this method to your ChildrenGodfatherAdmin
class:
def get_form(self, request, obj=None, **kwargs):
if obj is None:
self.exclude = ["edition"]
form = super(ChildrenGodfatherAdmin, self).get_form(request, obj, **kwargs)
return form
Upvotes: 1