0

I have two Django model classes with their respective DB tables, both using the same class method. So I refactored and created an abstract parent class with the class method:

from django.db import models
from django.forms.models import model_to_dict

class Parent(models.Model):
    @classmethod
    def get_random(cls, variables: Set[str]) -> str:
        elements: list = []
        for o in cls.objects.filter(active=True):
            elements.append(model_to_dict(o, fields=["id", "string"]))
        chosen: dict = choice(elements)
        # some other code...
        return chosen["string"]

class Child1(Parent):
    string = models.CharField(max_length=100)
    type = models.ManyToManyField(Type, related_name="article_titles")
    active = models.BooleanField(default=True)

    class Meta:
        db_table = "table_child_1"

class Child2(Parent):
    string = models.TextField()
    active = models.BooleanField(default=True)

    class Meta:
        db_table = "table_child_2"

When I call the method on one of the child class with chosen_string: str = Child1.get_random(variables=variables) for example, I get a Django DB error:

django.db.utils.OperationalError: no such table: app_name_parent.

So it seems the parent class method is called on the default Django DB table name for parent class, instead of the child.

What do I miss here? What would be the most elegant solution for using the same custom class method requesting the DB for two Django models?

bolino
  • 867
  • 1
  • 10
  • 27
  • Nah both tables are invoked. If `Parent` is not an abstract model, this is multi-table inheritance, and there will have to be a db table for the parent model. – user2390182 Nov 04 '21 at 12:06
  • You need be sure that migrations for this model (`Parent`) are done and applied. or you can add `class Meta: abstract = True` to the `Parent` class – Rvector Nov 04 '21 at 12:08
  • Sorry I should say that Parent IS an abstract model. I created it only for this shared method. It must not have any DB table. – bolino Nov 04 '21 at 12:44
  • Edited. I guess if we want the parent class to be abstract, it must not inherit from Django Models, but only the childs, right? – bolino Nov 04 '21 at 13:07
  • 1
    @bolino no to make an abstract model, you need to set `abstract = True` in the model's `Meta` class, see the documentation on [Abstract base classes](https://docs.djangoproject.com/en/3.2/topics/db/models/#abstract-base-classes) – Abdul Aziz Barkat Nov 04 '21 at 13:23
  • 1
    Also your use case seems to suit a custom [manager](https://docs.djangoproject.com/en/3.2/topics/db/managers/) more than using inheritance there (The method just seems to be getting a random entry, furthermore you don't need to fetch all the entries to do that, see [Django get a random object](https://stackoverflow.com/questions/22816704/django-get-a-random-object)) – Abdul Aziz Barkat Nov 04 '21 at 13:30
  • Gotcha, thanks. Yeah a custom manager makes sense. Regarding the method code in itself, I simplified it greatly here because it wasn't interesting for the question, but it definitely needs to fetch everything. – bolino Nov 05 '21 at 04:15
  • Thanks, just needed to make the parent class an abstract one indeed, using Django model class Meta abstract attribute. Works now. Should we answer the question, or remove it? – bolino Nov 05 '21 at 05:45

0 Answers0