Django Rest UrlField com vários lookups¶
As vezes suas url pode ter vários lookups que precisem ser acessado para ser mondata e achada pelo reverse
do Django. Um exemplo de URL com tal comportamente é o seguinte exemplo:
https://www.domain.com/api/school/20/teacher/100/class/10/students/
A URL acima possui 3 lookups field: 20, 100 e 10.
ou ainda uma URL sem lookup algum, como:
https://www.domain.com/api/login/
Para adicionar um campo de URL, ao seu serializer, que seja capaz de gerar as seguinte urls será preciso alguns passos a mais.
Definindo a URL¶
Primeiro vamos registrar nossa URL acima no arquivos urls.py
# urls.py
from django.urls import path
from .viws import MyView
url = 'api/school/<int:id_school>/teacher/<int:id_teacher>/class/<int:id_class>/students/'
urlpatterns = [
path('', HomeView.as_view(), name='home'),
path('login/', LoginView.as_view(), name='login'),
path(url, MyView.as_view(), name='students-view')
]
A URL acima tem os seguintes lookups keys:
id_school
: intid_teacher
: intid_class
: int
Criando nosso Field¶
Agora criaremos um Field dos customoizado do Django Rest que receberá a instância do model e irá chamar um método para criar os lookups da URL.
Reverse de uma URL com vários lookups¶
# serializers.py
from rest_framework import serializers
from rest_framework.reverse import reverse
class UrlPatternsField(serializers.HyperlinkedIdentityField):
def get_url(self, obj, view_name, request, format):
kwargs = {}
# nome do método que deve ser implementado para
# gerar os lookups da URL
# ex: suponha que o field_name seja `esola`
# o nome do método será: `get_lookups_fields_escola`
method_name = 'get_lookups_fields_{}'.format(field_name)
# pega o método, se existir.
# Caso contrário o valor retornado é None
multiple_lookups_fields = getattr(self.parent, method_name, None)
if multiple_lookups_fields:
# já que existe um método, passaremos o objeto
# para que ele possa gerar os lookups a partir do
# objeto
kwargs = multiple_lookups_fields(obj)
return reverse(view_name, request=request, kwargs=kwargs, format=format)
Pronto, field criado, agora devemos implementar no nosso serializer.
# serializers.py
class ClassSerializer(serializer.ModelSerializer):
students_url = UrlPatternsField(view_name='students-view')
# note que o nome do field deve ser adicionar ao nome do metodo
# nesse caso será `get_lookups_fields_students_url`
class Meta:
model = ClassModel
fields = '__all__'
def get_lookups_fields_students_url(self, obj):
# retornamos um dict com os lookups necessários para
# monstar a URL
return {
'id_school': obj.school.id,
'id_teacher': obj.teacher.id,
'id_class': obj.id
}
Reverse de uma URL sem lookup¶
Muito simple, não implementamos o método que retorna os lookups ou retornamos um dicionário vazio.
# serializers.py
class EntryPointSerializer(serializer.ModelSerializer):
login = UrlPatternsField(view_name='login')
# a url nao precisa de lookups, portanto nao implementamos o metodos
home = UrlPatternsField(view_name='home')
# a url nao precisa de lookups, portanto nao implementamos o metodos
class Meta:
model = EntryModel
fields = '__all__'