Now I understand — you want to inherit from a concrete model but to use a 
separate table.

I’m not sure how widely applicable this would be. I find it counter-intuitive 
that Parent.objects.all() isn’t a superset of Child.objects.all() anymore. This 
is a surprising way to implement inheritance.

The usual ways to implement inheritance in an ORM are single-table inheritance 
(STI) and multi-table inheritance (MTI). Django supports MTI. It also supports 
inheriting Python classes without affecting the database, with abstract or 
proxy models, depending on whether the database table(s) are tied to the 
children or the parent.



In your use case, the only reason why you can’t make the parent model abstract 
is that it’s provided by a third-party app. Perhaps the general problem is to 
customize models provided by third-party apps? At this time, Django doesn’t 
provide a mechanism for doing that. The two solutions I know of are:

1) Swappable models: this is only officially supported for the auth.User model 
via the AUTH_USER_MODEL setting but it’s technically possible to achieve a 
similar effect with other models.
2) App-registry hacks: for example, that’s what django-oscar does; I’m not sure 
they would have ended up with the solution if they had started after Django 
1.7, though.

So, in the current state of things, the path of least resistance is to 
encourage authors of reusable apps to provide an abstract version of 
inheritable models in addition to the concrete version, like Django does with 
AbstractUser and User, and perhaps discuss making swappable models a supported 
API.


If we leave aside the current implementation of abstract models for a moment, 
for your use case, I can see the logic in having the child model declare what 
kind of inheritance it uses rather than the parent. In the end, it’s the 
child’s database table that has either a FK to the parent of a copy of all the 
parent’s columns (with your patch). `copy_from_base` is a poor name for 
declaring the whether you’re using MTI or not, though.

If we ever implement single table inheritance (STI), either having the parent 
declaring that it collects database columns from all its children or the 
children declare that they add database columns to their parent will be 
awkward. When inheriting across applications, that will interact very poorly 
with the migrations framework. So it’s unclear that one solution is better than 
the other here.

That said, we need to keep `abstract = True` on the parent to prevent the 
creation of a related database table, which could be accidentally used even if 
the model was intended to be abstract.

So I don’t think we can draw a general conclusion on whether inheritance 
behavior should be declared on parents or children.


To sum up, Django currently provides limited but safe options for model 
inheritance:

- MTI — it's the default when inheriting from a regular model; the main 
usability drawback is that there’s no good way to specialize a queryset of 
parents into children
- abstract models (declared on the parent) — the parent cannot interact with 
the database, each child has its own table, which avoids interactions between 
the ORM and inheritance
- proxy models (declared on the child) — the child only specializes Python 
behavior, only the parent has a table, which also avoids interactions between 
the ORM and inheritance

There has been some talk about introducing STI but I don’t remember seeing a 
concrete proposal. (Also STI looks suspiciously similar to GFK which aren’t 
very popular among the core team.)

Looking at where your proposal would fit in this landscape, it’s unclear to me 
that the benefits outweigh the bizarre result of making both 
Parent.objects.all() and Child.objects.all() work, but not have the latter be a 
subset of the former.

I would be more comfortable with providing guidelines for reusable apps whose 
models may be inherited.


I suppose I just spent two pages rebuilding the reasoning behind the design of 
abstract models… I hope this helps anyway!

-- 
Aymeric.


> On 02 Mar 2016, at 11:02, Joakim Saario <[email protected]> wrote:
> 
> Yes it is true the patch do include some code for overriding parent fields, 
> but that is not the main feature.
> 
> In any way this thread is a double post (I thought the first one got lost). 
> Look at: 
> https://groups.google.com/forum/?hl=sv#!topic/django-developers/koRZDDCQREc 
> instead.
> 
> Den onsdag 2 mars 2016 kl. 10:52:07 UTC+1 skrev Aymeric Augustin:
> In that case, I believe this is the ticket you’re looking for: 
> https://code.djangoproject.com/ticket/24305 
> <https://code.djangoproject.com/ticket/24305>
> 
> There seems to be some activity on the related PR: 
> https://github.com/django/django/pull/5122 
> <https://github.com/django/django/pull/5122>
> 
> You may want to review these discussions and see how you can help. Thanks!
> 
> -- 
> Aymeric.
> 
>> On 02 Mar 2016, at 10:25, Joakim Saario <[email protected] <javascript:>> 
>> wrote:
>> 
>> I'm sorry, this is a typo, local fields overrides parent fields of course. 
>> Look at the patch.
>> 
>> Den onsdag 2 mars 2016 kl. 08:19:23 UTC+1 skrev Aymeric Augustin:
>> Hello,
>> 
>> The “locally declared field gets overriden by parent definition” behavior 
>> shown in your example looks counter-intuitive to me.
>> 
>> Inheritance means that children inherit and possibly specialize their 
>> parent’s behavior, not that the parent overrides the child.
>> 
>> Best regards,
>> 
>> -- 
>> Aymeric.
>> 
>>> On 02 Mar 2016, at 01:57, Joakim Saario <[email protected] <>> wrote:
>>> 
>>> Hello!
>>> 
>>> I'd like to propose another inheritance strategy for django's models.
>>> 
>>> Think of it sort of like reversed abstract models
>>> 
>>> For example:
>>> 
>>> class NormalModel(models.Model):
>>>     foo = models.CharField(max_length=10)
>>>     bar = models.CharField(max_length=10)
>>> 
>>> class CopiedBaseModel(NormalModel):
>>>     bar = models.CharField(max_length=2)
>>>     buzz = models.CharField(max_length=10)
>>> 
>>>     class Meta:
>>>         copy_from_base = True
>>> 
>>> Would be equivalent to:
>>> 
>>> class NormalModel(models.Model):
>>>     foo = models.CharField(max_length=10)
>>>     bar = models.CharField(max_length=10)
>>> 
>>> class CopiedBaseModel(NormalModel):
>>>     foo = models.CharField(max_length=10)
>>>     bar = models.CharField(max_length=10)
>>>     buzz = models.CharField(max_length=10)
>>> 
>>> My initial use case for this was with django-cms which didn't play well with
>>> multi-table inheritance when i needed to extend a built in plugin of 
>>> theirs. So
>>> I ended copying the whole model instead, which didn't make me too happy.
>>> So I started writing some code for the behaviour I was after. Which was,
>>> ironicly a standard python inheritance. Django only offers part of this 
>>> behaviour
>>> through the proxy and abstract models. But neither of them worked for me.
>>> 
>>> This is quite easy to implement with some of the current abstract model
>>> logic (see the patch).
>>> 
>>> -- 
>>> You received this message because you are subscribed to the Google Groups 
>>> "Django developers (Contributions to Django itself)" group.
>>> To unsubscribe from this group and stop receiving emails from it, send an 
>>> email to [email protected] <>.
>>> To post to this group, send email to [email protected] <>.
>>> Visit this group at https://groups.google.com/group/django-developers 
>>> <https://groups.google.com/group/django-developers>.
>>> To view this discussion on the web visit 
>>> https://groups.google.com/d/msgid/django-developers/d4872520-eeb1-49a7-a8f3-aefc23a98346%40googlegroups.com
>>>  
>>> <https://groups.google.com/d/msgid/django-developers/d4872520-eeb1-49a7-a8f3-aefc23a98346%40googlegroups.com?utm_medium=email&utm_source=footer>.
>>> For more options, visit https://groups.google.com/d/optout 
>>> <https://groups.google.com/d/optout>.
>>> <django-copy-from-base.diff>
>> 
>> 
>> -- 
>> You received this message because you are subscribed to the Google Groups 
>> "Django developers (Contributions to Django itself)" group.
>> To unsubscribe from this group and stop receiving emails from it, send an 
>> email to [email protected] <javascript:>.
>> To post to this group, send email to [email protected] 
>> <javascript:>.
>> Visit this group at https://groups.google.com/group/django-developers 
>> <https://groups.google.com/group/django-developers>.
>> To view this discussion on the web visit 
>> https://groups.google.com/d/msgid/django-developers/d95ca003-a45a-4030-b36f-b7b2ffddd9fb%40googlegroups.com
>>  
>> <https://groups.google.com/d/msgid/django-developers/d95ca003-a45a-4030-b36f-b7b2ffddd9fb%40googlegroups.com?utm_medium=email&utm_source=footer>.
>> For more options, visit https://groups.google.com/d/optout 
>> <https://groups.google.com/d/optout>.
> 
> 
> -- 
> You received this message because you are subscribed to the Google Groups 
> "Django developers (Contributions to Django itself)" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to [email protected] 
> <mailto:[email protected]>.
> To post to this group, send email to [email protected] 
> <mailto:[email protected]>.
> Visit this group at https://groups.google.com/group/django-developers 
> <https://groups.google.com/group/django-developers>.
> To view this discussion on the web visit 
> https://groups.google.com/d/msgid/django-developers/aec59b40-b2cf-4408-952e-4f5ad3619e9f%40googlegroups.com
>  
> <https://groups.google.com/d/msgid/django-developers/aec59b40-b2cf-4408-952e-4f5ad3619e9f%40googlegroups.com?utm_medium=email&utm_source=footer>.
> For more options, visit https://groups.google.com/d/optout 
> <https://groups.google.com/d/optout>.

-- 
You received this message because you are subscribed to the Google Groups 
"Django developers  (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/django-developers.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-developers/04D06552-CCC8-4B91-B76C-E3888B7DED40%40polytechnique.org.
For more options, visit https://groups.google.com/d/optout.

Reply via email to