Quantcast
Channel: Planet Python
Viewing all articles
Browse latest Browse all 22462

PythonClub - A Brazilian collaborative blog about Python: Django Rest Framework Serialization

$
0
0

Eu resolvi estudar um pouco mais de DRF depois do tutorial do Hugo Brilhante na Python Brasil 11.

Obs: se você não sabe Django sugiro que leia este tutorial antes.

Este tutorial é a parte 1/6 de uma série de posts sobre DRF.

Obs: Tem coisas que é melhor nem traduzir. ;)

  • 0 - Quickstart
  • 1 - Serialization
  • 2 - Requests & Responses
  • 3 - Class based views
  • 4 - Authentication & permissions
  • 5 - Relationships & hyperlinked APIs
  • 6 - Viewsets & routers

Pra quem não sabe, para usar API Web usamos REST, no caso, Django Rest Framework, framework web do Django.

Nota: este tutorial não é exatamente igual ao do Hugo, é baseado nele. E baseado também em Tutorial 1: Serialization.

Então para criar a API, no meu caso, eu usei:

  • Ambiente: .venv
  • Projeto: myproject
  • App: core
  • Model: Person
  • Fields: first_name, last_name, email, active (boolean), created

img

Configurando um novo ambiente

$ virtualenv -p python3 .venv
$ source .venv/bin/activate
$ mkdir drf;cd drf
$ pip install django==1.8.6 djangorestframework==3.3.1
$ pip install django-filter drf-nested-routers
$ pip freeze > requirements.txt
$ django-admin.py startproject myproject .
$ python manage.py startapp core

Veja o meu requirements.txt

Django==1.8.6
django-filter==0.11.0
djangorestframework==3.3.1
drf-nested-routers==0.10.0

Step-0 Projeto inicial

Abra o arquivo settings.py e em INSTALLED_APPS acrescente

INSTALLED_APPS=(...'rest_framework','core',)

Step-1 Serializer

models.py: Criando o modelo Person

fromdjango.dbimportmodelsclassPerson(models.Model):first_name=models.CharField(max_length=30)last_name=models.CharField(max_length=30)email=models.EmailField(null=True,blank=True)active=models.BooleanField(default=True)created=models.DateTimeField(auto_now_add=True,auto_now=False)classMeta:ordering=['first_name']verbose_name=u'pessoa'verbose_name_plural=u'pessoas'def__str__(self):returnself.first_name+" "+self.last_namefull_name=property(__str__)

serializers.py: Criando PersonSerializer

Precisamos proporcionar uma forma de serialização e desserialização das instâncias de person em uma representação JSON.

$ cd core/
$ touch serializers.py

Edite

fromrest_frameworkimportserializersfromcore.modelsimportPersonclassPersonSerializer(serializers.Serializer):pk=serializers.IntegerField(read_only=True)first_name=serializers.CharField(max_length=30)last_name=serializers.CharField(max_length=30)email=serializers.EmailField()active=serializers.BooleanField(default=True)created=serializers.DateTimeField()defcreate(self,validated_data):"""        Create and return a new `Person` instance, given the validated data.        :param validated_data:"""returnPerson.objects.create(**validated_data)defupdate(self,instance,validated_data):"""        Update and return an existing `Person` instance, given the validated data."""instance.first_name=validated_data.get('first_name',instance.first_name)instance.last_name=validated_data.get('last_name',instance.last_name)instance.email=validated_data.get('email',instance.email)instance.save()returninstance

A primeira parte da classe define os campos que serão serializados. Os métodos create() e update() criam e atualizam as instâncias, respectivamente, quando chamados.

Uma classe de serialização é similar a uma classe Form do Django, e inclui validações similares para os campos, tais como required, max_length e default.

Fazendo a migração

$ ./manage.py makemigrations core
$ ./manage.py migrate

Trabalhando com a serialização

Abra o shell do Django.

$ ./manage.py shell

Primeiro vamos criar uma pessoa.

>>>fromcore.modelsimportPerson>>>fromcore.serializersimportPersonSerializer>>>fromrest_framework.renderersimportJSONRenderer>>>fromrest_framework.parsersimportJSONParser>>>person=Person(first_name='Paul',last_name='Van Dyke',email='paul@email.com')>>>person.save()>>>person=Person(first_name='Regis',last_name='Santos',email='regis@email.com')>>>person.save()

Agora que já temos alguns dados podemos ver a serialização da última instância.

>>>serializer=PersonSerializer(person)>>>serializer.data# {'pk': 2, 'first_name': 'Regis', 'created': '2015-11-15T03:20:25.084990Z', 'last_name': 'Santos', 'email': 'regis@email.com', 'active': True}

Neste ponto nós traduzimos a instância do modelo em tipos de dados nativos do Python. Para finalizar o processo de serialização nós vamos renderizar os dados em json.

>>>content=JSONRenderer().render(serializer.data)>>>content# b'{"pk":2,"first_name":"Regis","last_name":"Santos","email":"regis@email.com","active":true,"created":"2015-11-15T03:20:25.084990Z"}'

A desserialização é similar.

>>>fromcore.modelsimportPerson>>>fromcore.serializersimportPersonSerializer>>>fromrest_framework.renderersimportJSONRenderer>>>fromrest_framework.parsersimportJSONParser>>>fromdjango.utils.siximportBytesIO>>>person=Person.objects.get(pk=1)>>>serializer=PersonSerializer(person)>>>content=JSONRenderer().render(serializer.data)>>>stream=BytesIO(content)>>>data=JSONParser().parse(stream)>>>serializer=PersonSerializer(data=data)>>>serializer.is_valid()# True>>>serializer.validated_data# OrderedDict([('first_name', 'Paul'), ('last_name', 'Van Dyke'), ('email', 'paul@email.com'), ('active', True)])

Step-2 ModelSerializer

Nossa classe PersonSerializer está replicando um monte de informações que está contido no modelo Person.

Da mesma forma que o Django fornece Form e ModelForm, REST framework inclui as classes Serializer e ModelSerializer.

Vamos refatorar nosso arquivo serializers.py, que agora ficará assim:

fromrest_frameworkimportserializersfromcore.modelsimportPersonclassPersonSerializer(serializers.ModelSerializer):classMeta:model=Personfields=('pk','first_name','last_name','email','active','created')

Uma propriedade legal que a serialização tem é que você pode inspecionar todos os campos em uma instância serializer, imprimindo sua representação. Abra o shell do Django.

$ ./manage.py shell
>>>fromcore.serializersimportPersonSerializer>>>serializer=PersonSerializer()>>>print(repr(serializer))# PersonSerializer():#     pk = IntegerField(label='ID', read_only=True)#     first_name = CharField(max_length=30)#     last_name = CharField(max_length=30)#     email = EmailField(allow_blank=True, allow_null=True, max_length=254, required=False)#     active = BooleanField(required=False)#     created = DateTimeField(read_only=True)

É importante lembrar que as classes ModelSerializer não faz nenhuma mágica, são simplesmente um atalho para a criação das classes de serialização:

  • Os campos são definidos automaticamente.
  • Os métodos create() e update() são implementados por padrão de uma forma simplificada.

views.py: Criando views regulares usando nosso Serializer

Vamos criar uma view simples para visualizar os dados em json.

Edite o arquivo views.py

fromdjango.httpimportHttpResponsefromdjango.views.decorators.csrfimportcsrf_exemptfromrest_framework.renderersimportJSONRendererfromrest_framework.parsersimportJSONParserfromcore.modelsimportPersonfromcore.serializersimportPersonSerializerclassJSONResponse(HttpResponse):"""    An HttpResponse that renders its content into JSON."""def__init__(self,data,**kwargs):content=JSONRenderer().render(data)kwargs['content_type']='application/json'super(JSONResponse,self).__init__(content,**kwargs)

A raiz da nossa API será uma lista de todas as pessoas, ou podemos criar uma pessoa nova.

@csrf_exemptdefperson_list(request):"""    List all persons, or create a new person."""ifrequest.method=='GET':persons=Person.objects.all()serializer=PersonSerializer(persons,many=True)returnJSONResponse(serializer.data)elifrequest.method=='POST':data=JSONParser().parse(request)serializer=PersonSerializer(data=data)ifserializer.is_valid():serializer.save()returnJSONResponse(serializer.data,status=201)returnJSONResponse(serializer.errors,status=400)

Note que nós queremos usar o POST mas não temos o CSRF Token, por isso usamos o @csrf_exempt.

Também vamos precisar visualizar os detalhes de cada pessoa. Assim podemos recuperar, atualizar ou deletar cada registro.

@csrf_exemptdefperson_detail(request,pk):"""    Retrieve, update or delete a person."""try:person=Person.objects.get(pk=pk)exceptPerson.DoesNotExist:returnHttpResponse(status=404)ifrequest.method=='GET':serializer=PersonSerializer(person)returnJSONResponse(serializer.data)elifrequest.method=='PUT':data=JSONParser().parse(request)serializer=PersonSerializer(person,data=data)ifserializer.is_valid():serializer.save()returnJSONResponse(serializer.data)returnJSONResponse(serializer.errors,status=400)elifrequest.method=='DELETE':person.delete()returnHttpResponse(status=204)

Agora, vamos criar as urls. Crie um novo arquivo core/urls.py.

fromdjango.conf.urlsimporturlfromcoreimportviewsurlpatterns=[url(r'^persons/$',views.person_list),url(r'^persons/(?P<pk>[0-9]+)/$',views.person_detail),]

E acrescente a seguinte linha em myproject/urls.py.

urlpatterns=[url(r'^',include('core.urls')),url(r'^admin/',include(admin.site.urls)),]

Instalando httpie

Podemos usar o curl, mas o httpieé mais amigável, e escrito em Python.

$ sudo pip install httpie

Vamos usar o httpie digitando

$ http http://127.0.0.1:8000/persons/

HTTP/1.0 200 OK
Content-Type: application/json
Date: Sun, 15 Nov 2015 03:24:44 GMT
Server: WSGIServer/0.2 CPython/3.4.3
X-Frame-Options: SAMEORIGIN

[{"active": true, 
        "created": "2015-11-15T03:20:24.938378Z", 
        "email": "paul@email.com", 
        "first_name": "Paul", 
        "last_name": "Van Dyke", 
        "pk": 1
    }, 
    {"active": true, 
        "created": "2015-11-15T03:20:25.084990Z", 
        "email": "regis@email.com", 
        "first_name": "Regis", 
        "last_name": "Santos", 
        "pk": 2
    }]

Veja os detalhes

$ http http://127.0.0.1:8000/persons/1/

Atenção: se você receber erro 301, muito provavelmente é porque você esqueceu da barra / no final da url.

Como seria em curl?

Assim

$ curl http://127.0.0.1:8000/persons/

[{"pk":1,"first_name":"Paul","last_name":"Van Dyke","email":"paul@email.com","active":true,"created":"2015-11-15T03:20:24.938378Z"},{"pk":2,"first_name":"Regis","last_name":"Santos","email":"regis@email.com","active":true,"created":"2015-11-15T03:20:25.084990Z"}]

GitHub: Se você quiser pode olhar meu GitHub, mas terá que ver os commits para ver os passos.


Viewing all articles
Browse latest Browse all 22462

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>