I'm a little bit stuck with the following situation. I want to build a REST API for a shopping cart app using the Django Rest Framework, however, due to legacy requirements I need to work with nested URLs.
In general, I have two resources AppUsers and Carts. Both of the resources are available at the default /appUsers/ and /carts/ endpoints. I then tried using nested routers to get the cart detail view for a specific user to be addressable as /appUsers/app_user_pk/cart/ instead of /carts/pk/ since every AppUser can only have one cart anyway.
Here's my setup:
models.py
class AppUser(models.Model):
_id = models.AutoField(primary_key=True)
class Meta:
default_related_name = 'app_users'
class Cart(models.Model):
app_user = models.OneToOneField(
'AppUser',
on_delete=models.CASCADE,
related_query_name='cart',
)
class Meta:
default_related_name = 'carts'
def __str__(self):
return "{user} cart".format(user=self.app_user._id)
serializers.py
class AppUserSerializer(serializers.HyperlinkedModelSerializer):
cart = serializers.HyperlinkedIdentityField(view_name='cart-detail')
class Meta:
model = AppUser
fields = '__all__'
class CartSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Cart
fields = '__all__'
views.py
class AppUserViewSet(viewsets.ModelViewSet):
"""
Model viewset for AppUser model
"""
queryset = AppUser.objects.all()
serializer_class = AppUserSerializer
class CartViewSet(viewsets.ModelViewSet):
"""
List all carts, or create new / edit existing product.
"""
queryset = Cart.objects.all()
serializer_class = CartSerializer
def get_queryset(self):
if 'app_user_pk' in self.kwargs:
return Cart.objects.filter(app_user=self.kwargs['app_user_pk'])
return Cart.objects.all()
urls.py
router = DefaultRouter()
router.register(r'appUsers', views.AppUserViewSet)
router.register(r'carts', views.CartViewSet)
urlpatterns = [
url(r'^', include(router.urls)),
url(r'^appUsers/(?P<app_user_pk>[0-9]+)/cart/$', views.CartViewSet.as_view({'get': 'retrieve'}), name='cart-detail'),
]
However, I can't get it to work, whenever I try something new I run into a different issue. So I was wondering what the best way is to achieve such task?
Essentially I just want to have cart-detail view for the one shopping cart the an AppUser can have under /appUsers/app_user_pk/cart/
SOLUTION:
I used the accepted answer to deal with the issue above. Additionally I had another ModelViewSet located at /appUsers/app_user_pk/cart/products, which I then registered using a NestedDefaultRouter from drf-nested-routers at cart/products like this:
cart_products_router = routers.NestedDefaultRouter(router, r'appUsers', lookup='app_user')
cart_products_router.register(r'cart/products', views.CartProductViewSet, base_name='cartproduct')
You can create a custom method to
AppUserViewSet
: