Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nested urls are not working with Django REST framework

url.py
router.register(r'Costumers', CostumerViewSet, base_name='costumer')
  .register(r'Agreements', AgreementViewSet, base_name='agreement', parents_query_lookups=['costumer']).
      .register(r'Programs', ProgramViewSet,base_name='programs',parents_query_lookups=['agreement']),

model.py

class Costumer(models.Model):
  company_name = models.CharField(max_length=300)
  supplier = models.ForeignKey(Supplier)

class Agreement(models.Model): 
  agreement_name = models.CharField(max_length=300)
  programs = models.ManyToManyField(Program, through='Programs_in_Agreement')
  costumer = models.ForeignKey(Costumer)

class Program(models.Model):
  program_name = models.CharField(max_length=300)

class Programs_in_Agreement(models.Model):
   programs = models.ForeignKey(Program)
   agreement = models.ForeignKey(Agreement)

Im trying to get this page 
/api/v1/Costumers/1/Agreements/1/Programs/

and I've got this error
"^Costumers/(?P<parent_lookup_agreement>[^/.]+)/Agreements/(?P<parent_lookup_agreement>[^/.]+)/Programs/$" is not a valid regular expression: redefinition of group name 'parent_lookup_agreement' as group 2; was group 1

the relation between Programs and Agreements is M2M and the relation between Agreement and costumer is M21 can somone help me please?

like image 819
Gal Yaish Avatar asked Jan 17 '26 02:01

Gal Yaish


1 Answers

You are nesting the routers, which means you are using one of the nested router plugins. The problem is that you are not providing all of the lookup fields for the last register call.

The relationship that it looks like you are trying to achieve is

Program -> Agreement -> Costumers

And the routers are generating

Costumers
Agreement -> Costumers
Program -> Agreement -> Costumers

Where the -> signals the lookup that is being made. The lookup must manually be provided when registering by passing in parents_query_lookups. This is important, as otherwise the plugin has to guess what the lookup is, and it's bound to be wrong. The lookups are not maintained across nestings of the routers, so a lookup defined on router A will not be passed down to router B, it must be repeated on router B as well.

So what you should be doing when registering the router is passing in the parent lookup. The snippet below should work:

router.register(r'Costumers', CostumerViewSet, base_name='costumer')
  .register(r'Agreements', AgreementViewSet, base_name='agreement', parents_query_lookups=['costumer']).
      .register(r'Programs', ProgramViewSet, base_name='programs', parents_query_lookups=['agreement__costumer', 'agreement'])

Note the addition of agreement__costumer in the parents_query_lookups for the last call. This allows the plugin to fill in the lookup field for that part of the URL, preventing duplicated groups from showing up.

like image 97
Kevin Brown-Silva Avatar answered Jan 19 '26 18:01

Kevin Brown-Silva



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!