Reputation: 1269
I have a method in my model that I would like to call in my views. However, I get a NameError
that this function is not defined (I have imported all models in my views and all migrations are up to date). It has worked for other functions in the past.
Here is my model:
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)
And in my views the relevant part where I want to use it:
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
The error: name 'sorted_strings' is not defined
When I move the method to my views, it works. But I have to use this in several views, so I am trying to follow the DRY principle, and so it would be great to get it to work.
Edit - What the sorted_strings
function is for:
My Song
model contains lyrics. I am displaying all words in the lyrics in a table, but I want to show it alphabetically. In order to be able to sort Russian words, I needed to add this function.
Upvotes: 0
Views: 156
Reputation: 2018
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")
Manager's method can only be called with Model.objects
Upvotes: 0
Reputation: 12012
The method sorted strings
as defined in the class 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)
cannot be called like this:
sorted_strings(strings, locale)
This obviously leads to a NameError
. It is a method, so you need to call it on an object as instance of that class.
You might get tempted to try this:
Song.sorted_strigns(strings, locale)
but it won't work. It will result in missing 1 required positional argument. That is you have to provide self
. You can't call it directly on the class.
If you introspect this method well, it doesn't perform any action on an object. The argument self
is not used. You'd like to call it without instantiating an object, but directly on the class. Therefore you can use the decorator @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)
Please notice how the static method doesn't need to be passed the argument self
.
Now your code should work like this:
lyrics_list = Song.objects.get(pk=self.kwargs['pk']).lyrics_as_list()
lyrics_sorted = Song.sorted_strings(set(lyrics_list), "ru_RU.UTF8")
Also in your code example you have an error with the parentheses in the second line.
Besides static methods, there are also class methods, defined using the decorator @classmethod
. For this purpose here I'd go with the static method, but if someone has an objection, I'm ready to learn.
Static methods are not very common in Python and frowned upon by many.
Nevertheless it's good to know they exist and how they work.
Upvotes: 3