1

The Django documentation: Models page mentions that the default related_name for foreign keys uses the pattern f"{ModelClass.__name__.lower()}_set" (or childb_set in the specific example).

Is there a way to configure Django to convert CapWords to cap_words (instead of capwords) when creating these default related_names?

For example, take the following models:

from django.db import models

class BlogChannel(models.Model):
    name = models.CharField(max_length=100)
    tagline = models.TextField()

    def __str__(self):
        return self.name

class ArticleAuthor(models.Model):
    name = models.CharField(max_length=200)
    email = models.EmailField()

    def __str__(self):
        return self.name

class TextEntry(models.Model):
    blog_channel = models.ForeignKey(Blog, on_delete=models.CASCADE)
    headline = models.CharField(max_length=255)
    body_text = models.TextField()
    article_authors = models.ManyToManyField(Author)
    number_of_comments = models.IntegerField()
    number_of_pingbacks = models.IntegerField()
    rating = models.IntegerField()

    def __str__(self):
        return self.headline

Accessing BlogChannel records through TextEntry is intuitive:

>>> text_entry = TextEntry.objects.first()
>>> blog_channel = text_entry.blog_channel

But the reverse is not:

>>> blog_channel.text_entry_set    # should be `blog_channel.textentry_set`
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-19-0402bfca7d1f> in <module>
----> 1 blog_channel.text_entry_set

AttributeError: 'BlogChannel' object has no attribute 'text_entry_set'

Rather than modifying every foreign key field of every model to specify a related_name that uses underscores, I'm curious if there is a setting or something to effect this style change.

Bryant
  • 664
  • 2
  • 9
  • 23
  • 1
    Not exactly possible unless you go and create your own custom relation fields, which honestly would be more work to maintain the just setting the `related_name` yourself. Looking at the code [this](https://github.com/django/django/blob/8a7ac78b706797a03d26b88eddb9d1067ed35b66/django/db/models/fields/reverse_related.py#L180-L195) is where the accessor name is made. Also here is a related [question](https://stackoverflow.com/questions/66169631/is-it-possible-to-create-snake-case-related-name-from-class-interpolation-in-d) (again no answer, or similar need to override fields, etc.) – Abdul Aziz Barkat Jun 26 '21 at 13:25
  • Or you can try dabbling in metaclasses and [set the `__name__` attribute](https://stackoverflow.com/questions/49781234/setting-a-class-name-declaratively) of the class such that it in lowercase would end up being in snake case. Although I don't know if that would be recommended. – Abdul Aziz Barkat Jun 26 '21 at 13:30
  • 1
    @AbdulAzizBarkat, you are right. As you saw in '12 the way is to override `contribute_to_class` – dani herrera Jun 26 '21 at 14:22
  • Ah thanks for the help! Yeah I agree; I think this is one of the instances where it makes more sense to ignore PEP-8 for ORM relationships than to try to force it – Bryant Jun 26 '21 at 16:32

0 Answers0