Last active
October 31, 2020 09:45
-
-
Save davemerwin/bad642979b9681d3b0e8 to your computer and use it in GitHub Desktop.
This is a (mostly) complete relationship example of a parent child relationship via Django Rest Framework
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This example will allow you to manipluate a Parent and a Child via various endpoints | |
# /api - All endpoints | |
# /api/parents - Parents list | |
# /api/parents/(?P<pk>\d+) - Parent detail | |
# /api/parents/(?P<pk>\d+)/children - List of children of parent | |
# /api/children - Child list | |
# /api/children/(?P<pk>\d+) - Child Detail | |
# Models - models.py | |
# Pretty simple setup. Children have a FK to parent | |
from django.db import models | |
from django.contrib.auth.models import User | |
class Parent(models.Model): | |
user = models.ForeignKey(User, related_name="user_parent") | |
# other fields | |
class Meta: | |
verbose_name = 'Parent' | |
verbose_name_plural = 'Parents' | |
class Child(models.Model): | |
user = models.ForeignKey(User, related_name="user_child") | |
parent = models.ForeignKey(Parent, related_name="parent_child") | |
# other fields | |
class Meta: | |
verbose_name = 'Child' | |
verbose_name_plural = 'Children' | |
# Permisions - permissions.py | |
# Basic permisions | |
from rest_framework.permissions import BasePermission, SAFE_METHODS | |
class IsStaffOrOwner(BasePermission): | |
def has_permission(self, request, view): | |
# allow user to list all users if logged in user is staff | |
return view.action == 'retrieve' or 'create' or request.user.is_staff | |
def has_object_permission(self, request, view, obj): | |
return request.user.is_staff or request.user == obj.user | |
# Serializers - serializers.py | |
from django.contrib.auth.models import User | |
from rest_framework import serializers | |
from myproject.myapp import models | |
class ChildSerializer(serializers.HyperlinkedModelSerializer): | |
user_child = serializers.HyperlinkedRelatedField(view_name="user-detail", read_only=True) | |
class Meta: | |
model = models.Child | |
fields = ('id', 'url', 'user',) | |
class ParentSerializer(serializers.HyperlinkedModelSerializer): | |
parent_child = serializers.HyperlinkedRelatedField(many=True, required=False, view_name='child-detail') | |
user_parent = serializers.HyperlinkedRelatedField(view_name="user-detail", read_only=True) | |
class Meta: | |
model = models.Parent | |
fields = ('id', 'url', 'user', 'parent_child') | |
# API Views - views.py | |
from django.contrib.auth.models import User | |
from rest_framework import viewsets | |
from rest_framework.decorators import list_route, detail_route | |
from rest_framework.response import Response | |
from .serializers import ParentSerializer, ChildSerializer | |
from .permissions import IsStaffOrOwner | |
from myproject.myapp import models | |
class ChildViewSet(viewsets.ModelViewSet): | |
serializer_class = ChildSerializer | |
permission_classes = (IsStaffOrOwner,) | |
def get_queryset(self): | |
if self.request.user.is_superuser: | |
return models.Child.objects.all() | |
else: | |
return self.request.user.user_child.all() | |
def pre_save(self, obj): | |
obj.user = self.request.user | |
class ParentViewSet(viewsets.ModelViewSet): | |
serializer_class = ParentSerializer | |
permission_classes = (IsStaffOrOwner,) | |
def get_queryset(self): | |
if self.request.user.is_superuser: | |
return models.Parent.objects.all() | |
else: | |
return self.request.user.user_parent.all() | |
def pre_save(self, obj): | |
obj.user = self.request.user | |
# The detail_route allows me to see all the children of a parent | |
# with the following URL: /api/parents/(?P<pk>\d+)/children | |
@detail_route() | |
def children(self, request, pk): | |
parent = self.get_object(pk) | |
children = parent.parent_child.all() | |
serializer = ChildSerializer(hints) | |
return Response(serializer.data) | |
# API URLS - urls.py | |
from django.conf.urls import patterns, include, url | |
from rest_framework.routers import DefaultRouter | |
from .myapp.api import views as myapp_views | |
router = DefaultRouter(trailing_slash=False) | |
router.register(r'children', myapp_views.ChildViewSet, base_name="child") | |
router.register(r'parent', myapp_views.TaskViewSet, base_name="parent") | |
urlpatterns = patterns('', | |
# API URIs | |
url(r'^api/', include(router.urls)), | |
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')), | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
What's with the "hints" in line 111 ? I am just browsing your code and shouldn't it throw a NameError? Thanks for boiling it down to a nearly complete piece dude! Good stuff :)