Code

Opened 5 years ago

Closed 3 years ago

Last modified 3 years ago

#11369 closed (fixed)

verbose_name_plural not inherited if base class is abstract.

Reported by: Beetle_B Owned by: ramiro
Component: Database layer (models, ORM) Version: 1.0
Severity: Keywords: verbose_name_plural, inheritance, abstract
Cc: mueen@…, bronger@… Triage Stage: Accepted
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: UI/UX:

Description

Perhaps this is desired behavior. However, I think the docs should mention this explicitly.

The situation where this arose is that I was creating a CategoryBase class (abstract), which was a bit barebones. I then subclassed this to get a number of derived classes (all abstract as well) - because I have different use cases (some need an HTML description, which will be formatted using Textile or Markdown, etc). Then for one particular app, I needed one of these, so I subclassed (without making it an abstract class).

I had set verbose_name_plural in the Meta of the original CategoryBase class. This did not get inherited...

In summary:

CategoryBase --> CategoryMarkup --> Category

where all but Category were abstract classes.

Anyway, I'm not arguing it should be inherited - will leave that up to you to decide. I just feel that if it isn't, it should be reflected in the docs for abstract base classes.

Attachments (1)

11369-r11267.diff (2.4 KB) - added by ramiro 5 years ago.

Download all attachments as: .zip

Change History (18)

comment:1 Changed 5 years ago by Beetle_B

  • Cc mueen@… added
  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset

comment:3 Changed 5 years ago by Beetle_B

It's not obvious from those docs.

It explicitly states that Meta options are inherited if you don't define a Meta class. It then goes on to say that some options aren't (giving the examples of db_table and abstract). That's about it. Are we supposed to guess whether verbose_name_plural is inherited?

db_table is obvious.
abstract is not that obvious, which is why it was explicitly explained.

Likewise, I think stuff like verbose_name_plural is not obvious.

(Unless I'm missing something else from the docs...)

comment:4 Changed 5 years ago by Alex

  • Component changed from Uncategorized to Documentation
  • Triage Stage changed from Unreviewed to Accepted

The documentation should explicitly state what properties are/are not inherited.

comment:5 Changed 5 years ago by ramiro

Some tests I've performed trying to understand this ticket (also available at http://dpaste.de/45tH/), the <django.utils.functional.__proxy__ object hints this is getting handled by the string_concat calls in django.db.models.options.Option.contribute_to_class:

# models.py

from django.db import models

class CategoryBase(models.Model):
    class Meta:
        abstract = True
        verbose_name_plural = u'CategoryBase verbose_name_plural'

class Category(CategoryBase):
    title = models.CharField(max_length=100)

#----------------------
>>> from t11369.models import Category

>>> c = Category(title=u'Title A')
>>> c.save()
>>> print Category._meta.verbose_name_plural
CategoryBase verbose_name_plural
>>> print c._meta.verbose_name_plural
CategoryBase verbose_name_plural

#======================
# models.py

from django.db import models

class CategoryBase(models.Model):
    class Meta:
        abstract = True
        verbose_name_plural = u'CategoryBase verbose_name_plural'

class CategoryMarkup(CategoryBase):
    class Meta:
        abstract = True
        verbose_name_plural = u'CategoryMarkup verbose_name_plural'

class Category(CategoryMarkup):
    title = models.CharField(max_length=100)

#----------------------
>>> from t11369.models import Category

>>> c = Category(title=u'Title A')
>>> c.save()
>>> print Category._meta.verbose_name_plural
CategoryMarkup verbose_name_plural
>>> print c._meta.verbose_name_plural
CategoryMarkup verbose_name_plural

#======================
# models.py

from django.db import models

class CategoryBase(models.Model):
    class Meta:
        abstract = True
        verbose_name_plural = u'CategoryBase verbose_name_plural'

class CategoryMarkup(CategoryBase):
    class Meta:
        abstract = True

class Category(CategoryMarkup):
    title = models.CharField(max_length=100)

#----------------------
>>> from t11369.models import Category

>>> c = Category(title=u'Title A')
>>> c.save()
>>> print Category._meta.verbose_name_plural
<django.utils.functional.__proxy__ object at 0xb75a76ec>
>>> print c._meta.verbose_name_plural
<django.utils.functional.__proxy__ object at 0xb75a76ec>

comment:6 Changed 5 years ago by ramiro

  • Component changed from Documentation to Database layer (models, ORM)

As can be seen above, problem occurs when there is one or more intermediate abstract classes between the one containing the verbose_name_plural definition and the non-abstract one.

In the example posted by the OP, the CategoryMarkup model needs to define its own inner Meta class basause it has to explicitely specify it is a abstract class. Then, if it is desired it inherits the verbose_name_plural attribute from CategoryBase we need to make sure it extends its Meta inner class by subclassing it:

class CategoryBase(models.Model):
    class Meta:
        abstract = True
        verbose_name_plural = u'CategoryBase verbose_name_plural'

class CategoryMarkup(CategoryBase):
    class Meta(CategoryBase.Meta):
        abstract = True

#...

OP didn´t paste his models se we don't know if he was taking this in account.

But even if this usage error isn't present in user's models there is a Django bug (Category.verbose_name_plural values shown are <django.utils.functional.proxy... as above and they evaluate to "Categorys" in the admin). IMHO it should treat verbose_name_plural in a way consistent with verbose_name`. I'm changing the component field of this ticket accordingly.

Changed 5 years ago by ramiro

comment:7 Changed 5 years ago by ramiro

  • Has patch set

comment:8 follow-up: Changed 5 years ago by Beetle_B

  • Owner changed from nobody to Beetle_B
  • Status changed from new to assigned

OP here.

Here's how I remember it (I have the code, but it may have been modified since then):

There's one (perhaps important) difference:

class CategoryBase(models.Model):
    class Meta:
        abstract = True
        verbose_name_plural = u'CategoryBase verbose_name_plural'

class CategoryMarkup(CategoryBase):
    class Meta(CategoryBase.Meta):
        abstract = True

class Category(CategoryMarkup):
    title = models.CharField(max_length=100)

The difference is that the intermediate abstract model (CategoryMarkup)'s Meta is subclassing the Meta of the parent. This was as per the docs...

In any case, your examples are illuminating. So normally, verbose_name_plural is inherited from an abstract base class that defines it?

The point of this bug report was that the docs should state explicitly what is or is not inherited. Your examples have, in a sense, confused me, and is suggesting an inconsistent behavior (in which case a separate ticket needs to be opened). On the one hand, it is inherited (if the immediate parent defines it). On the other, it is not (even when the intermediate abstract class's Meta is inheriting directly from the parent's Meta).

comment:9 Changed 5 years ago by Beetle_B

  • Owner Beetle_B deleted
  • Status changed from assigned to new

comment:10 Changed 5 years ago by Beetle_B

  • Owner set to Beetle_B
  • Status changed from new to assigned

comment:11 Changed 5 years ago by Beetle_B

  • Owner Beetle_B deleted
  • Status changed from assigned to new

I don't know what I'm doing "wrong", but somehow this keeps getting assigned to me. Trying to reset...

comment:12 in reply to: ↑ 8 Changed 5 years ago by ramiro

Replying to Beetle_B:

OP here.

Here's how I remember it (I have the code, but it may have been modified since then):
...
The difference is that the intermediate abstract model (CategoryMarkup)'s Meta is subclassing the Meta of the parent. This was as per the docs...

Correct.

In any case, your examples are illuminating. So normally, verbose_name_plural is inherited from an abstract base class that defines it?

Correct.

The point of this bug report was that the docs should state explicitly what is or is not inherited.

Oops, sorry. From the tracking of the ticket history I had understood this ticket was initially opened to report the mis-behavior and later changed to be about the docs, that's why I changed is component to ORM.

Your examples have, in a sense, confused me, and is suggesting an inconsistent behavior (in which case a separate ticket needs to be opened). On the one hand, it is inherited (if the immediate parent defines it). On the other, it is not (even when the intermediate abstract class's Meta is inheriting directly from the parent's Meta).

Correct, and the patch solves it, the regression test case added shows this with an very similar example: It fails without the patch and works after applying it.

Anyway, if the patch (or another solution) is committed to solve the problem that Django is treating the verbose_name_plural in a way different to verbose_name when abstract model inheritance is involved then there won't be any special cases to document (apart for the cases already covered: abstract is not inherited and db_table is but it won't make any sense). That is, all the meta model options are inherited just like in the non-abstract scenario and IMHO there won't be any need to explicitely list them.

comment:13 Changed 4 years ago by ramiro

  • Owner set to ramiro
  • Status changed from new to assigned

comment:14 Changed 4 years ago by bronger

  • Cc bronger@… added

comment:15 Changed 3 years ago by ramiro

  • Resolution set to fixed
  • Status changed from assigned to closed

(In [14588]) Fixed #11369 -- Corrected verbose_name_plural model Meta option to be consistent with verbose_name when using abstract model inheritance. Thanks Beetle_B for the report.

comment:16 Changed 3 years ago by ramiro

(In [14589]) [1.2.X] Fixed #11369 -- Corrected verbose_name_plural model Meta option to be consistent with verbose_name when using abstract model inheritance. Thanks Beetle_B for the report.

Backport of [14588] from trunk

comment:17 Changed 3 years ago by bronger

I exterience the very same problem with "ordering" instead of "verbose_name_plural". Is this related?

Add Comment

Modify Ticket

Change Properties
<Author field>
Action
as closed
as The resolution will be set. Next status will be 'closed'
The resolution will be deleted. Next status will be 'new'
Author


E-mail address and user name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.