Link Django models together via GenericKey?

Question:

i have the following models:

class Team(models.Model):
    users = models.ManyToManyField("User")
    
class User(AbstractUser):
     ...
    
class Subscription(models.Model):
    team = models.ForeignKey("Team", on_delete=models.CASCADE)
    name = models.CharField(max_length=64)
    
class Package(models.Model):
    name = models.CharField(max_length=64) # packageA, packageB
    max_activation_number = models.PositiveIntegerField(default=1)
    
class Activation(models.Model):
    subscription = models.ForeignKey("Subscription", on_delete=models.CASCADE)
    package = models.ForeignKey("Package", on_delete=models.CASCADE)
    created = models.DatetimeField()
    
class PackageA(models.Model):
    ... 
    
    
class PackageB(models.Model):
    ... 
    

A team has one subscription and it can activate one or more package and the same package could be activated more than one time. (number of times specified with "max_ativation_number")

Example:

A team has a subscription called Suite and the available packages are: EmailAccount and Calendar
The team choose to activate 3 EmailAccount and 2 Calendar (packages are not tied to each other)

For that reason the team could activate the same package more times.

For every activation i need to create a new instance on PackageA or PackageB (it depends on the choice a team made) and then i should "link" to that instance somehow.

Should i use GenericKey field inside Activation model? I not only need the name of the chosen package but I also need to figure out which instance.

Asked By: Dail

||

Answers:

This can be solved in multiple ways as you want to create a new package instance one solution is using Django signals to create the new instance of packages by using post_save signal from django.db.models.signals import post_save.

from django.db.models.signals import post_save

@receiver(post_save, sender= Activation)
def post_activation_save(sender, instance, **kwargs):
    if kwargs.get('created'):
        # create new package instance
        ....
Answered By: Nitin Tiwari

As far as I understand, you are trying to make a Many-To-Many relationship actually https://docs.djangoproject.com/en/dev/topics/db/models/#extra-fields-on-many-to-many-relationships:

enter image description here


class Team(models.Model):
    users = models.ManyToManyField("User")
    
class User(AbstractUser):
     ...
    
class Subscription(models.Model):
    team = models.ForeignKey("Team", on_delete=models.CASCADE)
    name = models.CharField(max_length=64)
    packages = models.ManyToManyField(Package, through=Activation)
    
class Package(models.Model):
    name = models.CharField(max_length=64) # packageA, packageB
    
class Activation(models.Model):
    subscription = models.ForeignKey("Subscription", on_delete=models.CASCADE)
    package = models.ForeignKey("Package", on_delete=models.CASCADE)
    max_activation_number = models.PositiveIntegerField(default=1)
    created = models.DatetimeField()

So in order to create Subscription Suite with 3 EmailAccount and 2 Calendar

suite_subscription = Subscription.objects.create(name='Suite', team=team_1)
email_package = Package.objects.create(name='EmailAccount')
calendar_package = Package.objects.create(name='Calendar')
suite_subscription.activation_set.create(package=email_package, max_activation_number=3)
suite_subscription.activation_set.create(package=calendar_package, max_activation_number=2)

Now you have suite_subscription with 3 max email packages and 2 max calendar packages. Similarly to this, you can create extra packages and subscriptions…

And you can add as many custom attributes as you want to that "pivot" Activation table.

Answered By: Đào Minh Hạt