Valery
Valery

Reputation: 332

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

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"

Upvotes: 5

Views: 728

Answers (3)

blondelg
blondelg

Reputation: 986

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.

Upvotes: 0

DKmb
DKmb

Reputation: 116

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)

Upvotes: 7

Nathan Horrigan
Nathan Horrigan

Reputation: 813

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

Upvotes: 7

Related Questions