Milano
Milano

Reputation: 18745

Can't access instancemethod attribute?

Is it possible to somehow access variable or attribute of a method?

In Django (but problem isn't probably sticked to Django):

class Product(models.Model):
    ...
    STATISTIC = ['get_last_average_price',]

    def statistic(self):
        """ returns a list of methods with names in list STATISTIC """
        lst = []
        for method_str in Product.STATISTIC:
            method = getattr(self, method_str)
            lst.append(method)
        return lst

    def get_last_average_price(self):
        self.get_last_average_price.label = 'Last AVG price'
        self.get_last_average_price.xml_tag = '<last_average_price>'
        self.get_last_average_price.xml_close_tag = '</last_average_price>'
        prices = [x.get_last_scan().price for x in self.get_occurences() if x.get_last_scan() and x.get_last_scan().price]
        return round(decimal.Decimal(sum(prices)/len(prices)),2) if prices else None

Now I want to generate an XML where this (iteration where method is get_last_average_price:

{{ method.xml_tag }}{{ method }}{{ method.xml_close_tag }}

should produce:

<last_average_price>1548.48</last_average_price>

The price ( {{ method }} ) works correctly. The problem is with tags.

It returns error:

Exception Value: 'instancemethod' object has no attribute 'label'

<products>
    {% for product in products %}
        <product>
            <code>{{ product.code }}</code>
            <name>{{ product.name }}</name>
            <statistics>
                {% for method in product.statistic %}
                    {{ method.xml_tag }}{{ method }}{{ method.xml_close_tag }}
                {% endfor %}
            </statistics>
        </product>
    {% endfor %}
</products>

Do you know what to do to make it work? Or some workaround?

Upvotes: 1

Views: 63

Answers (2)

e4c5
e4c5

Reputation: 53774

The problem is right here:

def get_last_average_price(self):
    self.get_last_average_price.label = 'Last AVG price'

here self.get_last_average_price references an instance method, you are not calling it. To call it would be to code it as self.get_last_average_price() unfortunately for you that wouldn't work either because it would lead to an infinite recursion. I would say the data structure needs to be changed completely.

def get_last_average_price(self):
        prices = [x.get_last_scan().price for x in self.get_occurences() if x.get_last_scan() and x.get_last_scan().price]
        value = round(decimal.Decimal(sum(prices)/len(prices)),2) if prices else None
        return {"label": 'Last AVG price', "xml_tag": 'last_average_price', 'value': value }

Note that you don't really need xml_close_tag. because then the tag can be derived (note that I have removed the < and > leaving them to be appended at the next stage.

Upvotes: 1

lucasnadalutti
lucasnadalutti

Reputation: 5948

Why not return the full XML row?

def get_last_average_price(self):
    return '<last_average_price>{}</last_average_price>'.format(value)

Then:

{% for method in product.statistic %}
    {{ method }}
{% endfor %}

Upvotes: 0

Related Questions