В моей модели есть метод, который я хотел бы вызвать в своих представлениях. Однако я получаю NameError, что эта функция не определена (я импортировал все модели в свои представления, и все миграции обновлены). В прошлом он работал с другими функциями.

Вот моя модель:

class Song(models.Model):
    """
    fields
    """

    def lyrics_as_list(self):
       return self.lyrics_ru.split()

    def sorted_strings(self, strings, locale=None):
       if locale is None:
           return sorted(strings)
       collator = icu.Collator.createInstance(icu.Locale(locale))
       return sorted(strings, key=collator.getSortKey)

И, на мой взгляд, соответствующая часть, в которой я хочу ее использовать:

lyrics_list = models.Song.objects.get(pk=self.kwargs['pk']).lyrics_as_list() #this is also a method on my model, and it does work
lyrics_sorted = sorted_strings(set(lyrics_list, "ru_RU.UTF8")) #but this one gives me an error

Ошибка: name 'sorted_strings' is not defined

Когда я перемещаю метод в свои представления, он работает. Но мне приходится использовать это в нескольких представлениях, поэтому я пытаюсь следовать принципу DRY, и было бы здорово заставить его работать.

Изменить - для чего предназначена функция sorted_strings: Моя модель Song содержит тексты песен. Я показываю все слова в тексте в таблице, но я хочу показать ее в алфавитном порядке. Чтобы иметь возможность сортировать русские слова, мне нужно было добавить эту функцию.

0
MeL 30 Июл 2020 в 12:52

2 ответа

Лучший ответ

Метод sorted strings, определенный в классе Song:

class Song(models.Model):
    """
    fields
    """

    def sorted_strings(self, strings, locale=None):
        if locale is None:
            return sorted(strings)
        collator = icu.Collator.createInstance(icu.Locale(locale))
        return sorted(strings, key=collator.getSortKey)

Нельзя так называть:

sorted_strings(strings, locale)

Это, очевидно, приводит к NameError. Это метод, поэтому вам нужно вызвать его для объекта как экземпляра этого класса.

У вас может возникнуть соблазн попробовать это:

Song.sorted_strigns(strings, locale)

Но это не сработает. Это приведет к отсутствию 1 обязательного позиционного аргумента. То есть вы должны предоставить self. Вы не можете вызвать это прямо в классе.

Если вы хорошо изучите этот метод, он не будет выполнять никаких действий с объектом. Аргумент self не используется. Вы хотели бы вызвать его без создания экземпляра объекта, а непосредственно в классе. Поэтому вы можете использовать декоратор @staticmethod:

@staticmethod
def sorted_strings(strings, locale=None):
    if locale is None:
        return sorted(strings)
    collator = icu.Collator.createInstance(icu.Locale(locale))
    return sorted(strings, key=collator.getSortKey)

Обратите внимание, что статическому методу не нужно передавать аргумент self.

Теперь ваш код должен работать так:

lyrics_list = Song.objects.get(pk=self.kwargs['pk']).lyrics_as_list()
lyrics_sorted = Song.sorted_strings(set(lyrics_list), "ru_RU.UTF8")

Также в вашем примере кода у вас есть ошибка со скобками во второй строке.

Помимо статических методов, существуют также методы класса, определенные с помощью декоратора @classmethod. Для этого я бы использовал статический метод, но если у кого-то есть возражения, я готов учиться.

Статические методы не очень распространены в Python и многими не одобряются.
Тем не менее хорошо знать, что они существуют и как работают.

2
cezar 30 Июл 2020 в 11:10
lyrics_list = models.Song.objects.get(pk=self.kwargs['pk']).lyrics_as_list()
lyrics_sorted = models.Song.objects.sorted_strings(set(lyrics_list), "ru_RU.UTF8")

Метод менеджера может быть вызван только с Model.objects

0
Pruthvi Barot 30 Июл 2020 в 11:34