Search code examples
djangotastypie

Django-Tastypie self children


Trying to make api for multiple subtasks. I have the task model, that can have another task as a parent:

class Task(models.Model):
    parent_task = models.ForeignKey("Task", null=True, blank=True)
    name = models.CharField(max_length=64)

    def __unicode__ (self):
        return self.name

Now I'm trying to make tastypie resource:

class TaskResource(ModelResource):
    parent_task = fields.ForeignKey(TaskResource, 'parent_task', full=False) <-- ERROR HERE

    class Meta:
        queryset = Task.objects.all()
        resource_name = 'task'
        list_allowed_methods = ['get', 'put', 'post', 'delete']
        include_resource_uri = False

    def dehydrate(self, bundle, for_list=False):
        bundle.data["subtasks"] = "how?" <-- HOW??
        return bundle

Thanks for your time.

P.S. I need something like this:

[
    {
        "id": 1,
        "name": "Task 1",
        "subtasks": [
            {
                "id": 1,
                "name": "Task 1",
                "subtasks": [...]
            }
        ]
    },
    {
        "id": 2,
        "name": "Task 2",
        "subtasks": "how?"
    }
]

Solution

  • Almost a copy of Including child resources in a Django Tastypie API but not exactly.

    1. So your first problem is that you specify relation to self wrong. It should be just self:

      parent_task = fields.ForeignKey('self', 'parent_task', null=True, full=False)
      
    2. Secondly, notice null=True - parent could be null.

    3. Lastly, you just need to add another relation field and ask for the full details

      subtasks = fields.ToManyField('self', 'task_set', full=True)
      

      task_set is a related_name for the Task.parent_task field.

    The resulting code is:

    class TaskResource(ModelResource):
        parent_task = fields.ForeignKey('self', 'parent_task', null=True, full=False)
        subtasks = fields.ToManyField('self', 'subtasks', full=True)
    
        class Meta:
            queryset = Task.objects.all()
            resource_name = 'task'
            list_allowed_methods = ['get', 'put', 'post', 'delete']
            include_resource_uri = False
    

    And the result:

    {
        "meta": {
            "previous": null, 
            "total_count": 3,  
            "offset": 0,  
            "limit": 20, 
            "next": null
        },  
        "objects": [
            {
                "parent_task": null, 
                "subtasks": [
                    {
                        "parent_task": "/api/v1/task/1/", 
                        "subtasks": [], 
                        "id": 2,  
                        "name": "Root's Child 1"
                    },
                    {
                        "parent_task": "/api/v1/task/1/", 
                        "subtasks": [], 
                        "id": 3,  
                        "name": "Root's Child 2"
                    }
                ],
                "id": 1,  
                "name": "Root Task"
            },
            {
                "parent_task": "/api/v1/task/1/", 
                "subtasks": [], 
                "id": 2,  
                "name": "Root's Child 1"
            },
            {
                "parent_task": "/api/v1/task/1/", 
                "subtasks": [], 
                "id": 3,  
                "name": "Root's Child 2"
            }
        ]   
    }