django template system, calling a function inside a model

PythonDjangoDjango ModelsDjango Templates

Python Problem Overview


I want to call a function from my model at a template such as:

class ChannelStatus(models.Model):
 ..............................
 ..............................

	def get_related_deltas(self,epk):
		mystring = ""
		if not self.get_error_code_delta(epk):
			return mystring
		else:
			for i in self.get_listof_outage():
				item = i.error_code.all()
				for x in item:
					if epk == x.id:
						mystring= mystring +" "+str(i.delta())
		return mystring			

And when I want to call this from the template: assume while rendering, I pass channel_status_list as

channel_status_list = ChannelStatus.objects.all()

{% for i in channel_status_list %}
  {{ i.get_related_deltas(3) }}
{% endfor %}

This doesn't work, I am able to call a function that consumes nothing, but couln't find what to do if it has parameter(s)

Cheers

Python Solutions


Solution 1 - Python

You can't call a function with parameters from the template. You can only do this in the view. Alternatively you could write a custom template filter, which might look like this:

@register.filter
def related_deltas(obj, epk):
    return obj.get_related_deltas(epk)

So now you can do this in the template:

{% for i in channel_status_list %}
  {{ i|related_deltas:3 }}
{% endfor %}

Solution 2 - Python

If the method doesn't require any arguments, you can use the @property decorator and access it normally in the template.

class ChannelStatus(models.Model):
    ...
    @property
    def function_you_want_as_property(self):
	    mystring = ""
    	...

Solution 3 - Python

For > 1 argument, use simple tags:

@register.simple_tag
def related_deltas(obj, epk, second_arg):
    return obj.get_related_deltas(epk, second_arg)

Template:

{% for i in channel_status_list %}
  {% related_deltas i 3 4 %}
{% endfor %}

(Note the change of syntax from {{ to {%)

Can take positional parameters (e.g. related_deltas i 3 second_arg=4 debug=true).

Solution 4 - Python

If you find that there are too many properties running around everywhere or you have a template filter for every other method that you write, another solution was suggested on IRC thanks @FunkyBob. It's a little well, erm, funky but it is nice in certain cases.

  class MethodProxy(object):
        """For consolidating into 1 method the calling of methods with various single args
        (suitable dictionary keys)
    
        class MyModel(models.Model):
            ...
    
            def magic(self, value):
                # Free the ponies
    
            def thing(self):
                return MethodProxy(self.magic)
    
        # Usage
        >>> m = MyModel()
        ...
        >>> m.thing['value'] == m.magic('value')

        # template
        {{ m.thing.value }}
    
        """
    
        def __init__(self, method):
            self.method = method
        def __getitem__(self, key):
            return self.method(key)

Solution 5 - Python

Another option is to define a property. See http://adam.gomaa.us/blog/2008/aug/11/the-python-property-builtin/ .

You write your function that can do pretty much anything you want. You make it a read only property. You call the property from the template.

Et voilĂ  !!!!

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestioncribView Question on Stackoverflow
Solution 1 - PythonDaniel RosemanView Answer on Stackoverflow
Solution 2 - PythonsabalabaView Answer on Stackoverflow
Solution 3 - PythonlaffusteView Answer on Stackoverflow
Solution 4 - PythonSkylar SavelandView Answer on Stackoverflow
Solution 5 - PythonArnaud SahuguetView Answer on Stackoverflow