32

I've got some code that looks like this:

class BaseMessage(models.Model):
    is_public = models.BooleanField(default=False)
    # some more fields...

    class Meta:
        abstract = True

class Message(BaseMessage):
    # some fields...

and I'd like to override the default value of the is_public field in the Message model so that it's True for that model.

I've looked through some relevant Django docs and poked around the model objects but I'm having trouble finding the right place to do this. Any suggestions?

John Debs
  • 3,714
  • 2
  • 25
  • 35

2 Answers2

36

You can actually do this as follows:

class BaseMessage(models.Model):
    is_public = models.BooleanField(default=False)
    # some more fields...

    class Meta:
        abstract = True

class Message(BaseMessage):
    # some fields...
Message._meta.get_field('is_public').default = True

I have done this once or twice. It works, because the field on Message is a different instance than the field on BaseMessage. However, I doubt it's recommended ;-) It depends a lot on how django internals currently work, so there's no guarantee that it will work forever.

melinath
  • 800
  • 6
  • 10
  • 5
    This worked for me. In my case I was overriding help text. It made more sense to move that code into the initializer though, so I have: def __init__(self, *args, **kwargs): super(MyModelClass, self).__init__(*args, **kwargs) self._meta.get_field('mymodelfield').help_text = self.help_text() – Mark Jul 18 '13 at 18:33
  • 5
    I try this for the attribute "unique", but I get this: `AttributeError: can't set attribute`. – guettli Nov 26 '15 at 11:57
  • 5
    @guettli Same here. Doesn't seem to work for setting `unique`. This is on Django 1.7. – Maik Hoepfel Dec 10 '15 at 12:46
  • if you want to update unique use `_unique` – Sawan Chauhan Jul 20 '22 at 15:09
  • Unfortunately, today, on Django 4.1.3, the code above actually changes the base class, and the default then applies to all subclasses. :( – Scott Smith May 15 '23 at 14:22
0

For validation level overload like max_length one could add this to apps.py ready method

from django.apps import AppConfig
from django.utils.translation import gettext_lazy as _


class MyAppConfig(AppConfig):
    name = "myapp"
    verbose_name = _("myapp")

    def ready(self):
        from myapp.models import MyModel

        # HACK: to set max_length for field when you can't change
        # this on parent model for example when inheriting from third
        # party app
        MyModel._meta.get_field('field').max_length = 128
Sardorbek Imomaliev
  • 14,861
  • 2
  • 51
  • 63