Code

Opened 4 years ago

Closed 13 months ago

#14018 closed New feature (wontfix)

Introduce class_plural %-substitution placeholder for related_name of ForeignKey/ManyToManyField

Reported by: puxlit Owned by: nobody
Component: Database layer (models, ORM) Version: master
Severity: Normal Keywords: related_name, ManyToManyField, ForeignKey, abstract base class
Cc: Triage Stage: Design decision needed
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: yes
Easy pickings: no UI/UX: no

Description

Django 1.2 introduced two %-substitution placeholders, %(class)s and %(app_label)s, to work around uniqueness issues when a custom related_name for a ForeignKey or ManyToManyField defined in an abstract base class is inherited by multiple child classes.

Quoting from Django's models documentation, "It's suggested ![...] that the name of a ManyToManyField ![...] be a plural describing the set of related model objects." Given the nature of a ManyToManyField, it may be preferable to reciprocate this pluralized field naming style through related_name. By introducing a third %-substitution placeholder, %(class_plural)s, this can be accomplished.

Consider the following snippet:

class Tag(models.Model):
    slug = models.SlugField(max_length=63, unique=True)

class Post(models.Model):
    slug = models.SlugField(max_length=127, unique=True)
    tags = models.ManyToManyField(Tag, related_name='%(class_plural)s') # docs suggest related_name='%(app_label)s_%(class)s_related'
    
    class Meta:
        abstract = True

class Entry(Post):
    title = models.CharField(max_length=255)
    content = models.TextField()
    
    class Meta:
        verbose_name_plural = 'entries'

class Event(Post):
    summary = models.CharField(max_length=255)
    start_date = models.DateTimeField()

Arguably, tag.entries and tag.events are more semantic than either tag.entry_set and tag.event_set or tag.appname_entry_related and tag.appname_event_related.

Ultimately, the introduction of a %(class_plural)s %-substitution placeholder provides greater flexibility when designing models with abstract base classes and ForeignKeys or ManyToManyFields.

Attachments (1)

changes.diff (2.5 KB) - added by puxlit 4 years ago.
Code and documentation patch

Download all attachments as: .zip

Change History (10)

Changed 4 years ago by puxlit

Code and documentation patch

comment:1 follow-up: Changed 4 years ago by anonymous

  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset

I don't think using verbose_name_plural as part of the related_name is a good idea. If you have a model named SpecialEntry, the default verbose_name will be 'special entry' and verbose_name_plural will be 'special entrys'.

comment:2 Changed 4 years ago by mk

Making code (attribute names) dependent on the result of a translation is quite a stupid idea. verbose_name_plural might evaluate to other translations depending on settings.LANGUAGE_CODE, might contain special chars and whitespace and isn't suitable at all for naming class attributes (i.e. related_name).

I'm quite sure this is "wontfix" material.

comment:3 Changed 3 years ago by lrekucki

  • Patch needs improvement set
  • Triage Stage changed from Unreviewed to Design decision needed

The patch "as is" surely needs improvement. A simple solution that comes to mind would be adding name_plural to Meta. Then %(class_plural) could be replaced with that value or with class' name with an "s" added. The example above would then look something like this:

class Tag(models.Model):
    slug = models.SlugField(max_length=63, unique=True)

class Post(models.Model):
    slug = models.SlugField(max_length=127, unique=True)
    tags = models.ManyToManyField(Tag, related_name='tagged_%(class_plural)s')
    
    class Meta:
        abstract = True

class Entry(Post):
    title = models.CharField(max_length=255)
    content = models.TextField()
    
    class Meta:
        name_plural = "entries" # related attribute will be "tagged_entries"
        verbose_name_plural = _("Journal entries")        

class Event(Post):
    summary = models.CharField(max_length=255)
    start_date = models.DateTimeField()
    # related attribute will be "tagged_events"

I don't think much people care about this that much, so it's mostly a "nice to have" feature.

comment:4 in reply to: ↑ 1 Changed 3 years ago by puxlit

  • milestone changed from 1.3 to 2.0

Replying to anonymous and mk:
Good point; I hadn't considered verbose_name_plurals with multiple and/or internationalised words.

Replying to lrekucki:
That's a rather elegant solution. I agree that it's more of a nice touch than a must-have feature, but I make use of this patch in my code, and don't believe there's any harm in including it.

Thanks for all the suggestions! I'm presently working on a patch with updated documentation and a set of test cases.

comment:5 Changed 3 years ago by julien

  • Severity set to Normal
  • Type set to New feature

comment:6 Changed 3 years ago by jacob

Milestone 2.0 deleted

comment:3 Changed 2 years ago by aaugustin

  • UI/UX unset

Change UI/UX from NULL to False.

comment:4 Changed 2 years ago by aaugustin

  • Easy pickings unset

Change Easy pickings from NULL to False.

comment:5 Changed 13 months ago by aaugustin

  • Resolution set to wontfix
  • Status changed from new to closed

I'm going to close this ticket, because it proposes to hardcode one specific case, rather than provide an API to resolve the general problem.

There are several other tickets about related name with more general proposals.

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.