Validation methods to ensure start and end date come after existing instances We have a "Committee" class and I need to ensure that any new committee has start and end dates (don't know why they're CharFields instead of Dates or even Ints, but that's not my call) that are after any existing instances.  This works, but I would appreciate any general review as well as specifically on my solution to my test problem:  When no Committees exist, my tests broke as noted in the comment.  My solution worked but feels hacky.  

class Committee(models.Model):
    start_year = models.CharField(max_length=4)
    end_year = models.CharField(max_length=4)

    def save(self, *args, **kwargs):
        # new committees need to ensure start and end dates are in the future

        if not self.pk:
            committee_set = Committee.objects.all()
            latest_start_year = committee_set.aggregate(Max('start_year'))["start_year__max"]
            latest_end_year = committee_set.aggregate(Max('end_year'))["end_year__max"]

            # in the test database when there are no other committees yet, these evaluate to
            # None and break the tests. Doesn't really affect production code otherwise.
            try:
                latest_start_year = int(latest_start_year)
            except TypeError:
                latest_start_year = 0
            try:
                latest_end_year = int(latest_end_year)
            except TypeError:
                latest_end_year = 1

            if not (self.start_year &gt; latest_start_year):
                raise ValidationError("Start year (%s) must be greater than most recent "
                                      "Committee start year (%s)" % (
                                          self.start_year, latest_start_year))

            if not (self.end_year &gt; latest_end_year):
                raise ValidationError("End year (%s) must be greater than most recent "
                                      "Committee end year (%s)" % (self.end_year, latest_end_year))


        super(Committee, self).save(*args, **kwargs)
Instead of trying to convert to int and catching TypeError,
it would be better to check for None values.

Instead of committee_set.aggregate(Max('start_year'))["start_year__max"],
you could give a custom alias to the max value,
making the code slightly more compact.

Instead of getting the latest start and end years in the beginning,
it would be better to delay getting the latest end year until it's needed.
That way you may be able to avoid one unnecessary query.

Instead of the style formatting strings with '%s' % (...),
the modern way is to use '{}'.format(...).

Combining the above tips, I would write the main part like this:

query = Committee.objects

latest_start_year = query.aggregate(max=Max('start_year'))['max']
if latest_start_year and int(self.start_year) &lt;= int(latest_start_year):
    raise ValidationError("Start year {} must be greater than most recent {}".format(self.start_year, latest_start_year))

latest_end_year = query.aggregate(max=Max('end_year'))['max']
if latest_end_year and int(self.end_year) &lt;= int(latest_end_year):
    raise ValidationError("End year {} must be greater than most recent {}".format(self.end_year, latest_end_year))


If it's not very important to include in the error message the latest start and end years,
a more compact and more efficient solution is possible:

query = Committee.objects

if query.filter(start_year__gt=self.start_year).exists():
    raise ValidationError("Start year must be greater than most recent")

if query.filter(end_year__gt=self.end_year).exists():
    raise ValidationError("End year must be greater than most recent")


And let's not forget about test cases.
Django provides a rich framework for testing.
Here are some examples:

class CommitteeTests(TestCase):
    def test_create_first(self):
        self.assertEqual(0, Committee.objects.count())
        Committee(start_year='1991', end_year='1992').save()
        self.assertEqual(1, Committee.objects.count())

    def test_create_second_valid(self):
        self.assertEqual(0, Committee.objects.count())

        Committee(start_year='1991', end_year='1995').save()
        self.assertEqual(1, Committee.objects.count())

        Committee(start_year='1992', end_year='1996').save()
        self.assertEqual(2, Committee.objects.count())

    def test_should_fail_if_start_is_before_latest_start(self):
        Committee(start_year='1991', end_year='1995').save()
        with self.assertRaises(ValidationError):
            Committee(start_year='1990', end_year='1995').save()

    def test_should_fail_if_end_is_before_latest_end(self):
        Committee(start_year='1991', end_year='1995').save()
        with self.assertRaises(ValidationError):
            Committee(start_year='1992', end_year='1994').save()


Lastly, you didn't mention about it,
but the current code allows Committee instances having start date after end date.
Probably it would be a good idea to prevent that too,
not to mention valid numeric values.
These validations should come first before the others querying the database,
and there should be test cases for them too.