pythondjangodjango-modelsdjango-jsonfield

During a django model's object creation, how to pop out and save a value from a JSON array stored in JSONField of another model's object?


I am building a website in django where users can purchase lets say activation keys for a software. Now there are a limited number of these keys, all of whome are right now stored in a json array in a JSONField of a django model named Software.

Whenever a user purchases a key, an object of PurchasedKey model is created. During this, an activation key from the list of available keys must be saved in the attribute named activation_key of this object. After saving the key it must also be deleted from the list of available keys. This is the part I am not sure how to do.

I could just manipulate the JSON to retrieve one key from the list, remove it from the list and the update and save the Software object. But is there a better way to do this with probably also a better way to store the available keys instead of using JSONField.

# models.py
from django.db import models
from django.contrib.auth.models import User

class Software(models.Model):
    name=models.CharField(max_length=20)
    available_keys=models.JSONField()

class PurchasedKey(models.Model):
    purchased_by=models.ForeignKey(User, on_delete=models.CASCADE)
    software=models.ForeignKey(Software, on_delete=models.CASCADE)
    activation_key= What to do here

Solution

  • Create a new model to hold the software keys

    SoftwareKey(models.Model):
       software_key = models.CharFiled(length=256)
       // or put the json field here
       active = models.BooleanField(default=True)
    
    Purchase(models.Model):
      purchased_by=models.ForeignKey(User, on_delete=models.CASCADE)
      software=models.ForeignKey(Software, on_delete=models.CASCADE)
      activation_key= models.ForeignKey(SoftwareKeys, on_delete=models.SET_NULL)
      active = models.BooleanField(default=True)
    

    Then in the Purchase model add some unique partial indexes(https://pypi.org/project/django-partial-index/) to restrict adding the same key again.

    Also you can make the activation_key 1-1, So activation key can be added only once.

    activation_key= models.OneToOneField(SoftwareKeys, on_delete=models.SET_NULL)
    

    Additionally you can add a new field in SoftwareKey

    purchased = models.BooleanField(default=False)
    

    and make it true if it purchased. Deleting the purchased keys from the model is not a good practice, keep it there for future reference, use some flags to know whether its purchased or not.