Search code examples
pythondjangomongodbpostgresqlinfluxdb

django timeseries postgres beginner


I'm writing small application in django in order to learn databases and web etc. The application should display players data and record statistics over time.
To answer questions such as:
How many random battles palyer has played in last month/week/day? - graph
What players left/entered clan? - etc.

I've been searching and reading and I found these suggestions: What is a good combination of technology to use?

MongoDB, InfluxDB, PostgreSQL, RedisDB, or from packages django-timeseries, django-reversion.

I did not find my approach to be good and I probably, can anybody suggest me which database to use and how models should look like then a bit?

Critics or advice with database design is very appreciated.

Data is being downloaded from 3rd party API as jsons. Structures which are downloaded:

Player.json

{
  "501435906": { # this is PlayerID
    "last_battle_time": 1484160229,
    "statistics": {
      "all": {
        "battles": 70555
      },
      "random": {
        "battles": 67361
      }
    }
  }, # then next players continue
}

clan.json

{
  "500004323": { # clan ID
    "members": [
      {
        "account_id": 501435906, # PlayerID same as in Player.json
        "account_name": "Player1",
        "joined_at": 1447589992,
        "role": "private",
        "role_i18n": "Private"
      },]
    "name": "Full Clan Name",
    "tag": "TAG",
}

stronghold.json

{
  "500323931": { # PlayerID
    "stronghold_skirmish": null,
    "total_resources_earned": 0,
    "week_resources_earned": 0
  }, # next player follows
}

My approach: Merge data together

{
  "500004323": {
    'name': 'Full Clan Name',
    'tag': 'TAG'
    "members": {
      "500012979": {
        "account_id": "500012979",
        "account_name": "Player1",
        "joined_clan_date": 1415990768,
        "last_battle_time": 1484160229,
        "role": "Commander",
        "statistics": {
          "all": {
            "battles": 70555
          },
          "random": {
            "battles": 67361
          }
        },
        "stronghold": {
          "stronghold_skirmish": {
            "battles": 2223
          },
          "total_resources_earned": 32582,
          "week_resources_earned": 80
        }
      }, # next members
    }, # next clan
}

And import this data into following models:

class Clan(models.Model):
    """Clan model"""
    clan_id = models.IntegerField(primary_key=True)
    name = models.CharField(max_length=100)
    tag = models.CharField(max_length=5)

    @property
    def members(self):
        return Player.objects.filter(clan=self)

    def kick_player(self, player):
        player.leave_clan()

class PlayerLeaversManager(models.Manager):

    def leave_clan(self, players):
        """Take list of players and remove them from their clan
        :param players:
        """
        for player in players:
            player.leave_clan()

class Player(models.Model):
    """Player model"""
    account_id = models.IntegerField(primary_key=True)
    access_token = models.TextField(blank=True,
                                    null=True)
    access_token_expires_at = models.CharField(max_length=10,
                                               blank=True,
                                               null=True)
    account_name = models.CharField(max_length=250)


    clan = models.ForeignKey('Clan',
                               on_delete=models.CASCADE,
                               blank=True,
                               null=True,
                            related_name='current_clan')

    previous_clan = models.ForeignKey('Clan',
                               on_delete=models.CASCADE,
                               blank=True,
                               null=True,
                            related_name='previous_clan')

    # objects = models.Manager()
    objects = PlayerLeaversManager()


    def __str__(self):
        return '{0} - {1}'.format(self.account_name, self.account_id)

    def get_absolute_url(self):
        return reverse('wot:player_detail',
                       args=[self.account_name])

    def leave_clan(self):
        self.previous_clan = self.clan
        self.clan = None
        self.save()

class PlayerData(models.Model):
    """Players data daily tracked"""
    created = models.DateTimeField(auto_now_add=True)

    player = models.ForeignKey('Player',
                               on_delete=models.CASCADE,
                               null=True,
                               blank=True
                               )

    joined_clan_date = models.DateTimeField(blank=True,
                                             null=True)

    role_in_clan = models.CharField(max_length=250,
                                    blank=True,
                                    null=True)

    battles_on_random = models.IntegerField(blank=True,
                                               null=True)
    battles_all = models.IntegerField(blank=True,
                                      null=True)
    battles_stronghold = models.IntegerField(blank=True,
                                             null=True)

    tank = models.ManyToManyField('Vehicle',
                                    related_name='tanks',
                                    blank=True,)

    last_battle_time = models.DateTimeField(blank=True,
                                             null=True)
    # stronghold stats
    total_resources_earned = models.IntegerField(blank=True, null=True)

    week_resources_earned = models.IntegerField(blank=True, null=True)

Whole code can be found on my github https://github.com/1oglop1/anv_wot Thank you for all suggestions.


Solution

  • After some more research and asking at python FB community I will try following: 1) Normalize the models 2) Use PostgreSQL as backend.