0

I have a Django model like this:

class Competitor(models.Model):
  """
  Competitor model object
  """
  name = models.CharField(max_length=20)
  easy = ArrayField(models.PositiveSmallIntegerField(), size=9, null=True, blank=True, verbose_name='Easy Mode')
  hard = ArrayField(models.PositiveSmallIntegerField(), size=9, null=True, blank=True, verbose_name='Hard Mode')
  tematicas = ArrayField(models.PositiveSmallIntegerField(), size=7, null=True, blank=True, verbose_name='Tematicas')
  random_score = ArrayField(models.PositiveSmallIntegerField(), size=9, null=True, blank=True, verbose_name='Random Mode')
  min1 = ArrayField(models.PositiveSmallIntegerField(), size=9, null=True, blank=True, verbose_name='minuto 1')
  min2 = ArrayField(models.PositiveSmallIntegerField(), size=9, null=True, blank=True, verbose_name='minuto 2')
  deluxe = ArrayField(models.PositiveSmallIntegerField(), size=14, null=True, blank=True, verbose_name='Deluxe')
  replica = ArrayField(models.PositiveSmallIntegerField(), size=9, null=True, blank=True, verbose_name='Replica')

And I want to be able to access the properties with index, therefore, if I write competitor[0], it should return the value of name.

I have looked, and according to this question, I have to "Implement both __iter__() and __getitem__() et alia methods." But I have no idea what to do inside this methods.

Anyone knows how to do this?

Joaquin
  • 91
  • 1
  • 14

3 Answers3

0

If you're planning only to get items, you must override __getitem__.

class Competitor(models.Model):
  """
  Competitor model object
  """
  name = models.CharField(max_length=20)
  easy = ArrayField(models.PositiveSmallIntegerField(), size=9, null=True, blank=True, verbose_name='Easy Mode')
  hard = ArrayField(models.PositiveSmallIntegerField(), size=9, null=True, blank=True, verbose_name='Hard Mode')
  tematicas = ArrayField(models.PositiveSmallIntegerField(), size=7, null=True, blank=True, verbose_name='Tematicas')
  random_score = ArrayField(models.PositiveSmallIntegerField(), size=9, null=True, blank=True, verbose_name='Random Mode')
  min1 = ArrayField(models.PositiveSmallIntegerField(), size=9, null=True, blank=True, verbose_name='minuto 1')
  min2 = ArrayField(models.PositiveSmallIntegerField(), size=9, null=True, blank=True, verbose_name='minuto 2')
  deluxe = ArrayField(models.PositiveSmallIntegerField(), size=14, null=True, blank=True, verbose_name='Deluxe')
  replica = ArrayField(models.PositiveSmallIntegerField(), size=9, null=True, blank=True, verbose_name='Replica')

  def __getitem__(self, key):
      if key == 0:
          return self.nome
      elif key == 1:
          return self.easy
      ...
      elif key == 8:
          return self.replica

An easy way is to keep track of the properties using a list:

class Competitor(models.Model):
  """
  Competitor model object
  """
  name = models.CharField(max_length=20)
  easy = ArrayField(models.PositiveSmallIntegerField(), size=9, null=True, blank=True, verbose_name='Easy Mode')
  hard = ArrayField(models.PositiveSmallIntegerField(), size=9, null=True, blank=True, verbose_name='Hard Mode')
  tematicas = ArrayField(models.PositiveSmallIntegerField(), size=7, null=True, blank=True, verbose_name='Tematicas')
  random_score = ArrayField(models.PositiveSmallIntegerField(), size=9, null=True, blank=True, verbose_name='Random Mode')
  min1 = ArrayField(models.PositiveSmallIntegerField(), size=9, null=True, blank=True, verbose_name='minuto 1')
  min2 = ArrayField(models.PositiveSmallIntegerField(), size=9, null=True, blank=True, verbose_name='minuto 2')
  deluxe = ArrayField(models.PositiveSmallIntegerField(), size=14, null=True, blank=True, verbose_name='Deluxe')
  replica = ArrayField(models.PositiveSmallIntegerField(), size=9, null=True, blank=True, verbose_name='Replica')
  _list = [name, easy, hard, tematicas, random_score, min1, min2, deluxe, replica]

  def __getitem__(self, key):
      return self._list[key]

In order to fully implemented the subscript notation ([]), you will need to implement __setitem__ and __delitem__ too.

  def __setitem__(self, index, value):
      self._list[index] = value
  • I am planning to get **and** modify items. So like `comp[0] = 'hello'`. If I want to do this, I have to implement `__setitem__`, right? If I have to, it is kindda intuitive how I should do it, but I want to make sure @julianofischer – Joaquin Apr 03 '21 at 01:23
  • I edited the answer and added a proposal of a __setitem__ method – julianofischer Apr 03 '21 at 01:28
  • It didn't work. There is no error, the value doesn't change. I noticed that if I do: `comp.__dict__['hard']`, I get `[9, 9, 9, 9, 9, 9, 9, 9, 9]`, but if I do `comp[2]`, I get `` I guess that is why changing the value using `[]` doesn't work @julianofischer – Joaquin Apr 03 '21 at 02:49
  • sorry Joaquin, my mistake. check this: `self._list[index] = value` – julianofischer Apr 03 '21 at 04:29
0

I don't know if you could make this without mapping each index. Buf if you can ensure that the order of the indexes are going to always be the same, this works for you:

class Competitor:
    def __init__(self):
        self.name = 'Leonardo'

    def __getitem__(self, key):
        if key == 0:
            return self.name

if __name__ == "__main__":
    print(Competitor()[0])  # Leonardo
Leonardo Rick
  • 680
  • 1
  • 7
  • 14
0

First of all, I want to thank @julianofischer for his answer. It taught me how to implement the methods I will implement in this answer.

First add a list of strings with the names of the fields you want to be able to access with [] as a propperty of the class, like this:

class Competitor(Model):
  """
  Competitor model object
  """
  name = CharField(max_length=20)
  easy = ArrayField(PositiveSmallIntegerField(), size=9, null=True, blank=True, verbose_name='Easy Mode')
  hard = ArrayField(PositiveSmallIntegerField(), size=9, null=True, blank=True, verbose_name='Hard Mode')
  tematicas = ArrayField(PositiveSmallIntegerField(), size=7, null=True, blank=True, verbose_name='Tematicas')
  random_score = ArrayField(PositiveSmallIntegerField(), size=9, null=True, blank=True, verbose_name='Random Mode')
  min1 = ArrayField(PositiveSmallIntegerField(), size=9, null=True, blank=True, verbose_name='minuto 1')
  min2 = ArrayField(PositiveSmallIntegerField(), size=9, null=True, blank=True, verbose_name='minuto 2')
  deluxe = ArrayField(PositiveSmallIntegerField(), size=14, null=True, blank=True, verbose_name='Deluxe')
  replica = ArrayField(PositiveSmallIntegerField(), size=9, null=True, blank=True, verbose_name='Replica')
  _list = [ 'easy', 'hard', 'tematicas', 'random_score', 'min1', 'min2', 'deluxe', 'replica' ]

Then, if you want both to get and set the values, you have to implement __getitem__ and __setitem__, like this:

def __getitem__(self, index: int):
  return self.__dict__[self._list[index]]

def __setitem__(self, index: int, value: list):
  self.__dict__[self._list[index]] = value
  self.save(update_fields=[self._list[index]])

This way, you are accesing the values of the fields with __getitem__, using .__dict__[index], and returning those, and with __setitem__, you are modifying those directly.

Joaquin
  • 91
  • 1
  • 14