I have a serialised model (Job) which I am using with datatables. The "Job" model is related to another model (Board) and here is where my problem is. I followed the doc here to filter jobs that are related to the "Board" model which is currently being viewed, but I can't get it to work as intended.
models.py
class Board(models.Model):
name = models.CharField(_('board name'), max_length=256)
slug = models.SlugField(_('unique url'), null=True, blank=True)
...
class Job(models.Model):
board = models.ForeignKey(Board, on_delete=models.CASCADE, verbose_name=_('board'))
...
views.py
class JobDataTablesViewSet(viewsets.ModelViewSet):
queryset = Job.objects.all().order_by('-date_posted')
serializer_class = JobDatatablesSerializer
filter_backends = (DatatablesFilterBackend,)
filterset_class = JobGlobalFilter
def get_queryset(self):
slug = self.kwargs['slug']
queryset = Job.objects.filter(board__slug=slug)
return queryset
urls.py
path('<slug:slug>/', views.BoardPublicView.as_view(), name='public-board')
For anyone with a similar issue, kindly take a look at alanjds/drf-nested-routers. This is what I used and it worked perfectly.
Here is an overview of what I did.
After installing the package with pip install drf-nested-routers
.
According to the docs,
It is not needed to add this library in your Django project's settings.py file, as it does not contain any app, signal or model.
In my app urls.py
file, I created parent and child routers
router = routers.SimpleRouter()
router.register(r'boards', views.BoardViewSet, basename="boards_api_list")
boards_router = routers.NestedSimpleRouter(router, r'boards', lookup='board')
boards_router.register(r'jobs', views.JobViewSet, basename='board_jobs_list')
urlpatterns = [
path('api/', include(router.urls)),
path('api/', include(boards_router.urls)),
]
Then in my serializers.py
, I created a HyperlinkedModelSerializer
class BoardSerializer(serializers.HyperlinkedModelSerializer):
owner = UserSerializer()
jobs = NestedHyperlinkedRelatedField(
many=True,
read_only=True,
view_name='jobs_view_name',
parent_lookup_kwargs={'slug': 'board__slug'}
)
class Meta:
model = Board
fields = [...]
extra_kwargs = {
'url': {'view_name': 'my_custom_view_name', 'lookup_field': 'slug'},
...other desired kwargs...
}
class JobViewSet(serializers.ModelSerializer):
...standard serializer settings...
I went on to my views.py
to create my viewsets and added the get_queryset
params
class JobViewSet(viewsets.ModelViewSet):
queryset = Job.objects.all().order_by('-date_posted')
serializer_class = JobSerializer
filter_backends = (DatatablesFilterBackend,)
filterset_class = JobGlobalFilter
def get_queryset(self):
return Job.objects.filter(board__slug=self.kwargs['board_slug'])
Once you do these, you should be able to access your APIs via
/parent_url/{{parent_pk}}/child_list/{{child_pk}}
Now, because of my peculiar need (I wanted to use this on datatables to filter related objects), I added the URLs of my APIs to the head of my base.html
so that the URLs can be loaded dynamically since I can't load such in my javascript file
...
<head>
<script>var boardListUrl= "{% url 'boards:boards_api_list-list' %}?format=datatables"</script>
{% if board.slug %}
<script>var jobListUrl= "{% url 'boards:board_jobs_list-list' board.slug %}?format=datatables"</script>
{% endif %}
<head>
...
And in my main.py
file, I did the following
var table = $('#tableName').DataTable({
...
"ajax": jobListUrl,
...
});