Add an accepted CHOICE to a model while using Multi-Table Inheritance

Hi all,

is it possible to add a “choice” in an existing model’s field, when I created the model by using multi-table inheritance?

I’ve got the original model.py from the post_office app:

STATUS = namedtuple('STATUS', 'sent failed queued requeued')._make(range(4))
class Email(models.Model):
    STATUS_CHOICES = [(STATUS.sent, _("sent")), (STATUS.failed, _("failed")),
                      (STATUS.queued, _("queued")), (STATUS.requeued, _("requeued"))]
    ...
    status = models.PositiveSmallIntegerField(
        _("Status"),
        choices=STATUS_CHOICES, db_index=True,
        blank=True, null=True)

and would like to add the choice _(“CustomChoice”) to my model I created using multi-table inheritance:

class MYEmail(post_office_models.Email):
    ...

Is there any way to achieve that?

Background / Use-Case:
I schedule e-mails that shall be sent at a later time (discussed here). Just before they are sent, I add a single parameter to the model entry.

The original post-office function I chose for sending scheduled e-mails runs a management command every minute as a cronjob:

  1. It makes a db query to check if any scheduled mail with the status STATUS.queued needs to be sent and…
  2. …sends it if that’s the case.

My slightly adjusted management command is also a cronjob and works like that:

  1. It makes a db query to check if any scheduled mail with the status STATUS.queued needs to be sent
  2. Receives the mails that are queued and performs the slight changes. Then, as above, it…:
  3. …makes a db query to check if any scheduled mail with the status STATUS.queued needs to be sent and…
  4. …sends it if that’s the case.

As discussed in the thread linked above, this is not the most performant solution, but, beneath others, it was programmed with just some lines of code and works like a charm.

BUT: If I could simply add another STATUS_CHOICE, I could use it for the scheduled mails that need some treatment before being sent. Then I filter for mails from step 1 and 2, make the changes, set the status to “STATUS.queued” and then the mails could be “normally” sent in step 3 and 4. I see the following advantages:

  • If I accidently hit the original management command for sending e-mails (which obviously only performs step 3 and 4), no “unedited” mail will be sent. This would be some kind of safety net.
  • If I ever decide to use post_office’s function of sending scheduleing mails at any part of the project, I would not need to consider the mails which are actually in the status “queued” and need the “special treatment” before being sent.

BR :slight_smile:

FYI, from Django 3.0 you can use built-in enumeration types - see my post. You could make a PR upstream for this.

I don’t believe this is possible. You cannot alter the fields on the parent model, nor any data inside them.

If you try to shadow a field in the parent model, you’ll get:

django.core.exceptions.FieldError: Local field 'choices' in class 'MYEmail' clashes with field of the same name from base class 'Email'.

You could try adding another field to indicate if the “extra treatment” is required. Otherwise, with custom requirements, you could copy relevant code from post office into your project and drop it as a dependency. You already know what you want, and you can customize it further as required.

1 Like

Argh, that’s the result of my research too - and absolutely not what I wanted to hear… :roll_eyes: :laughing: :laughing: :laughing:

Thanks, Adam! If anyone else has a good idea, feel free. :slight_smile: