Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the right way to have custom instance attributes in Django models?

I want to add custom attributes to instances of a Django model. These attributes should not be stored in the database. In any other class, the attributes would simply be initialized by the __init__ method.

I can already see three different ways to do it, and none of them are completely satisfying. I wonder if there is any better/more pythonic/djangoist way to do it?

  1. Override the __init__ method: the syntax is a bit convoluted, but it works.

    from django.db.models import Model
    
    class Foo(Model):
      def __init__(self, *args, **kwargs):
         super(Model, self).__init__(*args, **kwargs)
         self.bar = 1
    
  2. Use a Django post_init signal: this takes class code outside of the class definition, which is not very readable.

    from django.dispatch import receiver
    from django.db.models.signals import post_init
    @receiver(post_init, sender=Foo)
        def user_init(sender, instance, *args, **kwargs):
          instance.bar = 1
    
  3. Use an instance method instead of an attribute: having a general exception raised as the default behaviour is a bit disturbing.

    class Foo(Model):
      def bar(self):
        try:
          return self.bar
        except:
          self.bar = 1
        return self.bar
    

Of these three choices, the first looks like the least worst to me. What do you think? Any alternative?

like image 657
Régis B. Avatar asked Jan 22 '13 16:01

Régis B.


People also ask

How do I create an instance of a Django model?

To create a new instance of a model, instantiate it like any other Python class: class Model (**kwargs) The keyword arguments are the names of the fields you've defined on your model. Note that instantiating a model in no way touches your database; for that, you need to save() .

How do I create an instance of an object in Django?

To create an object, instantiate it using keyword arguments to the model class, then call save() to save it to the database. This performs an INSERT SQL statement behind the scenes. Django doesn't hit the database until you explicitly call save() .

What is def __ str __( self in Django model?

def __str__( self ): return "something" This will display the objects as something always in the admin interface. Most of the time we name the display name which one could understand using self object.

What is attribute in model Django?

In Django , a model field pertains to a column in the database. On the other hand, a model attribute pertains to a method or property that is added to a model .


2 Answers

I would use the property decorator available in python

class Foo(Model):
    @property
    def bar(self):
        if not hasattr(self, '_bar'):
            self._bar = 1

        return self._bar

Then you can access that just like a property instead of invoking a function with ()

You could even get a little more straight forward with this by having the fallback built in, instead of stored

class Foo(Model):
    @property
    def bar(self):
        return getattr(self, '_bar', 1)
like image 94
Bryan Avatar answered Sep 18 '22 22:09

Bryan


Overriding __init__ is the right way.

like image 37
Pawel Furmaniak Avatar answered Sep 17 '22 22:09

Pawel Furmaniak