3

I am trying create a dynamic function that dynamically add attributes to easily make values accessible in a jinja template.

This code is working but it is static.

# Used to display a cart summary of items that have been pledged.
products_in_cart = Cart.query.filter(Cart.campaign_id == campaign_id).all()
# total_cart_quantity(products_in_cart, "quantity", "quantity_total")
for item in products_in_cart:
    item.quantity_total = 0 #Adding the attribute quantity_total

    for item_loop2 in products_in_cart:
        if item.user_id == item_loop2.user_id:
            item.quantity_total = item.quantity_total + item_loop2.quantity

# Remove duplicate objects based on user_id attribute.
new_set = set()
new_list = []
for obj in products_in_cart:
    if obj.user_id not in new_set:
        new_list.append(obj)
        new_set.add(obj.user_id)

products_in_cart = new_list

I would like to make the added attribute names dynamic based upon arguments passed into the function so I may use elsewhere. Dot notation wont work because I need a variable to name the attribute. obj[variable_attrbute] errors. setattr() does nothing.

def total_cart_quantity(cart_objects, sum_attribute, new_attribute):
'''
    From cart get the total of a particular quantity and add it to a new attribute.
    cart_objects = the queried cart_objects.
    sum_attribute = the attribute to be summed.
    new_attribute = the string of the new attribute name
'''
for item in cart_objects:
    # Two different attempts to add an attribute. 
    # setattr will just not add the attribute
    setattr(item, sum_attribute, new_attribute) # this will do nothing
    # item[new_attribute] = 0 # this will error

    for item_loop2 in cart_objects:
        if item.user_id == item_loop2.user_id:
            item[new_attribute] = item[new_attribute] + item_loop2[sum_attribute]

# Remove duplicate objects based on user_id attribute.
new_set = set()
new_list = []
for obj in cart_objects:
    if obj.user_id not in new_set:
        new_list.append(obj)
        new_set.add(obj.user_id)

products_in_cart = new_list

return products_in_cart

How does one dynamically add attribute names and values?

jdubtd10
  • 105
  • 1
  • 2
  • 9
  • Can the answers at http://stackoverflow.com/questions/4443301/python-adding-fields-to-objects-dynamically and http://stackoverflow.com/questions/2827623/python-create-object-and-add-attributes-to-it do what you need? This question has been asked and answered more than a few times already on SO. –  Jul 24 '15 at 22:42
  • Why isn't setattr working? Just reading your comments in the code – Pynchia Jul 24 '15 at 23:43
  • Can use @property decorator to make methods behave like attributes – reptilicus Jul 25 '15 at 18:40

2 Answers2

5

You're using getattr and setattr in a wrong way. The actual signatures are following:

variable = object.field  ~  variable = getattr(object, 'field' [, default])
object.field = value     ~  setattr(object, 'field', value)
Alexander Lutsenko
  • 2,130
  • 8
  • 14
0

You can also use the property decorator to do something like this. For instance:

class CartItem(Base):

   cart_id = Column(ForeignKey("cart.id", primary_key=True)
   item_id = Column(ForeignKey("item.id", primary_key=True)


class Cart(Base):

    id = Column(Integer, primary_key=True)
    items = relationship("CartItems")

    @property
    def number_of_items(self):
       return len(self.items) #or whatever logic you need here
reptilicus
  • 10,290
  • 6
  • 55
  • 79