Why MyPage._meta.get_field("title").verbose_name changes all the titles' labe in Wagtail?
Asked Answered
S

3

5

I have a few apps in my Wagtail project and one of them is "news" which contains News(Page). I want to overwrite the title's label "title" to "headline" in the admin.

News._meta.get_field("title").verbose_name = "Headline"

As a result, I get all the titles' label "Headline" in all apps and pages. Why I've got this strange effect?

UPDATE:

# news/models.py

class NewsDetails(Page):
    template = "news/news_details.html"

    news_text = RichTextField(features=['h2', 'h3', 'bold', 'italic', 'link', 'ol', 'ul',])
    news_image = models.ForeignKey(
        "wagtailimages.Image",
        null=True,
        blank=False,
        on_delete=models.SET_NULL,
    )

    content_panels = Page.content_panels + [
        ImageChooserPanel("news_image"),
        FieldPanel("news_text")
    ]

    class Meta:
        verbose_name = "News"

    parent_page_types = ['news.NewsList']


NewsDetails._meta.get_field("title").verbose_name = "Headline"

Spates answered 11/12, 2019 at 16:15 Comment(2)
Why don't you change the verbose_name in the model definition itself? Also include the full code for this part of admin so we can't find the issue.Moises
I've updated. Pay attention it's Wagtail (not pure Django)Spates
C
7

Slight change to Nathan's answer, which resolves Valery's issue with verbose_name not working. Set title.label rather than title.verbose_name:

class NewsDetailsForm(WagtailAdminPageForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        # Manually edit the default form's title attributes:
        title = self.fields['title']
        title.label = "Headline"
        title.help_text = "Some headline..."

Reason is we are now dealing with a django.forms.Field rather than a django.db.models.Field. See code in django.db.models.Field.formfield():

    def formfield(self, form_class=None, choices_form_class=None, **kwargs):
        """Return a django.forms.Field instance for this field."""
        defaults = {
            'required': not self.blank,
            'label': capfirst(self.verbose_name),
            'help_text': self.help_text,
        }

        ...

        return form_class(**defaults)
Crwth answered 3/5, 2020 at 2:55 Comment(0)
C
7

The problem with this approach is that when you run a django-admin.py makemigrations command, Django will generate a migration for Wagtail core (even if it's installed via pip).

To avoid this, it's better to use a custom base_form_class in your NewsDetails model. This approach works for changing other properties such as help_text as well:

from wagtail.admin.forms import WagtailAdminPageForm

class NewsDetailsForm(WagtailAdminPageForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        # Manually edit the default form's title attributes:
        title = self.fields['title']
        title.verbose_name="Headline"
        title.help_text="Some headline..."


class NewsDetails(Page):
    template = "news/news_details.html"

    news_text = RichTextField(features=['h2', 'h3', 'bold', 'italic', 'link', 'ol', 'ul',])
    news_image = models.ForeignKey(
        "wagtailimages.Image",
        null=True,
        blank=False,
        on_delete=models.SET_NULL,
    )

    content_panels = Page.content_panels + [
        ImageChooserPanel("news_image"),
        FieldPanel("news_text")
    ]

    class Meta:
        verbose_name = "News"

    parent_page_types = ['news.NewsList']

    # Important line below:
    base_form_class = NewsDetailsForm
Creuse answered 13/12, 2019 at 14:9 Comment(1)
Thank you, it helped but partly... I don't know why but it works only for help_text 🤷‍♂️Spates
C
7

Slight change to Nathan's answer, which resolves Valery's issue with verbose_name not working. Set title.label rather than title.verbose_name:

class NewsDetailsForm(WagtailAdminPageForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        # Manually edit the default form's title attributes:
        title = self.fields['title']
        title.label = "Headline"
        title.help_text = "Some headline..."

Reason is we are now dealing with a django.forms.Field rather than a django.db.models.Field. See code in django.db.models.Field.formfield():

    def formfield(self, form_class=None, choices_form_class=None, **kwargs):
        """Return a django.forms.Field instance for this field."""
        defaults = {
            'required': not self.blank,
            'label': capfirst(self.verbose_name),
            'help_text': self.help_text,
        }

        ...

        return form_class(**defaults)
Crwth answered 3/5, 2020 at 2:55 Comment(0)
P
0

Maybe by adding a init method within the model class as follow:

class NewsDetails(Page):
...
    def __init__(self, *args, **kwargs):
        super(NewsDetails, self).__init__(*args, **kwargs)
        self._meta.get_field('title').verbose_name = 'Headline'
...

I think this has to be done for all classes defined in the model otherwise, subclassed classes from Page will have the last updated label. For instance, here, if I subclass Page to create a new class, I will see Headline as title label whereas I should see the default label Title.

Plumy answered 18/7, 2020 at 21:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.