rouge8
rouge8

Reputation: 463

Nested ToManyFields in django-tastypie

I have two ModelResources, Attack and Packet, related by a ManyToManyField.

This tends to show up with Packet.attacks containing 1-3 attacks, and Attack.packets containing hundreds of packets.

The way I've been planning to do this is this: each AttackResource has an Attack.packets attribute that is a link to a the queryset containing Attack.packets and where the queryset is nested in AttackResource.

i.e.:

/api/attack/1/ # contains attribute with URL of /api/attack/1/packets/
/api/attack/1/packets/ # contains all packets where attack with id=1 is in Packet.attacks

How can I do this?

I've tried following cyberdelia's gist to have nested resources, but going to /api/attack/1/packets/ doesn't actually contain packets where attack.id is in packet.attacks.

My ModelResource class is identical to the gist, and then my other resources are:

class AttackResource(ModelResource):
    packets = fields.ToManyField('honeywall.api.PacketResource', 'packets', 'attack')

    class Meta:
        queryset = Attack.objects.all()
        resource_name = 'attack'

and

class PacketResource(ModelResource):
    attacks = fields.ToManyField('honeywall.api.AttackResource', 'attacks', 'packet')

    class Meta:
        queryset = Packet.objects.all()
        resource_name = 'packet'
        filtering = {
            'attacks': ALL_WITH_RELATIONS,
        }

Upvotes: 1

Views: 1344

Answers (2)

Daniel
Daniel

Reputation: 3501

Add this to your AttackResource:

def prepend_urls(self):
    return [
        url(r"^(?P<resource_name>%s)/(?P<pk>\w[\w/-]*)/packets%s$" % (self._meta.resource_name, trailing_slash()), self.wrap_view('get_attacks'), name="api_get_attacks"),
    ]

def get_attacks(self, request, **kwargs):
    try:
        bundle = self.build_bundle(data={'pk': kwargs['pk']}, request=request)
        obj = self.cached_obj_get(bundle=bundle, **self.remove_api_resource_names(kwargs))
    except ObjectDoesNotExist:
        return HttpGone()
    except MultipleObjectsReturned:
        return HttpMultipleChoices("More than one resource is found at this URI.")

    attack_resource = AttackResource()
    return attack_resource.get_detail(request, id=obj.pk)

Upvotes: 1

Aldarund
Aldarund

Reputation: 17621

You can create nested resources by overriding a override_urls function in your resources. One way to do this can be found in tastypie documentation. It`s based on creation of a custom function in your resource that will get all children, and you need to write this for every resource.

If this is not work well for you then there other way to do it.A more generic way and it will work for all nested resources without writing any additional functions. It can be found on this gist.

Upvotes: 0

Related Questions