0

I have a bunch of classes that I'm now trying to incorporate into django.

For example, I have a Base class that all my other classes derive from:

class Base:
    def __init__(self, label: str = 'Base'):
        self.label = label

An example of a sublcass would be a Person class:

from typing import Any, Dict

class Person(Base):
    def __init__(self, name: str, attributes_to_options: Dict[str, Any], **kwargs):
        super().__init__(**kwargs)
        self.name = name
        self.attributes_to_options = attributes_to_options

I would use this as:

alex = Person(name='Alex', attributes_to_options={'age': 10, 'is_happy': True}, label='Person:Alex')

My question is, how do I incorporate such a class into django? Is it as simple as inheritting from models.Model? e.g.

from django.db import models

class Person(Base, models.Model):
    def __init__(self, name: str, attributes_to_options: Dict[str, Any], **kwargs):
        super().__init__(**kwargs)
        self.name = name
        self.attributes_to_options = attributes_to_options

But then how do I specify the models.CharField for the two attributes name and attributes_to_options?

Thanks for any help here.

7
  • 1
    Have you tried declaring name = models.CharField(...) etc in the Person class scope? The important thing is that model fields must be declared in a class that inherits from models.Model. Commented Aug 6, 2019 at 10:00
  • 1
    You can have an abstract base model that implements some fields, like "label" Commented Aug 6, 2019 at 10:00
  • I'm not sure why you would use a CharField for the attributes_to_option attribute, since that is a dictionary. If you do want that, you would have to convert it to a string before saving. If you are using postgresql, you shoud consider using JSONField instead of CharField. Commented Aug 6, 2019 at 10:01
  • Passing dictionaries as parameters is nearly always a bad idea... a dictionary is a key/value store not a mobile namespace Commented Aug 6, 2019 at 10:02
  • 1
    @alex_lewis the issue with passing a dictionary around as an object/namespace is that when you or anyone else comes to debug your code you will just see a dictionary passed in to the function with no idea what is in it, then you have to trawl up the stack and maybe find where that key was set or maybe not, I have been there and it is not fun. Explicit parameters to functions may be slightly more restrictive but save a lot of debugging effort Commented Aug 6, 2019 at 10:11

1 Answer 1

1

Bear in mind that in general, any Django Model subclass corresponds to a database table. Inheriting from such a class ("concrete inheritance") means that another database table will be created with a one-to-one linkage between rows, and that every query will implicitly perform a join in the DB. This is bad for performance. But for tables with not very many rows or for tables queried infrequently, you possibly don't need to care.

Django provides two special cases that can be defined via the Meta class in the Model subclass. The first is an "Abstract Base Class" which allow you to define a bunch of stuff which will be present in any derived model. IN the case of fields, they are "copied" into the class that inherits them, rather than having their own DB table. The second is a "Proxy" class, which allows you to place a new set of methods on top of an existing database table, and which goes some way towards allowing polymorphic models. Careful reading of the Django doc. is a good idea.

I have experimentally established that one can also use mix-in classes in the same way as one uses them with class-based views. In other words,

class ExtraMethodsMixin( object): # NB must inherit from object
    # NB no model field definitions allowed here
    @property
    def something_or_other(self):
         return something_based_on_model_fields_defined_elsewhere
    #etc.

and then

class Foo( ExtraMethodsMixin, models.Model): # NB mixin goes first
    # define names and fields that the ExtraMethodsMixin uses
    #   (and anything else that a Foo needs)
    ...

The one snag I have found is that migrations do remember the dependency of Foo on ExtraMethodsMixin and so it's a PITA should you desire to completely remove the mixin at a later date. However, you can stub it out to a single pass statement without any problems, so this is probably not a significant worry. My other worry is that this usage is completely undocumented (other than as standard Python), so it's just about possible that it's trampling on Django internals in some very subtle way I've not yet spotted. So I'm definitely a bit short of recommending this technique.

Sign up to request clarification or add additional context in comments.

1 Comment

s/plugin class/mixin class/g

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.