How to write less same code and make it better?

Question:

I have a few similar functions with lots of same code:

class One(models.Model):
    CHOICES = (
        ('Text1', 'Text1'),
        ('Text2', 'Text2'),
        ('Text3', 'Text3'),
    )
    name = models.CharField(
        max_length=50,
        verbose_name='Name1',
        choices=CHOICES,
        unique=True
    )

    class Meta:
        ordering = ('id',)
        verbose_name = 'Name'
        verbose_name_plural = 'Names'

    def __str__(self):
        return self.name


class Two(models.Model):
    CHOICES = (
        ('Text4', 'Text4'),
        ('Text5', 'Text5'),
    )
    name = models.CharField(
        max_length=50,
        verbose_name='Name1',
        choices=CHOICES,
        unique=True
    )

    class Meta:
        ordering = ('id',)
        verbose_name = 'Name'
        verbose_name_plural = 'Names'

    def __str__(self):
        return self.name

Is it possible to write less same code and make it better?

I tried this:

class Choices(models.Model):
    CHOICES = (('.', '.'),)
    name = models.CharField(
        max_length=50,
        verbose_name='Name',
        choices=CHOICES,
        unique=True,
    )

    class Meta:
        ordering = ('id',)

    def __str__(self):
        return self.name


class One(Choices):
    CHOICES = (
        ('Text1', 'Text1'),
        ('Text2', 'Text2'),
        ('Text3', 'Text3'),
    )

    class Meta:
        verbose_name = 'Name'
        verbose_name_plural = 'Names'


class Two(Choices):
    CHOICES = (
        ('Text4', 'Text4'),
        ('Text5', 'Text5'),
    )

    class Meta:
        verbose_name = 'Name'
        verbose_name_plural = 'Names'

But it does not work.
The error: You are trying to add a non-nullable field ‘choices_ptr’ to one without a default; we can’t do that (the database needs something to populate existing rows).

Asked By: Inozem

||

Answers:

The way your inheritance hierarchy is currently set up, you have three models: One, Two, and Choices. The first two inherit from the third one using multi-table inheritance. That is, One and Two have an additional field (called choices_ptr) which is a foreign key into the Choices table.

It looks like you want Choices to be an abstract class, silently providing fields and functionality to subclasses while not itself being a model with a corresponding table in the database. If that’s the case, then you simply need to set Meta.abstract to true in the parent, and it will exist only in Python as an abstract class, not as an instantiable model.

class Choices(models.Model):
    CHOICES = (('.', '.'),)
    name = models.CharField(
        max_length=50,
        verbose_name='Name',
        choices=CHOICES,
        unique=True,
    )

    class Meta:
        ordering = ('id',)
        abstract = True # <-- Add this line :)

    def __str__(self):
        return self.name
Answered By: Silvio Mayolo
Categories: questions Tags:
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.