Skip to content
This repository has been archived by the owner on Mar 4, 2024. It is now read-only.

petbccufscar/Tutoramos

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Instalação e criação do virtualenv

pip install virtualenv
virtualenv .venv

Ativando o ambiente virtual

Windows

source .venv/Scripts/activate

Linux

source .venv/bin/activate

Instalando o django rest

Documentação

pip install django djangorestframework

Criando o Projeto

django-admin startproject tutoramos .

Instalando o Simple JWT

Documentação

pip install djangorestframework-simplejwt

Adicionando os Pacotes instalados

Em settings.py adicione os apps:

INSTALLED_APPS = [
    ...
    'rest_framework',
    'rest_framework_simplejwt',
]

Também se faz necessário adicionar o seguinte código no settings.py:


REST_FRAMEWORK = {
    ...
    'DEFAULT_AUTHENTICATION_CLASSES': (
        ...
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    )
    ...
}

Criando Apps

Vamos criar nossos próprios apps!!

django-admin startapp Perfil
django-admin startapp POT
django-admin startapp Reuniao

Lembre-se de adicioná-los nos INSTALLED_APPS.

INSTALLED_APPS = [
    ...
    'Perfil',
    'POT',
    'Reuniao'
]

Requirements.txt

Manter as dependências é importante!!

Para salvar:

pip freeze > requirements.txt

Para instalar a partir do arquivo:

pip install -r requirements.txt

Adicionando no painel de adm

Documentação

Para aparecer no painel de adm basta registrar o modelo no arquivo admin.py

Exemplo:

from .models import Reuniao
admin.site.register(Reuniao)

Migrações

python manage.py makemigrations
python manage.py migrate

Criando super usuário

python manage.py createsuperuser 

Rodando o servidor

python manage.py runserver

Model Fields

Referência

  • IntegerField
  • BooleanField
  • CharField
  • DateField
  • DateTimeField
  • DurationField
  • EmailField

Relações

models.TIPODERELACAO( MODELOASSOCIADO, on_delete=E_SE_DELETAR, related_name=FUNCAO_INVERSA)

Tipos de campos de relações

Documentação

  • ForeignKey - Usado para 1 - N
  • OneToOneField - Usado para 1 - 1
  • ManyToManyField - Usado para M - N

Tipos de deleções principais

Referência

  • CASCADE
  • PROTECT
  • RESTRICT
  • SET_NULL
  • SET_DEFAULT

Relação inversa

a.reunioes_do_perfil.all()

Modelando as entidades

Exemplo:

class Reuniao(models.Model):
    # Campos
    nome = models.CharField(blank=False, null=False, max_length=255)
    descricao = models.CharField(blank=False, null=False, max_length=400)
    dataHora = models.DateTimeField()
    created_at = models.DateTimeField(auto_now_add=True)

    # Relações
    #participantes = models.ManyToManyField(Perfil,related_name="reunioes_do_perfil") 
    #POT = models.ForeignKey(POT, models.CASCADE, related_name="reunioes_do_pot")

Serializadores

Documentação

"Serializers allow complex data such as querysets and model instances to be converted to native Python datatypes that can then be easily rendered into JSON, XML or other content types. Serializers also provide deserialization, allowing parsed data to be converted back into complex types, after first validating the incoming data."

Model Serializer (CRUD pronto)

Exemplo:

class ReuniaoSerializer(ModelSerializer):
    class Meta:
        model = Reuniao
        fields = '__all__'

SerializerMethodField

Documentação

PrimaryKeyRelatedField

Documentação

Criando os serializers

Crie arquivos serializers.py nos apps. Faça seus serializers, para esse tutorial ModelSerializer é suficiente. Para mais informações, consulte a documentação.

Serializers compostos

É possivel inserir um serializer como campo de outro. Exemplo:

user: User = UserSerializer(write_only=True)

to_representation

Documentação Você customiza o que quer ver pelo Serializer!!

@transaction.atomic

Lembram que em algum momento a gente ficou preocupado com as condições de corrida que podiam acontecer ao fazer alguma leitura do banco de dados, manipular esse dado e escrever novamente no banco? Aparentemente os bancos de dados tem operadores pra garantir que isso não aconteça. São chamados "transactions". Basicamente, vc coloca um "begin-transaction" antes de começar a fazer leituras e escritas no banco de dados e "commita" as alterações quando todas as operações forem feitas. Se alguma falhar, todas são desfeitas. Esse comando garante também a atomicidade, não tem a chance de vc ler uma propriedade A e outra pessoa escrever em cima desse propriedade antes de você terminar sua operação (se vc tiver usado o begin-transaction").

Rotas

  • CRUD Reunião
  • CRUD POT
  • CRUD Perfil+Usuário
  • Login
  • Refresh

APIView

Documentação Exemplo:

class ListUsers(APIView):
    authentication_classes = [authentication.TokenAuthentication]
    permission_classes = [permissions.IsAdminUser]

    def get(self, request, format=None):
        """
        Return a list of all users.
        """
        usernames = [user.username for user in User.objects.all()]
        return Response(usernames)

Generic views

Documentação

  • CreateAPIView
  • RetrieveAPIView
  • UpdateAPIView
  • DestroyAPIView
  • ListAPIView

Como testar as rotas???

CRUD POT, REUNIÃO, PERFIL

Os Cruds, em sua maioria serão feitos desse modo: Considerando um modelo NOME:

class ListCreateNOME(generics.ListCreateAPIView):
    queryset = NOME.objects.all()
    permission_classes = []
    serializer_class = NOMESerializer

class RetrieveUpdateDeleteNOME(generics.RetrieveUpdateDestroyAPIView):
    queryset = NOME.objects.all()
    permission_classes = []
    serializer_class = NOMESerializer

Esse é um CRUD bem simples que se aproveita dos generics para funcionar. Sempre é possível fazer modificações. Necessário dizer que é preciso linkar essas views no urls:

path('NOME/', ListCreateNOME.as_view()),
path('NOME/<pk>/', RetrieveUpdateDeleteNOME.as_view()),
# <pk> é um kwarg que é necessário em views que são relativas a um unico objeto.
# ele vai representar a chave primária desse objeto.
# se acessar NOME/1/, você estará fazendo a operação no objeto nome de chave primária 1.

Em relação ao CRUD do Perfil + User é um pouco mais complicado, pois, como eles são integrados, temos os seguintes serializers:

class UserSerializer(serializers.ModelSerializer):
    email = serializers.EmailField()
    password = serializers.CharField()
    username = serializers.CharField()
    name = serializers.CharField()

    def create(self, validated_data):
        user = User()

        user.username = validated_data['username']
        user.email = validated_data['email']
        user.first_name = validated_data['first_name']
        validated_data.pop('name')
        user.set_password(validated_data['password'])

        return user

    def update(self, user: User, validated_data):
        l = ['username', 'email', 'first_name']
        for i in l:
            if i in validated_data:
                setattr(user, i, validated_data[i])

        if 'name' in validated_data:
            validated_data.pop('name')

        if 'password' in validated_data:
            user.set_password(validated_data['password'])
        
        return user

    class Meta:
        model = User
        fields = ['name', 'email', 'password', 'username']


class PerfilSerializer(serializers.ModelSerializer):

    user: User = UserSerializer(write_only=True)
    
    class Meta:
        model = Perfil
        fields = '__all__'

    @transaction.atomic
    def create(self, validated_data):
        user_data = validated_data.pop('user')

        user = User.objects.create_user(
            first_name=user_data['name'],
            username=user_data['username'],
            email=user_data['email'],
            password=user_data['password']
        )

        return Perfil.objects.create(**validated_data, user=user)


    @transaction.atomic
    def update(self, instance, validated_data):
        if 'user' in validated_data:
            user_data = validated_data.pop('user')
            d = {}

            if 'name' in user_data:
                d['first_name'] = user_data['name']

            l = ['email', 'password', 'username']
            for i in l:
                if i in user_data:
                    d[i] = user_data[i]
            
            serializer = UserSerializer()
            user = serializer.update(user = instance.user,validated_data=d)
            user.save()
            instance.user = user
        return super().update(instance,validated_data=validated_data)

    


    def to_representation(self, instance: Perfil):
        representation = {'id': instance.user.id,
                          'username': instance.user.username,
                          'email': instance.user.email,
                          'nome': instance.user.get_full_name()
                          }

        # Adiciona os dados da própria instância.
        representation.update(super().to_representation(instance))
        return representation

Note que há uma preocupação se os parâmetros foram passados no update, pois o verbo PATCH passa apenas os que serão atualizados. Também é importante notar o uso do ".save()", você pode recuperar um objeto e modificar, mas para a aplicação refletir no banco de dados é necessário fazer o save.

Autenticação

  • Rotas de login

Adicione o seguinte no urls

from rest_framework_simplejwt.views import (
    TokenObtainPairView,
    TokenRefreshView,
)

urlpatterns = [
    ...
    path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
    path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
    ...
]

É possivel modificar as configurações do simple jwt

É possível modificar as rotas de login e refresh também!

Permissões

Com as Permissões podemos controlar o acesso as views!!

As principais são:

  • AllowAny
  • IsAuthenticated
  • IsAdminUser

Para ativa-las basta usar o campo permission_classes das views, as passando na lista.

exemplo:

class ListCreateReuniao(generics.ListCreateAPIView):
    queryset = Reuniao.objects.all()
    permission_classes = [IsAuthenticated]
    serializer_class = ReuniaoSerializer

Além de permitir o acesso, também podemos pegar o objeto do usuário logado nas views.

exemplo:

class ListCreateReuniao(generics.ListCreateAPIView):
    permission_classes = [IsAuthenticated]
    serializer_class = ReuniaoSerializer

    def get_queryset(self):
        qs = Reuniao.objects.all()
        return qs.filter(POT=self.request.user.perfil.POT)

Limitando o queryset pelo método:

class RetrieveUpdatePerfil(generics.RetrieveUpdateAPIView):
    permission_classes = [IsAuthenticated]
    serializer_class = PerfilSerializer

    def get_queryset(self):
        qs = Perfil.objects.all()
        if self.request.method == 'GET':
            return qs
        return qs.filter(id=self.request.user.perfil.id)

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages