How to create copy of model instance and related objects with values?

Hello! I hope this is an appropriate question for this forum.

I have a simple relation of three models. Task, which has a foreign key to a User, and some information about the task, a TaskList, which is a list of ask objects, and Project, which has (for the sake of this question ) one TaskList.

This relationship seems correct, but I’m stuck on how to accomplish my real goal, which is to make a copy of a TaskList for each new Project, sort of like a template. In each Project instance, each instance of Task in the TaskList must be able to be associated to a different user. As I have this modeled now, I can create many projects, but each project references the same instance of TaskList, and thus the same instances of Task. When i change the assigned person for the Tasks in TaskList(id=1) the assignment changes in TaskList(id=2).

I’m looking less for “this is the code to do that” and more for the pattern/thinking to solve this problem. I believe that what i need to do is to copy the TaskList and all related Task objects when i create a new Project, but I dont know how to do that! Should I be overriding save(), and how do i copy the related Task Objects and their values to the new copy of the TaskList? Any pointers, or help with how to describe the problem above would be really appreciated! as I have it now. Should I even be using a M2M relation on Project?

from django.contrib.auth import get_user_model
from django.db import models

class Task(models.Model):
    name = models.CharField()
    responsible_people = models.ManyToManyField(get_user_model())
    process = models.TextField(help_text='the steps to do the task')

    def __str__(self):
        return f"{}"

class TaskList(models.Model):
    name = models.CharField()
    tasks = models.ManyToManyField(Task)

    def __str__(self):
        return f"{}"

class Project(models.Model):
    name = models.CharField()
    description = models.TextField()
    onboarding_tasks = models.ManyToManyField(TaskList)

    def __str__(self):
        return f"{}"

Questions for you - you are talking about copying TaskList for a new Project, but you have a M2M relationship between Project and TaskList.

Is the real situation:
You have common task lists shared among all projects? Or is what you have a “standard” or “prototype” task list that gets assigned to each project? (And likewise for Task relative to each TaskList)

Do you have multiple TaskList for each Project needing to be managed individually as a TaskList? Or are you just using TaskList as a “container” for a set of Task?

Traditionally, the more “common” or “typical” model I’ve seen for situations similar to this is that Task has an FK to Project, where the Task has the various metrics associated with it.

In addition Task, then there are also separate and distinct TaskList and “TaskTemplate” tables, where the TaskTemplate is the base information for a task without the metrics and has an FK to TaskList.
People can then assign a TaskList to a project, resulting in the TaskTemplate being used to copy the set of TaskTemplate for that TaskList to create a new set of Task assigned to Project.
(Note: This type of assignment can be done when a Project is being created if there’s some type of widget allowing for the selection of the appropriate TaskList(s) on that same page.)

If the TaskList is itself a “measurable” and “traceable” element, then it is a two-level copy with the same idea. You end up with a TaskListTemplate in addition to the TaskTemplate - both of which needing to be copied to the TaskList and Task tables when necessary.

(Note: These basic concepts still work even if you’re talking about managing multi-million-dollar construction projects with WBS (Work-Breakdown-Structure) trees going 8-10 levels deep. However, the precise implementations will change.)

This type of structure also facilitates the ability to create processes allowing a TaskList to be modified, and being able to selectively identify which Project should be affected by those changes.

1 Like

Thank you Ken! This is precisely what I was after. To answer your question about the nature of the TaskList , it is the second option you describe: a TaskList is a prototype of the list of tasks for a given project.

The approach you suggest where I would create both the Task and TaskTemplate, and TaskList and TaskList Templates is the tip/cognitive leap I needed!

Thank you!