One place for hosting & domains

      clientes

      Como Gerenciar Réplicas e Clientes no Redis


      Introdução

      O Redis é um armazenamento de dados open-source de chave-valor na memória. Um dos seus recursos mais procurados é o suporte à replicação: qualquer servidor Redis pode replicar seus dados para qualquer número de réplicas, permitindo alta escalabilidade de leitura e forte redundância de dados. Além disso, o Redis foi projetado para permitir que muitos clientes (até 10000, por padrão) se conectem e interajam com os dados, tornando-o uma boa opção para casos em que muitos usuários precisam acessar o mesmo dataset ou conjunto de dados.

      Este tutorial aborda os comandos usados para gerenciar clientes e réplicas Redis.

      Como Usar Este Guia

      Este guia foi escrito como uma consulta rápida com exemplos independentes. Recomendamos que você pule para qualquer seção que seja relevante para a tarefa que você está tentando concluir.

      Os comandos mostrados neste guia foram testados em um servidor Ubuntu 18.04 executando a versão do Redis 4.0.9. Para configurar um ambiente semelhante, você pode seguir o Passo 1 do nosso guia Como Instalar e Proteger o Redis no Ubuntu 18.04. Vamos demonstrar como esses comandos se comportam executando-os com redis-cli, a interface de linha de comando do Redis. Observe que se você estiver usando uma interface Redis diferente — Redli, por exemplo — a saída exata de certos comandos pode ser diferente.

      Alternativamente, você pode provisionar uma instância de banco de dados Redis gerenciada para testar esses comandos, mas observe que, dependendo do nível de controle permitido pelo seu provedor de banco de dados, alguns comandos neste guia podem não funcionar como descrito. Para provisionar um banco de dados gerenciado na DigitalOcean, siga nossa documentação do produto Managed Databases. Em seguida, você deve instalar o Redli ou configurar um túnel TLS para conectar-se ao banco de dados gerenciado via TLS.

      Nota: O projeto Redis usa os termos “master” e “slave” em sua documentação e em vários comandos para identificar diferentes funções na replicação, embora os colaboradores do projeto estejam tomando medidas para alterar essa linguagem nos casos onde isso não cause problemas de compatibilidade. A DigitalOcean geralmente prefere usar os termos alternativos “primary” e “replica”.

      Este guia assumirá o padrão “primary” e “replica” sempre que possível, mas observe que existem algumas circunstâncias em que os termos “master” e “slave” inevitavelmente aparecem.

      Gerenciando Réplicas

      Um dos recursos que mais se destaca no Redis é sua replicação embutida. Ao usar a replicação, o Redis cria cópias exatas da instância primária. Essas instâncias secundárias se reconectam à primária sempre que suas conexões quebram e sempre procurarão permanecer como uma cópia exata da primária.

      Se você não tiver certeza se a instância do Redis à qual você está conectado atualmente é uma instância primária ou uma réplica, verifique com o comando role:

      Este comando retornará master ou slave ou, potencialmente, sentinel se você estiver usando Redis Sentinel.

      Para designar uma instância do Redis como uma réplica de outra instância em tempo real, execute o comando replicaof. Este comando usa o nome do host ou o endereço IP do servidor primário pretendido e a porta como argumentos:

      • replicaof hostname_ou_IP porta

      Se o servidor já era uma réplica de outro primário, ele interromperá a replicação do servidor antigo e começará a sincronizar imediatamente com o novo. Ele também descartará o dataset antigo.

      Para promover uma réplica de volta para ser primária, execute o seguinte comando replicaof:

      Isso impedirá a instância de replicar o servidor primário, mas não descartará o dataset que já foi replicado. Essa sintaxe é útil nos casos em que o primário original falha. Depois de executar replicaof no one em uma réplica do primário com falha, a réplica anterior pode ser usada como o novo primário e ter suas próprias réplicas como um mecanismo de proteção a falhas.

      Nota: Antes da versão 5.0.0, o Redis incluía uma versão deste comando chamada slaveof.

      Gerenciando Clientes

      Um cliente é qualquer máquina ou software que se conecta a um servidor para acessar um serviço. O Redis vem com vários comandos que ajudam a rastrear e gerenciar conexões de clientes.

      O comando client list retorna um conjunto de informações legíveis sobre as conexões atuais de cliente:

      Output

      "id=18165 addr=[2001:db8:0:0::12]:47460 fd=7 name=jerry age=72756 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 events=r cmd=ping id=18166 addr=[2001:db8:0:1::12]:47466 fd=8 name= age=72755 idle=5 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 events=r cmd=info id=19381 addr=[2001:db8:0:2::12]:54910 fd=9 name= age=9 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=26 qbuf-free=32742 obl=0 oll=0 omem=0 events=r cmd=client "

      Aqui está o que cada um desses campos significa:

      • id: um ID de cliente exclusivo de 64 bits
      • name: o nome da conexão do cliente, conforme definido por um comando anterior client setname
      • addr: o endereço e a porta a partir da qual o cliente está se conectando
      • fd: o descritor de arquivo que corresponde ao soquete no qual o cliente está se conectando
      • age: a duração total da conexão do cliente, em segundos
      • flags: um conjunto de uma ou mais flags de caractere simples que fornecem detalhes mais granulares sobre os clientes; veja a documentação do comando client list para mais detalhes
      • db: o número atual do ID do banco de dados ao qual o cliente está conectado (pode ser de 0 a 15)
      • sub😮 número de canais aos quais o cliente está inscrito
      • psub: o número de subscrições correspondentes ao padrão do cliente
      • mutli: o número de comandos que o cliente enfileirou em uma transação (mostrará -1 se o cliente não iniciou uma transação ou 0 se apenas iniciou uma transação e não colocou nenhum comando na fila)
      • qbuf😮 tamanho do buffer de consulta do cliente, com “0” significando que não há consultas pendentes
      • qbuf-free: a quantidade de espaço livre no buffer de consulta do cliente, com “0” significando que o buffer de consulta está cheio
      • obl: o comprimento do buffer de saída do cliente
      • oll: o comprimento da lista de saída do cliente, onde as respostas são colocadas na fila quando o buffer está cheio
      • omem: a memória usada pelo buffer de saída do cliente
      • events: eventos do descritor de arquivo do cliente, eles podem ser r para “legível”, w para “gravável” ou ambos
      • cmd: o último comando executado pelo cliente

      Definir nomes de clientes é útil para debugar vazamentos de conexão em qualquer aplicativo que esteja usando o Redis. Toda nova conexão é iniciada sem um nome atribuído, mas client setname pode ser usado para criar um para a conexão atual do cliente. Não há limite para o tamanho dos nomes dos clientes, embora o Redis normalmente limite os comprimentos de string de caracteres para 512 MB. Observe, porém, que os nomes dos clientes não podem incluir espaços:

      Para obter o nome de uma conexão de cliente, use o comando client getname:

      Output

      "elaine"

      Para buscar o ID de conexão de um cliente, use o comando client id:

      Output

      (integer) "19492"

      Os IDs de clientes Redis nunca são repetidos e são monotonicamente incrementais. Isso significa que, se um cliente tiver um ID maior que outro, então ele foi estabelecido posteriormente.

      Bloqueando Clientes e Fechando Conexões de Cliente

      Os sistemas de replicação são normalmente descritos como sendo síncronos ou assíncronos. Na replicação síncrona, sempre que um cliente adiciona ou altera dados, ele deve receber algum tipo de reconhecimento de um certo número de réplicas para que a alteração seja registrada como confirmada. Isso ajuda a impedir que os nodes tenham conflitos de dados, mas tem um custo de latência, já que o cliente deve esperar para executar outra operação até receber uma resposta de um certo número de réplicas.

      Na replicação assíncrona, por outro lado, o cliente vê uma confirmação de que a operação é concluída assim que os dados são gravados no armazenamento local. No entanto, pode haver um atraso entre isso e quando as réplicas realmente gravam os dados. Se uma das réplicas falhar antes de poder gravar a alteração, essa gravação será perdida para sempre. Portanto, embora a replicação assíncrona permita que os clientes continuem executando operações sem a latência causada pela espera das réplicas, isso pode levar a conflitos de dados entre nodes e pode exigir trabalho extra por parte do administrador do banco de dados para resolver esses conflitos.

      Devido ao seu foco no desempenho e na baixa latência, o Redis implementa a replicação assíncrona por padrão. No entanto, você pode simular a replicação síncrona com o comando wait. O wait bloqueia a conexão do cliente atual por um período de tempo especificado (em milissegundos) até que todos os comandos de gravação anteriores sejam transferidos e aceitos com sucesso por um número especificado de réplicas. Este comando usa a seguinte sintaxe:

      • wait número_de_réplicas número_de_milisegundos

      Por exemplo, se você deseja bloquear a sua conexão de cliente até que todas as gravações anteriores sejam registradas por pelo menos três réplicas dentro de um tempo limite de 30 milissegundos, sua sintaxe wait se parecerá com esta:

      O comando wait retorna um número inteiro que representa o número de réplicas que reconheceram os comandos de gravação, mesmo que nem todas as réplicas o façam:

      Output

      2

      Para desbloquear uma conexão de cliente que foi bloqueada anteriormente, seja de um comando wait, brpop ou xread, você pode executar um comando client unblock com a seguinte sintaxe:

      Para suspender temporariamente todos os clientes atualmente conectados ao servidor Redis, você pode usar o comando client pause. Isso é útil nos casos em que você precisa fazer alterações na configuração do Redis de maneira controlada. Por exemplo, se você estiver promovendo uma de suas réplicas como a instância primária, poderá pausar todos os clientes com antecedência para promover a réplica e fazer com que os clientes se conectem a ela como o novo primário sem perder nenhuma operação de gravação no processo.

      O comando client pause exige que você especifique a quantidade de tempo (em milissegundos) que deseja suspender os clientes. O exemplo a seguir suspenderá todos os clientes por um segundo:

      A sintaxe do client kill permite que você feche uma única conexão ou um conjunto de conexões específicas com base em vários filtros diferentes. A sintaxe é assim:

      • client kill filtro_1 valor_1 ... filtro_n valor_n

      Nas versões do Redis 2.8.12 e posteriores, os seguintes filtros estão disponíveis:

      • addr: permite fechar uma conexão de cliente a partir de um endereço IP e porta especificados
      • client-id: permite fechar uma conexão de cliente com base em seu campo de ID exclusivo
      • type: fecha todo cliente de um determinado tipo, que pode ser normal, master, slave ou pubsub
      • skipme: as opções de valor para este filtro são yes e no:
        • se no for especificado, o cliente que chama o comando client kill não será ignorado e será eliminado se os outros filtros se aplicarem a ele
        • se yes for especificado, o cliente executando o comando será ignorado e o comando kill não terá efeito no cliente. skipme é sempreyes por padrão

      Conclusão

      Este guia detalha vários comandos usados para gerenciar clientes e réplicas Redis. Se houver outros comandos, argumentos ou procedimentos relacionados que você gostaria de ver descritos neste guia, peça ou faça sugestões nos comentários abaixo.

      Para obter mais informações sobre comandos Redis, consulte nossa série de tutoriais sobre Como gerenciar um banco de dados Redis.



      Source link

      Como Construir um Aplicativo Web Moderno para Gerenciar Informações de Clientes com Django e React no Ubuntu 18.04


      O autor selecionou a Open Sourcing Mental Ilness Ltd para receber uma doação como parte do programa Write for DOnations.

      Introdução

      As pessoas usam tipos diferentes de dispositivos para se conectar à internet e navegar pela Web. Por isso, os aplicativos precisam ser acessíveis de uma variedade de locais. Para sites tradicionais, ter uma interface responsiva geralmente é o suficiente, mas aplicativos mais complexos requerem muitas vezes o uso de outras técnicas e arquiteturas. Essas incluem ter aplicativos (separados) REST com back-end e front-end – que podem ser implementados como aplicativos Web do lado do cliente, Progressive Web Applications (PWAs – Aplicativos Progressivos para Web) ou aplicativos móveis nativos.

      Algumas ferramentas que você pode usar ao construir aplicativos mais complexos incluem:

      • O React, um framework JavaScript que permite que os desenvolvedores construam front-ends para Web e nativos para seus back-ends de API REST.
      • O Django, um framework Web gratuito e de código aberto, escrito em Python, que segue o padrão arquitetônico de software Model View Controller (MVC) [Modelo-Visão-Controle].
      • Framework Django REST, um kit de ferramentas eficaz e flexível para a criação de APIs REST no Django.

      Neste tutorial, você irá construir um aplicativo Web moderno com uma API REST separada com back-end e front-end, usando React, Django e o Django REST Framework. Ao usar o React com o Django, você conseguirá se beneficiar dos últimos avanços em JavaScript e desenvolvimento front-end. Em vez de construir um aplicativo Django que utilize um mecanismo de template interno, você usará o React como uma biblioteca de UI, beneficiando-se de sua abordagem informativa virtual Modelo de Documento por Objetos (do inglês Document Object Model – DOM) e de componentes que processam rapidamente alterações nos dados.

      O aplicativo Web que você construirá armazena registros sobre os clientes em um banco de dados, e você pode usá-lo como um ponto de partida para um aplicativo CRM. Quando você terminar, você conseguirá criar, ler, atualizar e excluir registros usando uma interface React estilizada com o Bootstrap 4.

      Pré-requisitos

      Para completar este tutorial, você precisará de:

      Passo 1 — Criando um Ambiente Virtual em Python e Instalando Dependências

      Neste passo, vamos criar um ambiente virtual e instalar as dependências necessárias para nosso aplicativo, incluindo o Django, o Django REST framework, e o django-cors-headers.

      Nosso aplicativo usará dois servidores diferentes para o Django e o React. Eles executarão em portas diferentes e funcionarão como dois domínios separados. Por isso, precisamos habilitar o compartilhamento de recursos com origens diferentes (CORS) para enviar pedidos HTTP do React para o Django sem sermos bloqueado pelo navegador.

      Navegue até seu diretório principal (home) e crie um ambiente virtual usando o módulo do Python 3 venv:

      • cd ~
      • python3 -m venv ./env

      Ative o ambiente virtual criado usando source:

      A seguir, instale as dependências do projeto com o pip. Essas incluem:

      • Django: o framework Web para o projeto.
      • Framework Django REST: um aplicativo de terceiros que constrói APIs REST com o Django.
      • django-cors-headers: um pacote que habilita o CORS.

      Instale o framework Django:

      • pip install django djangorestframework django-cors-headers

      Com as dependências do projeto instaladas, você pode criar o projeto Django e o front-end do React.

      Passo 2 — Criando o Projeto Django

      Neste passo, vamos gerar o projeto Django usando os comandos e utilitários a seguir:

      • **django-admin startproject project-name**: django-admin é um utilitário de linha de comando usado para realizar tarefas com o Django. O comando startproject cria um novo projeto Django.

      • **python manage.py startapp myapp**: manage.py é um script utilitário, adicionado automaticamente a cada projeto Django, que executa uma série de tarefas administrativas: criar novos aplicativos, migrar o banco de dados e atender ao projeto Django localmente. Seu comando startapp cria um aplicativo Django dentro do projeto Django. No Django, o termo aplicativo descreve um pacote Python que fornece alguns recursos em um projeto.

      Para começar, crie o projeto Django com django-admin startproject. Vamos chamar nosso projeto de djangoreactproject:

      • django-admin startproject djangoreactproject

      Antes de continuar, vamos ver a estrutura do diretório do nosso projeto Django usando o comando tree.

      Dica: tree é um comando útil para visualizar estruturas do arquivo e diretório da linha de comando. Você pode instalá-lo com o seguinte comando:

      • sudo apt-get install tree

      Para usá-lo, cd no diretório que você queira e digite tree ou forneça o caminho para o ponto inicial com tree /home/sammy/sammys-project.

      Navegue até a pasta djangoreactproject na raiz do seu projeto e execute o comando tree:

      • cd ~/djangoreactproject
      • tree

      Você verá o seguinte resultado:

      Output

      ├── djangoreactproject │ ├── __init__.py │ ├── settings.py │ ├── urls.py │ └── wsgi.py └── manage.py

      A pasta ~/djangoreactproject é a raiz do projeto. Dentro dessa pasta, há vários arquivos que serão importantes para seu trabalho:

      • manage.py: o script utilitário que faz uma série de tarefas administrativas.
      • settings.py: o arquivo de configuração principal para o projeto Django onde você pode modificar as configurações do projeto. Essas configurações incluem variáveis como INSTALLED_APPS, uma lista de strings que designam os aplicativos habilitados para seu projeto. A documentação do Django tem mais informações sobre as configurações disponíveis.
      • urls.py: este arquivo contém uma lista de padrões de URL e visualizações relacionadas. Cada padrão mapeia uma conexão entre um URL e a função que deve ser chamada para aquele URL. Para obter mais informações sobre URLs e visualizações, consulte nosso tutorial em Como Criar Visualizações no Django.

      Nosso primeiro passo no desenvolvimento do projeto será configurar os pacotes que instalamos no passo anterior, incluindo o Django REST framework e o pacote Django CORS, adicionando-os às settings.py. Abra o arquivo com o nano ou com o seu editor favorito:

      • nano ~/djangoreactproject/djangoreactproject/settings.py

      Navegue até a configuração INSTALLED_APPS e adicione os aplicativos rest_framework e corsheaders no final da lista:

      ~/djangoreactproject/djangoreactproject/settings.py

      ...
      INSTALLED_APPS = [
          'django.contrib.admin',
          'django.contrib.auth',
          'django.contrib.contenttypes',
          'django.contrib.sessions',
          'django.contrib.messages',
          'django.contrib.staticfiles',
          'rest_framework',
          'corsheaders'
      ]
      

      A seguir, adicione o middleware corsheaders.middleware.CorsMiddleware do pacote CORS previamente instalado para a configuração do MIDDLEWARE. Esta configuração é uma lista de middlewares, uma classe Python que contém códigos processados cada vez que seu aplicativo Web lida com uma solicitação ou resposta:

      ~/djangoreactproject/djangoreactproject/settings.py

      ...
      
      MIDDLEWARE = [
      ...
      'django.contrib.messages.middleware.MessageMiddleware',
      'django.middleware.clickjacking.XFrameOptionsMiddleware',
      'corsheaders.middleware.CorsMiddleware'
      ]
      

      A seguir, você pode habilitar o CORS. A configuração CORS_ORIGIN_ALLOW_ALL especifica se você quer ou não permitir o CORS para todos os domínios e aCORS_ORIGIN_WHITELISTé uma tupla Python que contém URLs permitidos. No nosso caso, uma vez que o servidor de desenvolvimento para React estará executando em http://lochhost:3000, vamos adicionar as novas configurações CORS_ORIGIN_ALLOW_ALL = False e CORS_ORIGIN_WHHELIST('localhost:3000',) ao nosso arquivo settings.py. Adicione essas configurações em qualquer lugar do arquivo:

      ~/djangoreactproject/djangoreactproject/settings.py

      
      ...
      CORS_ORIGIN_ALLOW_ALL = False
      
      CORS_ORIGIN_WHITELIST = (
             'localhost:3000',
      )
      ...
      

      Você pode encontrar mais opções de configuração nos django-cors-headers docs.

      Salve o arquivo e saia do editor quando você terminar.

      Ainda no diretório ~/djangoreactproject, faça um novo aplicativo Django chamado customers:

      • python manage.py startapp customers

      Isso irá conter os modelos e exibições para gerenciar clientes. Modelos (models) definem os campos e comportamentos dos dados do aplicativo, enquanto exibições (views) habilitam nosso aplicativo para lidar corretamente com solicitações Web e retornar as respostas necessárias.

      A seguir, adicione este aplicativo na lista de aplicativos instalados no arquivo do seu projeto settings.py para que o Django o reconheça como parte do projeto. Abra as settings.py novamente:

      • nano ~/djangoreactproject/djangoreactproject/settings.py

      Adicione o aplicativo customers:

      ~/djangoreactproject/djangoreactproject/settings.py

      ...
      INSTALLED_APPS = [
          ...
          'rest_framework',
          'corsheaders',
          'customers'
      ]
      ...
      

      A seguir, migre o banco de dados e inicie o servidor local de desenvolvimento. Migrações consistem no modo que o Django tem de propagar as alterações que você faz nos modelos do esquema do seu banco de dados. Essas alterações podem incluir coisas como adicionar um campo ou excluir um modelo, por exemplo. Para saber mais sobre modelos e migrações, consulte o tópico Como Criar Modelos do Django.

      Migre o banco de dados:

      Inicie o servidor local de desenvolvimento:

      • python manage.py runserver

      Você verá um resultado similar ao seguinte:

      Output

      Performing system checks... System check identified no issues (0 silenced). October 22, 2018 - 15:14:50 Django version 2.1.2, using settings 'djangoreactproject.settings' Starting development server at http://127.0.0.1:8000/ Quit the server with CONTROL-C.

      Seu aplicativo Web estará executando do endereço http://127.0.0.1:8000. Se você navegar até este endereço no seu navegador Web você verá a seguinte página:

      Django demo page

      Neste ponto, deixe o aplicativo funcionando e abra um novo terminal para continuar desenvolvendo o projeto.

      Passo 3 — Criando a Front-end React

      Nesta seção, vamos criar o aplicativo com front-end do nosso projeto usando o React.

      O React tem um utilitário oficial que permite que você crie rapidamente projetos React sem ter que configurar o Webpack diretamente. Webpack é um empacotador de módulos usado para empacotar ativos Web como o código JavaScript, CSS e imagens. Normalmente, antes de poder usar o Webpack você precisa definir várias opções de configuração, mas graças ao utilitário create-react-app você não precisa lidar com o Webpack diretamente até decidir que você precisa de mais controle. Para executar o create-react-app você pode usar o npx, uma ferramenta que executa pacotes npm binários.

      No seu segundo terminal, certifique-se de estar em seu diretório de projeto:

      Crie um projeto React chamado frontend usando o create-react-app e o npx:

      • npx create-react-app frontend

      A seguir, navegue dentro do seu aplicativo React e inicie o servidor de desenvolvimento:

      • cd ~/djangoreactproject/frontend
      • npm start

      Seu aplicativo estará executando a partir do endereço http://localhost:3000/:

      React demo page

      Deixe o servidor React de desenvolvimento funcionando e abra outra janela do terminal para prosseguir.

      Para ver a estrutura do diretório do projeto inteiro até o momento, navegue até a pasta raiz e execute novamente o tree:

      • cd ~/djangoreactproject
      • tree

      Você verá uma estrutura como essa:

      Output

      ├── customers │ ├── admin.py │ ├── apps.py │ ├── __init__.py │ ├── migrations │ │ └── __init__.py │ ├── models.py │ ├── tests.py │ └── views.py ├── djangoreactproject │ ├── __init__.py │ ├── __pycache__ │ ├── settings.py │ ├── urls.py │ └── wsgi.py ├── frontend │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ └── manifest.json │ ├── README.md │ ├── src │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── index.css │ │ ├── index.js │ │ ├── logo.svg │ │ └── registerServiceWorker.js │ └── yarn.lock └── manage.py

      Nosso aplicativo usará o Bootstrap 4 para estilizar a interface do React. Assim,nós o incluiremos no arquivo frontend/src/App.css, que gerencia nossas configurações CSS. Abra o arquivo:

      • nano ~/djangoreactproject/frontend/src/App.css

      Adicione o seguinte import ao início do arquivo. Você pode excluir o conteúdo do arquivo existente, embora isso não seja necessário:

      ~/djangoreactproject/frontend/src/App.css

      @import  'https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css';
      

      Aqui, @import é uma instrução CSS que é usada para importar regras de estilo de outras folhas de estilo.

      Agora que criamos os aplicativos com back-end e front-end, vamos criar o modelo Customer e alguns dados demonstrativos.

      Passo 4 — Criando o Modelo de Cliente e Dados Iniciais

      Após criar o aplicativo Django e o front-end React, nosso próximo passo será criar o modelo Customer, que representa a tabela do banco de dados que irá reter informações sobre os clientes. Você não precisa de nenhuma SQL (Structured Query Language, ou Linguagem de Consulta Estruturada), uma vez que o Object Relational Mapper (ORM) [Mapeamento Objeto-Relacional] do Django gerenciará as operações de banco de dados, mapeando as classes e variáveis em Python até as tabelas e colunas em SQL. Desta forma, o ORM do Django separa as interações em SQL com o banco de dados através de uma interface em Python.

      Ative seu ambiente virtual novamente:

      • cd ~
      • source env/bin/activate

      Vá até o diretório customers e abra o models.py, um arquivo Python que possui os modelos do seu aplicativo:

      • cd ~/djangoreactproject/customers/
      • nano models.py

      O arquivo terá o seguinte conteúdo:

      ~/djangoreactproject/customers/models.py

      from django.db import models
      # Create your models here.
      

      A API do modelo Customer já foi importada para o arquivo, graças à declaração de importação from django.db import models. Agora, você adicionará a classe Customer, que estende models.Model. Cada modelo no Django é uma classe em Python que estende o django.db.models.Model.

      O modelo Customer terá esses campos de banco de dados:

      • first_name — O primeiro nome do cliente.
      • last_name — O sobrenome do cliente.
      • email — O endereço de e-mail do cliente.
      • phone — O número de telefone do cliente.
      • address — O endereço do cliente.
      • description — A descrição do cliente.
      • createdAt — A data em que o cliente é adicionado.

      Também adicionaremos a função __str__(), que define como o modelo será exibido. No nosso caso, ela estará com o primeiro nome do cliente. Para saber mais sobre a construção de classes e definição de objetos, consulte o tópico pelo link How To Construct Classes and Define Objects in Python 3.

      Adicione o código a seguir ao arquivo:

      ~/djangoreactproject/customers/models.py

      from django.db import models
      
      class Customer(models.Model):
          first_name = models.CharField("First name", max_length=255)
          last_name = models.CharField("Last name", max_length=255)
          email = models.EmailField()
          phone = models.CharField(max_length=20)
          address =  models.TextField(blank=True, null=True)
          description = models.TextField(blank=True, null=True)
          createdAt = models.DateTimeField("Created At", auto_now_add=True)
      
          def __str__(self):
              return self.first_name
      

      A seguir, migre o banco de dados para criar as tabelas de banco de dados. O comando makemigrations cria os arquivos de migração onde as alterações do modelo serão adicionadas e o comando migrate aplica as alterações feitas nos arquivos de migrações ao banco de dados.

      Navegue novamente para a pasta raiz do projeto:

      Execute o que vem a seguir para criar os arquivos de migração:

      • python manage.py makemigrations

      Você receberá um resultado que se parece com este:

      Output

      customers/migrations/0001_initial.py - Create model Customer

      Aplique essas alterações ao banco de dados:

      Você verá o resultado indicando uma migração bem-sucedida:

      Output

      Operations to perform: Apply all migrations: admin, auth, contenttypes, customers, sessions Running migrations: Applying customers.0001_initial... OK

      Depois, você usará um arquivo de migração de dados para criar os dados iniciais do cliente. Um arquivo de migração de dados é uma migração que adiciona ou altera dados no banco de dados. Crie um arquivo de migração de dados vazio para o aplicativo customers:

      • python manage.py makemigrations --empty --name customers customers

      Você verá a seguinte confirmação com o nome do seu arquivo de migração:

      Output

      Migrations for 'customers': customers/migrations/0002_customers.py

      Note que o nome do seu arquivo de migração é 0002_customers.py.

      Na sequência, navegue dentro da pasta de migração do aplicativo customers:

      • cd ~/djangoreactproject/customers/migrations

      Abra o arquivo de migração criado:

      Este é o conteúdo inicial do arquivo:

      ~/djangoreactproject/customers/migrations/0002_customers.py

      from django.db import migrations
      
      class Migration(migrations.Migration):
          dependencies = [
              ('customers', '0001_initial'),
          ]
          operations = [
          ]        
      

      A instrução de importação importa a API migrations, uma API Django para criação de migrações, do django.db, um pacote integrado que contém classes para trabalhar com bancos de dados.

      A classe Migration é uma classe em Python que descreve as operações que são executadas durante a migração de bancos de dados. Esta classe estende migrations.Migration e tem duas listas:

      • dependencies: contém as migrações dependentes.
      • operations: contém as operações que serão executadas quando aplicarmos a migração.

      Na sequência, adicione um method para criar os dados de cliente da demonstração. Adicione o seguinte método antes da definição da classe Migration:

      ~/djangoreactproject/customers/migrations/0002_customers.py

      ...
      def create_data(apps, schema_editor):
          Customer = apps.get_model('customers', 'Customer')
          Customer(first_name="Customer 001", last_name="Customer 001", email="customer001@email.com", phone="00000000", address="Customer 000 Address", description= "Customer 001 description").save()
      
      ...
      

      Neste método, estamos pegando a classe Customer do nosso app customers e criando um cliente de demonstração para inserir no banco de dados.

      Para obter a classe Customer, que irá habilitar a criação de novos clientes, usamos o método get_model() do objeto apps. O objeto apps representa o registry dos aplicativos instalados e seus modelos de banco de dados.

      O objeto apps passará do método RunPython() quando o usamos para executar o create_data(). Adicione o método migrations.RunPython() à lista operations vazia:

      ~/djangoreactproject/customers/migrations/0002_customers.py

      
      ...
          operations = [
              migrations.RunPython(create_data),
          ]  
      

      O RunPython() faz parte da API com Migrations que permite que você execute códigos em Python personalizados em uma migração. Nossa lista operations especifica que este método será executado quando aplicarmos a migração.

      Este é o arquivo completo:

      ~/djangoreactproject/customers/migrations/0002_customers.py

      from django.db import migrations
      
      def create_data(apps, schema_editor):
          Customer = apps.get_model('customers', 'Customer')
          Customer(first_name="Customer 001", last_name="Customer 001", email="customer001@email.com", phone="00000000", address="Customer 000 Address", description= "Customer 001 description").save()
      
      class Migration(migrations.Migration):
          dependencies = [
              ('customers', '0001_initial'),
          ]
          operations = [
              migrations.RunPython(create_data),
          ]        
      

      Para obter mais informações sobre a migração de dados, consulte a documentação sobre migrações de dados no Django.

      Para migrar seu banco de dados, navegue primeiro de volta para a pasta raiz do seu projeto:

      Migre o seu banco de dados para criar os dados para demonstração:

      Você verá o resultado que confirma a migração:

      Output

      Operations to perform: Apply all migrations: admin, auth, contenttypes, customers, sessions Running migrations: Applying customers.0002_customers... OK

      Para obter mais detalhes sobre este processo, volte para o link How To Create Django Models.

      Com o modelo Customer e dados de demonstração criados, podemos continuar para a construção da API REST.

      Passo 5 — Criando a API REST

      Neste passo, vamos criar a API REST utilizando o Django REST Framework. Vamos criar várias *visualizações da API *diferentes. Uma visualização de API é uma função que lida com um pedido ou chamada de API, enquanto um *ponto de extremidade de API *é um URL único que representa um ponto de contato com o sistema REST. Por exemplo, quando o usuário envia um pedido GET para um ponto de extremidade de API, o Django chama a função correspondente ou a visualização de API para lidar com o pedido e retornar quaisquer resultados possíveis.

      Também vamos usar os serializers. Um serializador no Django REST Framework permite que as instâncias de modelos complexas e o QuerySets sejam convertidos em formato JSON para consumo de API. A classe de serializadores também pode funcionar na outra direção, fornecendo mecanismos para processar e desserializar dados em modelos Django e QuerySets.

      Nossos pontos de extremidade de API irão incluir:

      • api/customers: este ponto de extremidade é usado para criar clientes e retorna conjuntos de clientes paginados.
      • api/customers/<pk>: este ponto de extremidade é usado para obter, atualizar e excluir clientes únicos por chave ou ID primária.

      Também vamos criar URLs no arquivo urls.py do projeto para os pontos de extremidade correspondentes (ou seja, api/customers e <pk>).

      Vamos começar criando a classe de serializadores para nosso modelo Customer.

      Adicionando a Classe de Serializadores

      Criar uma classe de serializadores para nosso modelo Customer é necessário para transformar as instâncias de cliente e os QuerySets de e para JSON. Para criar a classe de serializadores, faça primeiro um arquivo serializers.py dentro do aplicativo customers:

      • cd ~/djangoreactproject/customers/
      • nano serializers.py

      Adicione o seguinte código para importar o API do serializador e o modelo Customer:

      ~/djangoreactproject/customers/serializers.py

      from rest_framework import serializers
      from .models import Customer
      

      A seguir, crie uma classe de serializadores que estende serializers.ModelSerializer e especifica os campos que serão serializados:

      ~/djangoreactproject/customers/serializers.py

      
      ...
      class CustomerSerializer(serializers.ModelSerializer):
      
          class Meta:
              model = Customer 
              fields = ('pk','first_name', 'last_name', 'email', 'phone','address','description')
      

      A classe Meta especifica o modelo e os campos para serializar: pk, first_name, last_name, email, phone, address, description.

      Este é o conteúdo completo do arquivo:

      ~/djangoreactproject/customers/serializers.py

      from rest_framework import serializers
      from .models import Customer
      
      class CustomerSerializer(serializers.ModelSerializer):
      
          class Meta:
              model = Customer 
              fields = ('pk','first_name', 'last_name', 'email', 'phone','address','description')
      

      Agora que criamos nossa classe de serializadores, podemos adicionar as visualizações da API.

      Adicionando as Visualizações da API

      Nesta seção, vamos criar as visualizações da API para nosso aplicativo que serão chamadas pelo Django quando o usuário visitar o ponto de extremidade correspondente à função da visualização.

      Abra ~/djangoreactproject/customers/views.py:

      • nano ~/djangoreactproject/customers/views.py

      Exclua o que estiver ali e adicione as seguintes importações:

      ~/djangoreactproject/customers/views.py

      from rest_framework.response import Response
      from rest_framework.decorators import api_view
      from rest_framework import status
      
      from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
      from .models import Customer 
      from .serializers import *
      

      Estamos importando o serializador que criamos, junto com o modelo Customer e as APIs com o Django e o Django REST Framework.

      Em seguida, adicione a visualização para processar os pedidos do POST e GET HTTP:

      ~/djangoreactproject/customers/views.py

      ...
      
      @api_view(['GET', 'POST'])
      def customers_list(request):
          """
       List  customers, or create a new customer.
       """
          if request.method == 'GET':
              data = []
              nextPage = 1
              previousPage = 1
              customers = Customer.objects.all()
              page = request.GET.get('page', 1)
              paginator = Paginator(customers, 10)
              try:
                  data = paginator.page(page)
              except PageNotAnInteger:
                  data = paginator.page(1)
              except EmptyPage:
                  data = paginator.page(paginator.num_pages)
      
              serializer = CustomerSerializer(data,context={'request': request} ,many=True)
              if data.has_next():
                  nextPage = data.next_page_number()
              if data.has_previous():
                  previousPage = data.previous_page_number()
      
              return Response({'data': serializer.data , 'count': paginator.count, 'numpages' : paginator.num_pages, 'nextlink': '/api/customers/?page=' + str(nextPage), 'prevlink': '/api/customers/?page=' + str(previousPage)})
      
          elif request.method == 'POST':
              serializer = CustomerSerializer(data=request.data)
              if serializer.is_valid():
                  serializer.save()
                  return Response(serializer.data, status=status.HTTP_201_CREATED)
              return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
      

      Primeiramente, usamos o decorador @api_view(['GET', 'POST']) para criar uma visualização de API que possa aceitar solicitações GET e POST. Um decorator é uma função que assume outra função e a amplia de maneira dinâmica.

      No corpo do método, utilizamos a variável request.method para verificar o método HTTP atual e executar a lógica correspondente, dependendo do tipo de solicitação:

      • Se for uma solicitação GET, o método pagina os dados utilizando o Paginator do Django e retorna a primeira página de dados após a serialização, a contagem de clientes disponíveis, o número de páginas disponíveis, e os links para as páginas anteriores e as páginas posteriores. O Paginator é uma classe integrada do Django que organiza uma lista de dados em páginas e proporciona métodos para acessar os itens de cada página.
      • Se for uma solicitação POST, o método serializa os dados recebidos do cliente e chama então o método save() do objeto serializador. Então, ele retorna um objeto de Resposta, uma instância do HttpResponse, com um código de status 201. Cada visualização que você cria é responsável por retornar um objeto HttpResponse. O método save() salva os dados serializados no banco de dados.

      Para saber mais sobre HttpResponse e visualizações, leia esta discussão: creating view functions.

      Agora, adicione a visualização de API que será responsável por processar os pedidos GET, PUT e DELETE para obter, atualizar e excluir clientes por pk (chave primária):

      ~/djangoreactproject/customers/views.py

      
      ...
      @api_view(['GET', 'PUT', 'DELETE'])
      def customers_detail(request, pk):
       """
       Retrieve, update or delete a customer by id/pk.
       """
          try:
              customer = Customer.objects.get(pk=pk)
          except Customer.DoesNotExist:
              return Response(status=status.HTTP_404_NOT_FOUND)
      
          if request.method == 'GET':
              serializer = CustomerSerializer(customer,context={'request': request})
              return Response(serializer.data)
      
          elif request.method == 'PUT':
              serializer = CustomerSerializer(customer, data=request.data,context={'request': request})
              if serializer.is_valid():
                  serializer.save()
                  return Response(serializer.data)
              return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
      
          elif request.method == 'DELETE':
              customer.delete()
              return Response(status=status.HTTP_204_NO_CONTENT)
      

      O método é decorado com @api_view(['GET', 'PUT', 'DELETE']) para indicara que se trata de uma visualização de API que pode aceitar solicitações GET, PUT e DELETE.

      A checagem no campo request.method verifica o método de solicitação e, dependendo do seu valor, chama a lógica correta:

      • Se for um pedido GET, os dados do cliente são serializados e enviados utilizando um objeto de Resposta.
      • Se for um pedido PUT, o método cria um serializador para novos dados do cliente. Em seguida, ele chama o método save() do objeto serializador criado. Finalmente, ele envia um objeto de Resposta com o cliente atualizado.
      • Se for um pedido DELETE, o método chama o método delete() do objeto cliente a excluir; depois, retorna um objeto de Resposta sem dados.

      O arquivo final se parece com este:

      ~/djangoreactproject/customers/views.py

      from rest_framework.response import Response
      from rest_framework.decorators import api_view
      from rest_framework import status
      
      from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
      from .models import Customer 
      from .serializers import *
      
      
      @api_view(['GET', 'POST'])
      def customers_list(request):
          """
       List  customers, or create a new customer.
       """
          if request.method == 'GET':
              data = []
              nextPage = 1
              previousPage = 1
              customers = Customer.objects.all()
              page = request.GET.get('page', 1)
              paginator = Paginator(customers, 5)
              try:
                  data = paginator.page(page)
              except PageNotAnInteger:
                  data = paginator.page(1)
              except EmptyPage:
                  data = paginator.page(paginator.num_pages)
      
              serializer = CustomerSerializer(data,context={'request': request} ,many=True)
              if data.has_next():
                  nextPage = data.next_page_number()
              if data.has_previous():
                  previousPage = data.previous_page_number()
      
              return Response({'data': serializer.data , 'count': paginator.count, 'numpages' : paginator.num_pages, 'nextlink': '/api/customers/?page=' + str(nextPage), 'prevlink': '/api/customers/?page=' + str(previousPage)})
      
          elif request.method == 'POST':
              serializer = CustomerSerializer(data=request.data)
              if serializer.is_valid():
                  serializer.save()
                  return Response(serializer.data, status=status.HTTP_201_CREATED)
              return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
      
      @api_view(['GET', 'PUT', 'DELETE'])
      def customers_detail(request, pk):
          """
       Retrieve, update or delete a customer by id/pk.
       """
          try:
              customer = Customer.objects.get(pk=pk)
          except Customer.DoesNotExist:
              return Response(status=status.HTTP_404_NOT_FOUND)
      
          if request.method == 'GET':
              serializer = CustomerSerializer(customer,context={'request': request})
              return Response(serializer.data)
      
          elif request.method == 'PUT':
              serializer = CustomerSerializer(customer, data=request.data,context={'request': request})
              if serializer.is_valid():
                  serializer.save()
                  return Response(serializer.data)
              return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
      
          elif request.method == 'DELETE':
              customer.delete()
              return Response(status=status.HTTP_204_NO_CONTENT)
      

      Agora, podemos seguir em frente para criar nossos pontos de extremidade.

      Adicionando Pontos de extremidade de API

      Agora, vamos criar os pontos de extremidade de API: api/customers/, para consultar e criar clientes e api/customers/<pk>, para obter, atualizar ou excluir clientes únicos por pk.

      Abra ~/djangoreactproject/djangoreactproject/urls.py:

      • nano ~/djangoreactproject/djangoreactproject/urls.py

      Deixe o que está lá, mas adicione a importação às visualizações do customers no topo do arquivo:

      ~/djangoreactproject/djangoreactproject/urls.py

      from django.contrib import admin
      from django.urls import path
      from customers import views
      from django.conf.urls import url
      

      Em seguida, adicione os URLs api/customers/ e api/customers/<pk> à lista urlpatterns que contém os URLs do aplicativo:

      ~/djangoreactproject/djangoreactproject/urls.py

      ...
      
      urlpatterns = [
          path('admin/', admin.site.urls),
          url(r'^api/customers/$', views.customers_list),
          url(r'^api/customers/(?P<pk>[0-9]+)$', views.customers_detail),
      ]
      

      Com nossos pontos de extremidade de REST criados, vamos ver como podemos consumi-los.

      Neste passo, vamos instalar o Axios, o cliente HTTP que vamos usar para fazer chamadas de API. Também vamos criar uma classe para consumir os pontos de extremidade da API que criamos.

      Primeiramente, desative o seu ambiente virtual:

      Em seguida, navegue até sua pasta frontend:

      • cd ~/djangoreactproject/frontend

      Instale o axios a partir do npm utilizando:

      A opção --save adiciona a dependência do axios ao arquivo package.json do seu aplicativo.

      Em seguida, crie um arquivo JavaScript chamado CustomersService.js, que irá conter o código para chamar as APIs REST. Vamos fazer isso dentro da pasta src, onde o código do aplicativo para nosso projeto irá viver:

      • cd src
      • nano CustomersService.js

      Adicione o seguinte código, que contém métodos para se conectar à API REST do Django:

      ~/djangoreactproject/frontend/src/CustomersService.js

      import axios from 'axios';
      const API_URL = 'http://localhost:8000';
      
      export default class CustomersService{
      
          constructor(){}
      
      
          getCustomers() {
              const url = `${API_URL}/api/customers/`;
              return axios.get(url).then(response => response.data);
          }  
          getCustomersByURL(link){
              const url = `${API_URL}${link}`;
              return axios.get(url).then(response => response.data);
          }
          getCustomer(pk) {
              const url = `${API_URL}/api/customers/${pk}`;
              return axios.get(url).then(response => response.data);
          }
          deleteCustomer(customer){
              const url = `${API_URL}/api/customers/${customer.pk}`;
              return axios.delete(url);
          }
          createCustomer(customer){
              const url = `${API_URL}/api/customers/`;
              return axios.post(url,customer);
          }
          updateCustomer(customer){
              const url = `${API_URL}/api/customers/${customer.pk}`;
              return axios.put(url,customer);
          }
      }
      

      A classe CustomersService irá chamar os seguintes métodos do Axios:

      • getCustomers(): obtém a primeira página de clientes.
      • getCustomersByURL(): obtém clientes por URL. Isso possibilita obter-se as próximas páginas de clientes, atravessando-se links do tipo /api/customers/?page=2.
      • getCustomer(): obtém um cliente pela chave primária.
      • createCustomer(): cria um cliente.
      • updateCustomer(): atualiza um cliente.
      • deleteCustomer(): exclui um cliente.

      Agora, podemos exibir os dados de nossa API na nossa interface com a UI React criando um componente CustomersList.

      Passo 7 — Exibindo Dados da API no Aplicativo React

      Neste passo, vamos criar o componente do aplicativo React chamado CustomersList. Um componente do React representa uma parte da UI; ele também permite que você divida a UI em pedaços independentes e reutilizáveis.

      Inicie criando o CustomersList.js em frontend/src:

      • nano ~/djangoreactproject/frontend/src/CustomersList.js

      Inicie importando o React e o Component para criar um componente do React:

      ~/djangoreactproject/frontend/src/CustomersList.js

      import  React, { Component } from  'react';
      

      Em seguida, importe e crie a instância do módulo CustomersService que você criou no passo anterior, que proporciona métodos que interagem com o back-end da API REST:

      ~/djangoreactproject/frontend/src/CustomersList.js

      
      ...
      import  CustomersService  from  './CustomersService';
      
      const  customersService  =  new  CustomersService();
      

      Em seguida, crie um componente CustomersList que estende o Component para chamar a API REST. Um componente React deve estender ou subclassificar a classe Component. Para saber mais sobre as classes E6 e herança, consulte nossos tutorial Understanding Classes in JavaScript.

      Adicione o seguinte código para criar um componente do React que estende o react.Component:

      ~/djangoreactproject/frontend/src/CustomersList.js

      
      ...
      class  CustomersList  extends  Component {
      
          constructor(props) {
              super(props);
              this.state  = {
                  customers: [],
                  nextPageURL:  ''
              };
              this.nextPage  =  this.nextPage.bind(this);
              this.handleDelete  =  this.handleDelete.bind(this);
          }
      }
      export  default  CustomersList;
      

      Dentro do construtor, estamos inicializando o objeto de ](https://reactjs.org/docs/react-component.html#state)estado[. Isso mantém as variáveis de estado do nosso componente utilizando uma matriz de clientes vazia. Esta matriz conterá os clientes e um nextPageURL que irá reter o URL da próxima página a ser recuperada do back-end da API. Também estamos ligando os métodos nextPage() e o handleDelete() a este para que eles fiquem acessíveis a partir do código HTML.

      Em seguida, adicione o método componentDidMount() e uma chamada para o getCustomers() dentro da classe CustomersList, antes da chave de fechamento.

      O método componentDidMount() é um método de ciclo de vida do componente que é chamado quando o componente é criado e inserido no DOM. O getCustomers() chama o objeto Customers Service para obter a primeira página de dados e o link da página seguinte a partir do back-end do Django:

      ~/djangoreactproject/frontend/src/CustomersList.js

      
      ...
      componentDidMount() {
          var  self  =  this;
          customersService.getCustomers().then(function (result) {
              self.setState({ customers:  result.data, nextPageURL:  result.nextlink})
          });
      }
      

      Agora, adicione o método handleDelete() que lida com a exclusão de um cliente, abaixo do componentDidMount():

      ~/djangoreactproject/frontend/src/CustomersList.js

      
      ...
      handleDelete(e,pk){
          var  self  =  this;
          customersService.deleteCustomer({pk :  pk}).then(()=>{
              var  newArr  =  self.state.customers.filter(function(obj) {
                  return  obj.pk  !==  pk;
              });
              self.setState({customers:  newArr})
          });
      }
      

      O método handleDelete() chama o método deleteCustomer() para excluir um cliente utilizando sua pk (chave primária). Se a operação for bem-sucedida, a matriz de customers é filtrada em relação ao cliente removido.

      Em seguida, adicione um método nextPage() para obter os dados da próxima página e atualize o próximo link da página:

      ~/djangoreactproject/frontend/src/CustomersList.js

      
      ...
      nextPage(){
          var  self  =  this;
          customersService.getCustomersByURL(this.state.nextPageURL).then((result) => {
              self.setState({ customers:  result.data, nextPageURL:  result.nextlink})
          });
      }
      

      O método nextPage() chama um método getCustomersByURL(), que recebe o próximo URL da página do objeto de estado, this.state.nextPageURL​​​ e atualiza a matriz de customers com os dados retornados.

      Finalmente, adicione o método render() do componente, que renderiza uma tabela de clientes a partir do estado do componente:

      ~/djangoreactproject/frontend/src/CustomersList.js

      
      ...
      render() {
      
          return (
          <div  className="customers--list">
              <table  className="table">
                  <thead  key="thead">
                  <tr>
                      <th>#</th>
                      <th>First Name</th>
                      <th>Last Name</th>
                      <th>Phone</th>
                      <th>Email</th>
                      <th>Address</th>
                      <th>Description</th>
                      <th>Actions</th>
                  </tr>
                  </thead>
                  <tbody>
                      {this.state.customers.map( c  =>
                      <tr  key={c.pk}>
                          <td>{c.pk}  </td>
                          <td>{c.first_name}</td>
                          <td>{c.last_name}</td>
                          <td>{c.phone}</td>
                          <td>{c.email}</td>
                          <td>{c.address}</td>
                          <td>{c.description}</td>
                          <td>
                          <button  onClick={(e)=>  this.handleDelete(e,c.pk) }> Delete</button>
                          <a  href={"/customer/" + c.pk}> Update</a>
                          </td>
                      </tr>)}
                  </tbody>
              </table>
              <button  className="btn btn-primary"  onClick=  {  this.nextPage  }>Next</button>
          </div>
          );
      }
      

      Este é o conteúdo completo do arquivo:

      ~/djangoreactproject/frontend/src/CustomersList.js

      import  React, { Component } from  'react';
      import  CustomersService  from  './CustomersService';
      
      const  customersService  =  new  CustomersService();
      
      class  CustomersList  extends  Component {
      
      constructor(props) {
          super(props);
          this.state  = {
              customers: [],
              nextPageURL:  ''
          };
          this.nextPage  =  this.nextPage.bind(this);
          this.handleDelete  =  this.handleDelete.bind(this);
      }
      
      componentDidMount() {
          var  self  =  this;
          customersService.getCustomers().then(function (result) {
              console.log(result);
              self.setState({ customers:  result.data, nextPageURL:  result.nextlink})
          });
      }
      handleDelete(e,pk){
          var  self  =  this;
          customersService.deleteCustomer({pk :  pk}).then(()=>{
              var  newArr  =  self.state.customers.filter(function(obj) {
                  return  obj.pk  !==  pk;
              });
      
              self.setState({customers:  newArr})
          });
      }
      
      nextPage(){
          var  self  =  this;
          console.log(this.state.nextPageURL);        
          customersService.getCustomersByURL(this.state.nextPageURL).then((result) => {
              self.setState({ customers:  result.data, nextPageURL:  result.nextlink})
          });
      }
      render() {
      
          return (
              <div  className="customers--list">
                  <table  className="table">
                  <thead  key="thead">
                  <tr>
                      <th>#</th>
                      <th>First Name</th>
                      <th>Last Name</th>
                      <th>Phone</th>
                      <th>Email</th>
                      <th>Address</th>
                      <th>Description</th>
                      <th>Actions</th>
                  </tr>
                  </thead>
                  <tbody>
                  {this.state.customers.map( c  =>
                      <tr  key={c.pk}>
                      <td>{c.pk}  </td>
                      <td>{c.first_name}</td>
                      <td>{c.last_name}</td>
                      <td>{c.phone}</td>
                      <td>{c.email}</td>
                      <td>{c.address}</td>
                      <td>{c.description}</td>
                      <td>
                      <button  onClick={(e)=>  this.handleDelete(e,c.pk) }> Delete</button>
                      <a  href={"/customer/" + c.pk}> Update</a>
                      </td>
                  </tr>)}
                  </tbody>
                  </table>
                  <button  className="btn btn-primary"  onClick=  {  this.nextPage  }>Next</button>
              </div>
              );
        }
      }
      export  default  CustomersList;
      

      Agora que criamos o componente CustomersList para exibir a lista de clientes, podemos adicionar o componente que lida com a criação e as atualizações do cliente.

      Passo 8 — Adicionando os Componentes Customer Create e Update do React

      Neste passo, vamos criar o componente CustomerCreateUpdate que irá lidar com a criação e atualização dos clientes. Ele irá fazer isso fornecendo um formulário que os usuários podem usar para digitar dados sobre um novo cliente ou atualizar um item existente.

      No frontend/src, crie um arquivo CustomerCreateUpdate.js:

      • nano ~/djangoreactproject/frontend/src/CustomerCreateUpdate.js

      Adicione o seguinte código para criar um componente do React, import o React e o Component:

      ~/djangoreactproject/frontend/src/CustomerCreateUpdate.js

      import  React, { Component } from  'react';
      

      Além disso, podemos importar e instanciar a classe CustomersService que criamos no passo anterior, a qual proporciona métodos que interagem com o back-end da API REST:

      ~/djangoreactproject/frontend/src/CustomerCreateUpdate.js

      ...
      import  CustomersService  from  './CustomersService';
      
      const  customersService  =  new  CustomersService();
      

      Em seguida, crie um componente CustomerCreateUpdate que estende o Component para criar e atualizar os clientes:

      ~/djangoreactproject/frontend/src/CustomerCreateUpdate.js

      
      ...
      class  CustomerCreateUpdate  extends  Component {
      
          constructor(props) {
              super(props);
          }
      
      }
      export default CustomerCreateUpdate;
      

      Dentro da definição da classe, adicione o método render() do componente, que renderiza uma forma HTML que recebe informações sobre o cliente:

      ~/djangoreactproject/frontend/src/CustomerCreateUpdate.js

      
      ...
      render() {
              return (
                <form onSubmit={this.handleSubmit}>
                <div className="form-group">
                  <label>
                    First Name:</label>
                    <input className="form-control" type="text" ref='firstName' />
      
                  <label>
                    Last Name:</label>
                    <input className="form-control" type="text" ref='lastName'/>
      
                  <label>
                    Phone:</label>
                    <input className="form-control" type="text" ref='phone' />
      
                  <label>
                    Email:</label>
                    <input className="form-control" type="text" ref='email' />
      
                  <label>
                    Address:</label>
                    <input className="form-control" type="text" ref='address' />
      
                  <label>
                    Description:</label>
                    <textarea className="form-control" ref='description' ></textarea>
      
      
                  <input className="btn btn-primary" type="submit" value="Submit" />
                  </div>
                </form>
              );
        }
      

      Para cada elemento form input, o método adiciona uma propriedade ref para acessar e definir o valor do elemento do formulário.

      Em seguida, acima do método render(), defina um método handleSubmit(event) para que você tenha a funcionalidade apropriada quando um usuário clicar no botão para enviar:

      ~/djangoreactproject/frontend/src/CustomerCreateUpdate.js

      
      ...
      handleSubmit(event) {
          const { match: { params } } =  this.props;
          if(params  &&  params.pk){
              this.handleUpdate(params.pk);
          }
          else
          {
              this.handleCreate();
          }
          event.preventDefault();
      }
      
      ...
      

      O método handleSubmit(event) cuida do envio do formulário e, dependendo da rota, chama o método handleUpdate(pk) para atualizar o cliente com o método pk aprovado ou o método handleCreate() para criar um novo cliente. Vamos definir esses métodos em breve.

      De volta ao construtor do componente, conecte o método handleSubmit() recém-adicionado a este, para que você possa acessá-lo em seu formulário:

      ~/djangoreactproject/frontend/src/CustomerCreateUpdate.js

      ...
      class CustomerCreateUpdate extends Component {
      
      constructor(props) {
          super(props);
          this.handleSubmit = this.handleSubmit.bind(this);
      }
      ...
      

      Em seguida, defina o método handleCreate() para criar um cliente a partir dos dados do formulário. Acima do método handleSubmit(event) adicione o seguinte código:

      ~/djangoreactproject/frontend/src/CustomerCreateUpdate.js

      
      ...
      handleCreate(){
          customersService.createCustomer(
              {
              "first_name":  this.refs.firstName.value,
              "last_name":  this.refs.lastName.value,
              "email":  this.refs.email.value,
              "phone":  this.refs.phone.value,
              "address":  this.refs.address.value,
              "description":  this.refs.description.value
              }).then((result)=>{
                      alert("Customer created!");
              }).catch(()=>{
                      alert('There was an error! Please re-check your form.');
              });
      }
      
      ...
      

      O método handleCreate() será usado para criar um cliente a partir dos dados inseridos. Ele chama o método CustomersService.createCustomer() correspondente que faz a API real chamar o back-end para criar um cliente.

      Depois, abaixo do método handleCreate(), defina o método handleUpdate(pk) para implementar as atualizações:

      ~/djangoreactproject/frontend/src/CustomerCreateUpdate.js

      
      ...
      handleUpdate(pk){
      customersService.updateCustomer(
          {
          "pk":  pk,
          "first_name":  this.refs.firstName.value,
          "last_name":  this.refs.lastName.value,
          "email":  this.refs.email.value,
          "phone":  this.refs.phone.value,
          "address":  this.refs.address.value,
          "description":  this.refs.description.value
          }
          ).then((result)=>{
      
              alert("Customer updated!");
          }).catch(()=>{
              alert('There was an error! Please re-check your form.');
          });
      }
      

      O método updateCustomer() irá atualizar um cliente através da pk utilizando as novas informações do formulário de informações do cliente. Ele chama o método customersService.updateCustomer().

      Em seguida, adicione um método componentDidMount(). Se o usuário visitar uma rota customer/:pk, queremos preencher o formulário com informações relacionadas ao cliente, utilizando a chave primária do URL. Para fazer isso, podemos adicionar o método getCustomer(pk) após o componente ser montado no evento do ciclo de vida do componentDidMount(). Adicione o seguinte código abaixo do construtor do componente para adicionar este método:

      ~/djangoreactproject/frontend/src/CustomerCreateUpdate.js

      
      ...
      componentDidMount(){
          const { match: { params } } =  this.props;
          if(params  &&  params.pk)
          {
              customersService.getCustomer(params.pk).then((c)=>{
                  this.refs.firstName.value  =  c.first_name;
                  this.refs.lastName.value  =  c.last_name;
                  this.refs.email.value  =  c.email;
                  this.refs.phone.value  =  c.phone;
                  this.refs.address.value  =  c.address;
                  this.refs.description.value  =  c.description;
              })
          }
      }
      

      Este é o conteúdo completo do arquivo:

      ~/djangoreactproject/frontend/src/CustomerCreateUpdate.js

      import React, { Component } from 'react';
      import CustomersService from './CustomersService';
      
      const customersService = new CustomersService();
      
      class CustomerCreateUpdate extends Component {
          constructor(props) {
              super(props);
      
              this.handleSubmit = this.handleSubmit.bind(this);
            }
      
            componentDidMount(){
              const { match: { params } } = this.props;
              if(params && params.pk)
              {
                customersService.getCustomer(params.pk).then((c)=>{
                  this.refs.firstName.value = c.first_name;
                  this.refs.lastName.value = c.last_name;
                  this.refs.email.value = c.email;
                  this.refs.phone.value = c.phone;
                  this.refs.address.value = c.address;
                  this.refs.description.value = c.description;
                })
              }
            }
      
            handleCreate(){
              customersService.createCustomer(
                {
                  "first_name": this.refs.firstName.value,
                  "last_name": this.refs.lastName.value,
                  "email": this.refs.email.value,
                  "phone": this.refs.phone.value,
                  "address": this.refs.address.value,
                  "description": this.refs.description.value
              }          
              ).then((result)=>{
                alert("Customer created!");
              }).catch(()=>{
                alert('There was an error! Please re-check your form.');
              });
            }
            handleUpdate(pk){
              customersService.updateCustomer(
                {
                  "pk": pk,
                  "first_name": this.refs.firstName.value,
                  "last_name": this.refs.lastName.value,
                  "email": this.refs.email.value,
                  "phone": this.refs.phone.value,
                  "address": this.refs.address.value,
                  "description": this.refs.description.value
              }          
              ).then((result)=>{
                console.log(result);
                alert("Customer updated!");
              }).catch(()=>{
                alert('There was an error! Please re-check your form.');
              });
            }
            handleSubmit(event) {
              const { match: { params } } = this.props;
      
              if(params && params.pk){
                this.handleUpdate(params.pk);
              }
              else
              {
                this.handleCreate();
              }
      
              event.preventDefault();
            }
      
            render() {
              return (
                <form onSubmit={this.handleSubmit}>
                <div className="form-group">
                  <label>
                    First Name:</label>
                    <input className="form-control" type="text" ref='firstName' />
      
                  <label>
                    Last Name:</label>
                    <input className="form-control" type="text" ref='lastName'/>
      
                  <label>
                    Phone:</label>
                    <input className="form-control" type="text" ref='phone' />
      
                  <label>
                    Email:</label>
                    <input className="form-control" type="text" ref='email' />
      
                  <label>
                    Address:</label>
                    <input className="form-control" type="text" ref='address' />
      
                  <label>
                    Description:</label>
                    <textarea className="form-control" ref='description' ></textarea>
      
      
                  <input className="btn btn-primary" type="submit" value="Submit" />
                  </div>
                </form>
              );
            }  
      }
      
      export default CustomerCreateUpdate;
      

      Com o componente CustomerCreateUpdate criado, podemos atualizar o componente principal do App para adicionar links aos diferentes componentes que criamos.

      Passo 9 — Atualizando o Componente Principal do App

      Nesta seção, atualizaremos o componente App do nosso aplicativo para criar links para os componentes que criamos nos passos anteriores.

      A partir da pasta frontend, execute o seguinte comando para instalar o React Router, que permite que você adicione roteamento e navegação entre vários componentes do React:

      • cd ~/djangoreactproject/frontend
      • npm install --save react-router-dom

      Em seguida, abra ~/djangoreactproject/frontend/src/App.js:

      • nano ~/djangoreactproject/frontend/src/App.js

      Exclua tudo o que está lá e adicione o seguinte código para importar as classes necessárias para adicionar roteamentos. Esses incluem o BrowserRouter, que cria um componente Router e o Route, que cria um componente de rota:

      ~/djangoreactproject/frontend/src/App.js

      import  React, { Component } from  'react';
      import { BrowserRouter } from  'react-router-dom'
      import { Route, Link } from  'react-router-dom'
      import  CustomersList  from  './CustomersList'
      import  CustomerCreateUpdate  from  './CustomerCreateUpdate'
      import  './App.css';
      

      O BrowserRoutermantém a UI em sincronia com o URL utilizando a API de histórico HTML5.

      Na sequência, crie um layout básico que fornece o componente base a ser encapsulado pelo componente BrowserRouter:

      ~/djangoreactproject/frontend/src/App.js

      ...
      
      const  BaseLayout  = () => (
      <div  className="container-fluid">
          <nav  className="navbar navbar-expand-lg navbar-light bg-light">
              <a  className="navbar-brand"  href="https://www.digitalocean.com/#">Django React Demo</a>
              <button  className="navbar-toggler"  type="button"  data-toggle="collapse"  data-target="#navbarNavAltMarkup"  aria-controls="navbarNavAltMarkup"  aria-expanded="false"  aria-label="Toggle navigation">
              <span  className="navbar-toggler-icon"></span>
          </button>
          <div  className="collapse navbar-collapse"  id="navbarNavAltMarkup">
              <div  className="navbar-nav">
                  <a  className="nav-item nav-link"  href="/">CUSTOMERS</a>
                  <a  className="nav-item nav-link"  href="http://www.digitalocean.com/customer">CREATE CUSTOMER</a>
              </div>
          </div>
          </nav>
          <div  className="content">
              <Route  path="/"  exact  component={CustomersList}  />
              <Route  path="/customer/:pk"  component={CustomerCreateUpdate}  />
              <Route  path="/customer/"  exact  component={CustomerCreateUpdate}  />
          </div>
      </div>
      )
      

      Usamos o componente Route para definir as rotas do nosso aplicativo; o componente que o roteador deve carregar tão logo encontre um que seja compatível. Cada rota precisa de um path para especificar o caminho compatível e de um component para especificar o componente a carregar. A propriedade exact diz ao roteador para corresponder ao caminho exato.

      Finalmente, crie o componente App, o componente root ou o componente de nível superior do nosso aplicativo React:

      ~/djangoreactproject/frontend/src/App.js

      ...
      
      class  App  extends  Component {
      
      render() {
          return (
          <BrowserRouter>
              <BaseLayout/>
          </BrowserRouter>
          );
      }
      }
      export  default  App;
      

      Nós juntamos o componente BaseLayout ao componente BrowserRouter, uma vez que o nosso app deverá ser executado no navegador.

      O arquivo final se parece com este:

      ~/djangoreactproject/frontend/src/App.js

      import React, { Component } from 'react';
      import { BrowserRouter } from 'react-router-dom'
      import { Route, Link } from 'react-router-dom'
      
      import  CustomersList from './CustomersList'
      import  CustomerCreateUpdate  from './CustomerCreateUpdate'
      import './App.css';
      
      const BaseLayout = () => (
        <div className="container-fluid">
      <nav className="navbar navbar-expand-lg navbar-light bg-light">
        <a className="navbar-brand" href="https://www.digitalocean.com/#">Django React Demo</a>
        <button className="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavAltMarkup" aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation">
          <span className="navbar-toggler-icon"></span>
        </button>
        <div className="collapse navbar-collapse" id="navbarNavAltMarkup">
          <div className="navbar-nav">
            <a className="nav-item nav-link" href="/">CUSTOMERS</a>
            <a className="nav-item nav-link" href="http://www.digitalocean.com/customer">CREATE CUSTOMER</a>
      
          </div>
        </div>
      </nav>  
      
          <div className="content">
            <Route path="/" exact component={CustomersList} />
            <Route path="/customer/:pk"  component={CustomerCreateUpdate} />
            <Route path="/customer/" exact component={CustomerCreateUpdate} />
      
          </div>
      
        </div>
      )
      
      class App extends Component {
        render() {
          return (
            <BrowserRouter>
              <BaseLayout/>
            </BrowserRouter>
          );
        }
      }
      
      export default App;
      

      Após adicionar o roteamento ao nosso aplicativo, estamos agora prontos para testar o aplicativo. Navegue até o endereço http://localhost:3000. Você deve ver a primeira página do aplicativo:

      Application Home Page

      Com este aplicativo em funcionamento, agora você tem a base de um aplicativo de CRM.

      Conclusão

      Neste tutorial, você criou um aplicativo de demonstração utilizando o Django e o React. Você usou Django REST framework para construir a API REST, o Axios para consumir a API, e o Bootstrap 4 para estilizar o seu CSS. Você pode encontrar o código-fonte deste projeto neste repositório do GitHub.

      Esta configuração de tutorial usou apps separados de front-end e back-end. Para obter uma abordagem diferente para integrar o React ao Django, verifique este tutorial e este tutorial.

      Para saber mais sobre a construção de um aplicativo com o Django, você pode seguir as séries de desenvolvimento do Django. Você também pode considerar os documentos oficiais do Django.



      Source link

      Cómo crear una aplicación web moderna para gestionar la información de clientes con Django y React on Ubuntu 18.04


      El autor seleccionó Open Sourcing Mental Illness Ltd para recibir una donación como parte del programa Write for Donations.

      Introducción

      Las personas utilizan diferentes tipos de dispositivos para conectarse a internet y navegar por la Web. Debido a esto, las aplicaciones deben ser accesibles desde varios lugares. Para los sitios web tradicionales, tener una IU receptiva suele ser suficiente, pero las aplicaciones más complejas suelen requerir el uso de otras técnicas y arquitecturas. Entre ellas se contempla tener aplicaciones back-end y front-end REST independientes que puedan implementarse como aplicaciones web para el cliente, aplicaciones web progresivas (PWA) o aplicaciones móviles nativas.

      Algunas herramientas que puede utilizar al crear aplicaciones más complejas incluyen:

      • React, un marco de trabajo de JavaScript que permite a los desarrolladores crear frontends web y nativos para sus backend de API REST.
      • Django, una estructura web de Python gratuita y de código abierto que sigue el patrón de arquitectura del software de modelo vista controlador (MVC).
      • Django REST framework, un conjunto de herramientas potentes y flexibles para el desarrollo de REST APIs en Django.

      En este tutorial, usted creará una aplicación web moderna con un backend REST API independiente y un frontend utilizando React, Django y Django REST Framework. Al utilizar React con Django, podrá beneficiarse de los últimos avances en el desarrollo de JavaScript y front-end. En lugar de crear una aplicación de Django que utilice un motor de plantillas incorporado, usted utilizará React como biblioteca de IU, aprovechando su enfoque virtual de Modelo de objetos de documentos (DOM), enfoque declarativo y componentes que rápidamente reproduzcan cambios en los datos.

      La aplicación web que usted creará almacena registros sobre clientes en una base de datos, y puede utilizarlo como punto de partida para una aplicación CRM. Cuando haya terminado, podrá crear, leer, actualizar y borrar registros utilizando una interfaz React de estilo Bootstrap 4.

      Requisitos previos

      Para completar este tutorial, necesitará lo siguiente:

      Paso 1: Creación de un entorno virtual de Python e instalación de dependencias

      En este paso, crearemos un entorno virtual e instalaremos las dependencias necesarias para nuestra aplicación, entre ellas, Django, Django REST framework y django-cors-headers.

      Nuestra aplicación utilizará dos servidores de desarrollo distintos para Django y React. Se ejecutarán en diferentes puertos y funcionarán como dos dominios separados. Debido a esto, debemos permitir el intercambio de recursos de origen cruzado (CORS) para enviar solicitudes HTTP desde React a Django sin que el navegador pueda bloquearlos.

      Navegue a su directorio principal y cree un entorno virtual utilizando el módulo venv Python 3:

      • cd ~
      • python3 -m venv ./env

      Active el entorno virtual creado utilizando “source:

      A continuación, instale las dependencias del proyecto con pip. Entre ellas se incluyen:

      • Django: el marco de trabajo web para el proyecto.
      • Django REST framework: Una aplicación externa que desarrolla REST APIs con Django.
      • django-cors-headers: un paquete que habilita CORS.

      Instalar la estructura de Django:

      • pip install django djangorestframework django-cors-headers

      Con las dependencias del proyecto instaladas, puede crear el proyecto Django y el frontend de React.

      Paso 2: Creación del proyecto Django

      En este paso, generaremos el proyecto Django utilizando las siguientes comandos y utilidades:

      • **django-admin startproject project-name**:django-admin es una utilidad de línea de comandos que se utiliza para realizar tareas con Django. El comando startproject crea un nuevo proyecto Django.

      • **python manage.py startapp myapp**: manage.py es un script de utilidad que se añade automáticamente a cada proyecto de Django, y que ejecuta varias tareas administrativas, como crear nuevas aplicaciones, migrar la base de datos y servir de forma local el proyecto de Django. Su comando startapp crea una aplicación de Django dentro del proyecto Django. En Django, el término aplicación describe un paquete de Python que proporciona algunas características en un proyecto.

      Para comenzar, cree el proyecto Django con django-admin startproject. Hemos de nombrar a nuestro proyecto djangoreactproject

      • django-admin startproject djangoreactproject

      Antes de seguir, observemos la estructura del directorio de nuestro proyecto Django utilizando el comando tree.

      Nota: tree es un comando útil para visualizar estructuras de archivos y directorio desde la línea de comandos. Puede instalarlo con el comando que se indica a continuación:

      • sudo apt-get install tree

      Para utilizarlo, use el comando cd en el directorio que desee y escriba tree o proporcione la ruta al punto de partida con tree /home/sammy/sammys-project.

      Navegue a la carpeta djangoreactproject dentro del root de su proyecto y ejecute el comando tree:

      • cd ~/djangoreactproject
      • tree

      Verá lo siguiente:

      Output

      ├── djangoreactproject │ ├── __init__.py │ ├── settings.py │ ├── urls.py │ └── wsgi.py └── manage.py

      La carpeta ~/djangoreactproject es la root del proyecto. Dentro de esta carpeta, hay varios archivos que serán importantes para su labor:

      • manage.py: el script de utilidad que realiza diversas tareas administrativas.
      • settings.py: el archivo de configuración principal para el proyecto de Django, donde puede modificar la configuración del proyecto. Estos ajustes incluyen variables como INSTALLED_APPS, una lista de strings que designan las aplicaciones habilitadas para su proyecto. La documentación de Django contiene más información sobre los ajustes disponibles.
      • urls.py: este archivo contiene una lista de patrones de URL y vistas relacionadas. Cada patrón traza una conexión entre una URL y la función que se debe solicitar para esa URL. Para más información sobre URL y vistas, consulte nuestro tutorial sobre Cómo crear vistas de Django.

      Nuestro primer paso en el trabajo con el proyecto será configurar los paquetes que instalamos en el paso anterior, incluidos Django REST framework y el paquete Django CORS, al añadirlos a settings.py. Abra el archivo con nano o su editor favorito:

      • nano ~/djangoreactproject/djangoreactproject/settings.py

      Navegue al ajuste INSTALLED_APPS y añada las aplicaciones rest_framework y corsheaders en la parte inferior de la lista:

      ~/djangoreactproject/djangoreactproject/settings.py

      ...
      INSTALLED_APPS = [
          'django.contrib.admin',
          'django.contrib.auth',
          'django.contrib.contenttypes',
          'django.contrib.sessions',
          'django.contrib.messages',
          'django.contrib.staticfiles',
          'rest_framework',
          'corsheaders'
      ]
      

      A continuación, añada el middleware corsheaders.middleware.CorsMiddleware desde el paquete CORS instalado previamente al ajuste MIDDLEWARE. Este ajuste es una lista de middlewares, una clase de Python que contiene código que se procesa cada vez que su aplicación web gestiona una solicitud o respuesta:

      ~/djangoreactproject/djangoreactproject/settings.py

      ...
      
      MIDDLEWARE = [
      ...
      'django.contrib.messages.middleware.MessageMiddleware',
      'django.middleware.clickjacking.XFrameOptionsMiddleware',
      'corsheaders.middleware.CorsMiddleware'
      ]
      

      A continuación, puede habilitar CORS. El ajuste CORS_ORIGIN_ALLOW_ALL especifica si desea habilitar CORS para todos los dominios o no, y CORS_ORIGIN_WHITELIST es una tupla de Python que contiene URL permitidas. En nuestro caso, dado que el servidor de desarrollo de React se ejecutará en http://localhost:3000, añadiremos nuevos ajustes CORS_ORIGIN_ALLOW_ALL = False y CORS_ORIGIN_WHITELIST('localhost:3000',) a nuestro archivo settings.py. Añade estos ajustes en cualquier parte del archivo:

      ~/djangoreactproject/djangoreactproject/settings.py

      
      ...
      CORS_ORIGIN_ALLOW_ALL = False
      
      CORS_ORIGIN_WHITELIST = (
             'localhost:3000',
      )
      ...
      

      Puede encontrar más opciones de configuración en la documentación de django-cors-headers.

      Guarde el archivo y salga del editor cuando haya terminado.

      Aún en el directorio ~/djangoreactproject, cree una nueva aplicación de Django llamada customers:

      • python manage.py startapp customers

      Contendrá los modelos y las vistas para gestionar clientes. Los modelos definen los campos y los comportamientos de nuestros datos de aplicaciones, mientras que las vistas permiten a nuestras aplicaciones gestionar adecuadamente las solicitudes web y devolver las respuestas requeridas.

      A continuación, añada esta aplicación a la lista de aplicaciones instaladas en el archivo settings.py de su proyecto para que Django la reconozca como parte del proyecto. Abra settings.py de nuevo:

      • nano ~/djangoreactproject/djangoreactproject/settings.py

      Añada la aplicación customers:

      ~/djangoreactproject/djangoreactproject/settings.py

      ...
      INSTALLED_APPS = [
          ...
          'rest_framework',
          'corsheaders',
          'customers'
      ]
      ...
      

      A continuación, *migre *la base de datos e inicie el servidor de desarrollo local. Las migraciones son la manera en que Django propaga los cambios que usted realiza a sus modelos en su esquema de base de datos. Estos cambios pueden ser, por ejemplo, añadir un campo o eliminar un modelo. Para obtener más información sobre modelos y migraciones, consulte Cómo crear modelos de Django.

      Migre la base de datos:

      Inicie el servidor de desarrollo local:

      • python manage.py runserver

      El resultado debe ser similar a lo siguiente:

      Output

      Performing system checks... System check identified no issues (0 silenced). October 22, 2018 - 15:14:50 Django version 2.1.2, using settings 'djangoreactproject.settings' Starting development server at http://127.0.0.1:8000/ Quit the server with CONTROL-C.

      Su aplicación web se ejecuta desde http://127.0.0.1:8000. Si se dirige a esta dirección en su navegador web, debería ver la siguiente página:

      Página de demostración de Django

      En este momento, deje la aplicación en ejecución y abra una nueva terminal para seguir desarrollando el proyecto.

      Paso 3: creación del frontend de React

      En esta sección, vamos a crear la aplicación frontend de nuestro proyecto utilizando React.

      React tiene una herramienta oficial que le permite generar proyectos de React de forma rápida sin tener que configurar Webpack directamente. Webpack es un empaquetador de módulos que se utiliza para agrupar recursos web, como código de JavaScript, CSS e imágenes. Normalmente, para poder utilizar Webpack, debe establecer varias opciones de configuración, pero, gracias a la herramienta create-react-app, no tiene que lidiar con Webpack directamente hasta que decida que necesita más control. Para ejecutar create-react-app puede utilizar npx, una herramienta que ejecuta binarios de paquetes npm.

      En su segunda terminal, asegúrese de que estar en el directorio de su proyecto:

      Cree un proyecto de React llamado frontend utilizando create-react-app y npx

      • npx create-react-app frontend

      A continuación, navegue al interior de su aplicación de React e inicie el servidor de desarrollo:

      • cd ~/djangoreactproject/frontend
      • npm start

      Su aplicación se ejecutará desde http://localhost:3000/:

      Página de demostración de React

      Deje el servidor de desarrollo de React en ejecución y abra otra ventana de terminal para proceder.

      Para ver la estructura del directorio de todo el proyecto en este punto, navegue a la carpeta root y ejecute el comando tree de nuevo:

      • cd ~/djangoreactproject
      • tree

      Verá una estructura como esta:

      Output

      ├── customers │ ├── admin.py │ ├── apps.py │ ├── __init__.py │ ├── migrations │ │ └── __init__.py │ ├── models.py │ ├── tests.py │ └── views.py ├── djangoreactproject │ ├── __init__.py │ ├── __pycache__ │ ├── settings.py │ ├── urls.py │ └── wsgi.py ├── frontend │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ └── manifest.json │ ├── README.md │ ├── src │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── index.css │ │ ├── index.js │ │ ├── logo.svg │ │ └── registerServiceWorker.js │ └── yarn.lock └── manage.py

      Nuestra aplicación utilizará Bootstrap 4 para dar forma a la interfaz de React, por lo que lo incluiremos en el archivo frontend/src/App.css que gestiona nuestros ajustes de CSS. Abra el archivo:

      • nano ~/djangoreactproject/frontend/src/App.css

      Añada la importación que se indica a continuación al comienzo del archivo. Puede eliminar el contenido existente del archivo, pero no es necesario hacerlo:

      ~/djangoreactproject/frontend/src/App.css

      @import  'https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css';
      

      Aquí, @import es una instrucción de CSS que se utiliza para importar reglas de estilo de otras hojas de estilo.

      Ahora que hemos creado las aplicaciones back-end y front-end, vamos a crear el modelo de cliente y algunos datos de prueba.

      Paso 4: creación del modelo de cliente y datos iniciales

      Tras crear la aplicación de Django y el frontend de React, nuestro próximo paso será crear el modelo de cliente, que representa la tabla de base de datos que almacenará información sobre los clientes. No necesita nada de SQL, dado que el mapeo objeto-relacional (ORM) de Django se encargará de las operaciones de la base de datos al asignar las clases y variables de Python a tablas y columnas de SQL. De esta manera, el ORM de Django extrae las interacciones de SQL con la base de datos a través de una interfaz de Python.

      Active su entorno virtual de nuevo:

      • cd ~
      • source env/bin/activate

      Diríjase al directorio customers y abra models.py, un archivo de Python que contiene los modelos de su aplicación:

      • cd ~/djangoreactproject/customers/
      • nano models.py

      El archivo incluirá el siguiente contenido:

      ~/djangoreactproject/customers/models.py

      from django.db import models
      # Create your models here.
      

      La API del modelo de cliente ya está importada en el archivo gracias a la instrucción import from django.db import models. Ahora, añadirá la clase Customer, que extiende models.Model. Cada modelo de Django es una clase de Python que extiende django.db.models.Model.

      El modelo Customer tendrá estos campos de base de datos:

      • first_name: el nombre del cliente.
      • last_name: el apellido del cliente.
      • email: la dirección de correo electrónico del cliente.
      • phone: el número de teléfono del cliente.
      • address: la dirección del cliente.
      • description: la descripción del cliente.
      • createdAt: la fecha en que se añade el cliente.

      También añadiremos la función __str__(), que define la manera en que se mostrará el modelo. En nuestro caso, será con el nombre del cliente. Para obtener más información sobre la creación de clases y la definición de objetos, consulte Cómo crear clases y definir objetos en Python 3.

      Añada el código siguiente al archivo:

      ~/djangoreactproject/customers/models.py

      from django.db import models
      
      class Customer(models.Model):
          first_name = models.CharField("First name", max_length=255)
          last_name = models.CharField("Last name", max_length=255)
          email = models.EmailField()
          phone = models.CharField(max_length=20)
          address =  models.TextField(blank=True, null=True)
          description = models.TextField(blank=True, null=True)
          createdAt = models.DateTimeField("Created At", auto_now_add=True)
      
          def __str__(self):
              return self.first_name
      

      A continuación, migre la base de datos para crear las tablas de la base de datos. El comando makemigrations crea los archivos de migración en los que se añadirán los cambios al modelo, y migrate aplica los cambios en los archivos de migraciones a la base de datos.

      Vuelva a navegar a la carpeta root del proyecto:

      Ejecute lo siguiente para crear los archivos de migración:

      • python manage.py makemigrations

      Verá algo similar a esto:

      Output

      customers/migrations/0001_initial.py - Create model Customer

      Aplique estos cambios en la base de datos:

      Verá un resultado que indica que la migración se realizó correctamente:

      Output

      Operations to perform: Apply all migrations: admin, auth, contenttypes, customers, sessions Running migrations: Applying customers.0001_initial... OK

      A continuación, utilizará un archivo de migración de datos para crear datos iniciales de clientes. Un archivo de migración de datos es una migración que añade o altera datos en la base de datos. Cree un archivo de migración de datos vacío para la aplicación customers:

      • python manage.py makemigrations --empty --name customers customers

      Visualizará la siguiente confirmación con el nombre de su archivo de migración:

      Output

      Migrations for 'customers': customers/migrations/0002_customers.py

      Tenga en cuenta que el nombre de su archivo de migración es 0002_customers.py.

      A continuación, navegue al interior de la carpeta de migraciones de la aplicación customers:

      • cd ~/djangoreactproject/customers/migrations

      Abra el archivo de migración creado:

      Este es el contenido inicial del archivo:

      ~/djangoreactproject/customers/migrations/0002_customers.py

      from django.db import migrations
      
      class Migration(migrations.Migration):
          dependencies = [
              ('customers', '0001_initial'),
          ]
          operations = [
          ]        
      

      La instrucción import importa la API de migraciones, una API de Django para crear migraciones, desde django.db, un paquete incorporado que contiene clases para trabajar con bases de datos.

      La clase Migration es una clase de Python que describe las operaciones que se ejecutan al migrar bases de datos. Esta clase extiende migrations.Migration y tiene dos listas:

      • dependencies: contiene las migraciones dependientes.
      • operations: contiene las operaciones que se ejecutarán al aplicar la migración.

      A continuación, añada un método para crear datos de clientes de prueba. Añada el método que se indica a continuación antes de la definición de la clase Migration:

      ~/djangoreactproject/customers/migrations/0002_customers.py

      ...
      def create_data(apps, schema_editor):
          Customer = apps.get_model('customers', 'Customer')
          Customer(first_name="Customer 001", last_name="Customer 001", email="customer001@email.com", phone="00000000", address="Customer 000 Address", description= "Customer 001 description").save()
      
      ...
      

      En este método, estamos tomando la clase Customer de nuestra aplicación customers y creando un cliente de prueba para insertar en la base de datos.

      Para obtener la clase Customer, que permitirá la creación de nuevos clientes, usamos el método get_model() del objeto apps. El objeto apps representa el registro de aplicaciones instaladas y sus modelos de base de datos.

      El objeto apps se pasará del método RunPython() cuando lo usemos para ejecutar create_data(). Añada el método migrations.RunPython() a la lista operations vacía:

      ~/djangoreactproject/customers/migrations/0002_customers.py

      
      ...
          operations = [
              migrations.RunPython(create_data),
          ]  
      

      RunPython() es parte de la API de Migrations que le permite ejecutar código de Python personalizado en una migración. Nuestra lista operations especifica que este método se ejecutará al aplicar la migración.

      Este es el archivo completo:

      ~/djangoreactproject/customers/migrations/0002_customers.py

      from django.db import migrations
      
      def create_data(apps, schema_editor):
          Customer = apps.get_model('customers', 'Customer')
          Customer(first_name="Customer 001", last_name="Customer 001", email="customer001@email.com", phone="00000000", address="Customer 000 Address", description= "Customer 001 description").save()
      
      class Migration(migrations.Migration):
          dependencies = [
              ('customers', '0001_initial'),
          ]
          operations = [
              migrations.RunPython(create_data),
          ]        
      

      Para obtener más información sobre migraciones de datos, consulte la documentación sobre migraciones de datos en Django

      Para migrar su base de datos, primero, vuelva a navegar a la carpeta root de su proyecto:

      Migre su base de datos para crear los datos de prueba:

      Visualizará un resultado que confirma la migración:

      Output

      Operations to perform: Apply all migrations: admin, auth, contenttypes, customers, sessions Running migrations: Applying customers.0002_customers... OK

      Para obtener más detalles sobre este proceso, consulte Cómo crear modelos de Django.

      Con el modelo Customer y los datos de prueba creados, podemos pasar a la creación de la API REST.

      Paso 5: creación de la API REST

      En este paso, vamos a crear la API REST utilizando Django REST Framework. Crearemos varias vistas de API diferentes. Una vista de API es una función que gestiona una solicitud o llamada de API, mientras que un punto de final de API es una URL única que representa un punto de contacto con el sistema REST. Por ejemplo, cuando el usuario envía una solicitud de GET a un punto final de API, Django llama a la función o vista de API correspondiente para gestionar la solicitud y devolver los resultados posibles.

      También utilizaremos serializadores. Un serializador de Django REST Framework permite que instancias de modelos complejas y QuerySets se conviertan en formato JSON para el consumo de API. La clase de serialización también puede funcionar en dirección inversa, proporcionando mecanismos para el análisis y la deserialización de datos en QuerySets y modelos de Django.

      Nuestros puntos finales de API incluirán lo siguiente:

      • api/customers: este punto final se utiliza para crear clientes y devuelve conjuntos paginados de clientes.
      • api/clusters/<pk>: este punto final se utiliza para obtener, actualizar y eliminar clientes individuales por clave primaria o id.

      También crearemos URL en el archivo urls.py del proyecto para los puntos finales correspondientes (es decir, api/clusters y api/clusters/<pk>).

      Comencemos por crear la clase de serialización para nuestro modelo Customer.

      Incorporación de la clase de serialización

      Es necesario crear una clase de serialización para nuestro modelo Customer para transformar las instancias de cliente y QuerySets hacia y desde JSON. Para crear la clase de serialización, primero, cree un archivo serializer.py dentro de la aplicación customers:

      • cd ~/djangoreactproject/customers/
      • nano serializers.py

      Añada el código siguiente para importar el modelo Customer y la API de serializadores:

      ~/djangoreactproject/customers/serializers.py

      from rest_framework import serializers
      from .models import Customer
      

      A continuación, cree una clase de serialización que extienda serializers.ModelSerializer y especifique los campos que han de serializarse:

      ~/djangoreactproject/customers/serializers.py

      
      ...
      class CustomerSerializer(serializers.ModelSerializer):
      
          class Meta:
              model = Customer 
              fields = ('pk','first_name', 'last_name', 'email', 'phone','address','description')
      

      La clase Meta especifica qué campos y modelos se serializarán: pk, first_name, last_name, email, phone, address, description.

      Este es el contenido completo del archivo:

      ~/djangoreactproject/customers/serializers.py

      from rest_framework import serializers
      from .models import Customer
      
      class CustomerSerializer(serializers.ModelSerializer):
      
          class Meta:
              model = Customer 
              fields = ('pk','first_name', 'last_name', 'email', 'phone','address','description')
      

      Ahora que hemos creado nuestra clase de serialización, podemos añadir las vistas de API.

      Incorporación de vistas de API

      En esta sección, crearemos las vistas de API para nuestra aplicación, a las que llamará Django cuando el usuario visite el punto final correspondiente a la función de vista.

      Abra ~/djangoreactproject/customers/views.py:

      • nano ~/djangoreactproject/customers/views.py

      Elimine lo que haya allí y añada las siguientes importaciones:

      ~/djangoreactproject/customers/views.py

      from rest_framework.response import Response
      from rest_framework.decorators import api_view
      from rest_framework import status
      
      from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
      from .models import Customer 
      from .serializers import *
      

      Estamos importando el serializador que creamos, junto con el modelo Customer y las API de Django y Django REST Framework.

      A continuación, añada la vista para el procesamiento de POST y las solicitudes GET HTTP:

      ~/djangoreactproject/customers/views.py

      ...
      
      @api_view(['GET', 'POST'])
      def customers_list(request):
          """
       List  customers, or create a new customer.
       """
          if request.method == 'GET':
              data = []
              nextPage = 1
              previousPage = 1
              customers = Customer.objects.all()
              page = request.GET.get('page', 1)
              paginator = Paginator(customers, 10)
              try:
                  data = paginator.page(page)
              except PageNotAnInteger:
                  data = paginator.page(1)
              except EmptyPage:
                  data = paginator.page(paginator.num_pages)
      
              serializer = CustomerSerializer(data,context={'request': request} ,many=True)
              if data.has_next():
                  nextPage = data.next_page_number()
              if data.has_previous():
                  previousPage = data.previous_page_number()
      
              return Response({'data': serializer.data , 'count': paginator.count, 'numpages' : paginator.num_pages, 'nextlink': '/api/customers/?page=' + str(nextPage), 'prevlink': '/api/customers/?page=' + str(previousPage)})
      
          elif request.method == 'POST':
              serializer = CustomerSerializer(data=request.data)
              if serializer.is_valid():
                  serializer.save()
                  return Response(serializer.data, status=status.HTTP_201_CREATED)
              return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
      

      Primero, usamos el decorador @api_view(['GET', 'POST']) para crear una vista de API que pueda aceptar solicitudes GET y POST. Un decorador es una función que toma otra función y la extiende de forma dinámica.

      En el cuerpo del método, usamos la variable request.method para verificar el método HTTP actual y ejecutar la lógica correspondiente dependiendo del tipo de solicitud:

      • Si se trata de una solicitud GET, el método pagina los datos utilizando Django Paginator y devuelve a la primera página de datos después de la serialización, el conteo de clientes disponibles, el número de páginas disponibles y los enlaces a las páginas anteriores y siguientes. Paginator es una clase integrada de Django que pagina una lista de datos en páginas y proporciona métodos para acceder a los elementos de cada una de ellas.
      • Si se trata de una solicitud POST, el método serializa los datos de clientes recibidos y, luego, llama al método save() del objeto serializador. A continuación, devuelve un objeto de Response, una instancia de HttpResponse, con el código de estado 201. Cada vista que crea se encarga de regresar un objeto HttpResponse. El método save() guarda los datos serializados en la base de datos.

      Para obtener más información sobre HttpResponse y las vistas, consulte esta discusión con respecto a la creación de funciones de vista.

      Ahora, añada la vista de API que se encargará del procesamiento de las solicitudes GET, PUT y DELETE para obtener, actualizar y eliminar clientes por pk (clave primaria):

      ~/djangoreactproject/customers/views.py

      
      ...
      @api_view(['GET', 'PUT', 'DELETE'])
      def customers_detail(request, pk):
       """
       Retrieve, update or delete a customer by id/pk.
       """
          try:
              customer = Customer.objects.get(pk=pk)
          except Customer.DoesNotExist:
              return Response(status=status.HTTP_404_NOT_FOUND)
      
          if request.method == 'GET':
              serializer = CustomerSerializer(customer,context={'request': request})
              return Response(serializer.data)
      
          elif request.method == 'PUT':
              serializer = CustomerSerializer(customer, data=request.data,context={'request': request})
              if serializer.is_valid():
                  serializer.save()
                  return Response(serializer.data)
              return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
      
          elif request.method == 'DELETE':
              customer.delete()
              return Response(status=status.HTTP_204_NO_CONTENT)
      

      El método está representado con @api_view(['GET', 'PUT', 'DELETE']) para indicar que se trata de una vista de API que puede aceptar las solicitudes GET, PUT y DELETE.

      La marca de revisión en el campo request.method verifica el método de solicitud y, dependiendo de su valor, llama a la lógica correcta:

      • Si se trata de una solicitud GET, se serializan los datos de clientes y se envían utilizando un objeto Response.
      • Si se trata de una solicitud PUT, el método crea un serializador para nuevos datos de cliente y, luego, llama al método save() del objeto serializador creado. Por último, envía un objeto Response con el cliente actualizado.
      • Si se trata de una solicitud DELETE, el método llama al método delete() del objeto de cliente para eliminarlo y, a continuación, devuelve un objeto Response sin datos.

      El archivo completo se ve de este modo:

      ~/djangoreactproject/customers/views.py

      from rest_framework.response import Response
      from rest_framework.decorators import api_view
      from rest_framework import status
      
      from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
      from .models import Customer 
      from .serializers import *
      
      
      @api_view(['GET', 'POST'])
      def customers_list(request):
          """
       List  customers, or create a new customer.
       """
          if request.method == 'GET':
              data = []
              nextPage = 1
              previousPage = 1
              customers = Customer.objects.all()
              page = request.GET.get('page', 1)
              paginator = Paginator(customers, 5)
              try:
                  data = paginator.page(page)
              except PageNotAnInteger:
                  data = paginator.page(1)
              except EmptyPage:
                  data = paginator.page(paginator.num_pages)
      
              serializer = CustomerSerializer(data,context={'request': request} ,many=True)
              if data.has_next():
                  nextPage = data.next_page_number()
              if data.has_previous():
                  previousPage = data.previous_page_number()
      
              return Response({'data': serializer.data , 'count': paginator.count, 'numpages' : paginator.num_pages, 'nextlink': '/api/customers/?page=' + str(nextPage), 'prevlink': '/api/customers/?page=' + str(previousPage)})
      
          elif request.method == 'POST':
              serializer = CustomerSerializer(data=request.data)
              if serializer.is_valid():
                  serializer.save()
                  return Response(serializer.data, status=status.HTTP_201_CREATED)
              return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
      
      @api_view(['GET', 'PUT', 'DELETE'])
      def customers_detail(request, pk):
          """
       Retrieve, update or delete a customer by id/pk.
       """
          try:
              customer = Customer.objects.get(pk=pk)
          except Customer.DoesNotExist:
              return Response(status=status.HTTP_404_NOT_FOUND)
      
          if request.method == 'GET':
              serializer = CustomerSerializer(customer,context={'request': request})
              return Response(serializer.data)
      
          elif request.method == 'PUT':
              serializer = CustomerSerializer(customer, data=request.data,context={'request': request})
              if serializer.is_valid():
                  serializer.save()
                  return Response(serializer.data)
              return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
      
          elif request.method == 'DELETE':
              customer.delete()
              return Response(status=status.HTTP_204_NO_CONTENT)
      

      Ahora, podemos pasar a crear nuestros puntos finales.

      Incorporación de puntos finales de API

      Ahora, crearemos los puntos finales de API: api/customers/ para consultar y crear clientes, y api/customers/ <pk> para obtener, actualizar o eliminar clientes individuales por su pk.

      Abra ~/djangoreactproject/djangoreactproject/urls.py:

      • nano ~/djangoreactproject/djangoreactproject/urls.py

      Deje lo que haya allí, pero añada la importación a las vistas customers en la parte superior del archivo:

      ~/djangoreactproject/djangoreactproject/urls.py

      from django.contrib import admin
      from django.urls import path
      from customers import views
      from django.conf.urls import url
      

      A continuación, añada las URL de api/customers/ y api/customers/<pk> a la lista urlpatterns que contiene las URL de la aplicación:

      ~/djangoreactproject/djangoreactproject/urls.py

      ...
      
      urlpatterns = [
          path('admin/', admin.site.urls),
          url(r'^api/customers/$', views.customers_list),
          url(r'^api/customers/(?P<pk>[0-9]+)$', views.customers_detail),
      ]
      

      Con nuestros puntos finales REST creados, veamos cómo podemos consumirlos.

      Paso 6: consumo de API REST con Axios.

      En este paso, instalaremos Axios, el cliente HTTP que utilizaremos para realizar llamadas de API. También crearemos una clase para consumir los puntos finales de API que hemos creado.

      Primero, desactive su entorno virtual:

      A continuación, navegue a su carpeta frontend:

      • cd ~/djangoreactproject/frontend

      Instale axios desde npm utilizando:

      La opción --save añade la dependencia axios al archivo package.json de su aplicación.

      A continuación, cree un archivo de JavaScript denominado CustomersService.js, que contendrá el código para llamar a las API REST. Realizaremos esto dentro de la carpeta src, donde residirá el código de la aplicación de nuestro proyecto:

      • cd src
      • nano CustomersService.js

      Añada el código siguiente, que contiene métodos para conectarse a la API REST de Django:

      ~/djangoreactproject/frontend/src/CustomersService.js

      import axios from 'axios';
      const API_URL = 'http://localhost:8000';
      
      export default class CustomersService{
      
          constructor(){}
      
      
          getCustomers() {
              const url = `${API_URL}/api/customers/`;
              return axios.get(url).then(response => response.data);
          }  
          getCustomersByURL(link){
              const url = `${API_URL}${link}`;
              return axios.get(url).then(response => response.data);
          }
          getCustomer(pk) {
              const url = `${API_URL}/api/customers/${pk}`;
              return axios.get(url).then(response => response.data);
          }
          deleteCustomer(customer){
              const url = `${API_URL}/api/customers/${customer.pk}`;
              return axios.delete(url);
          }
          createCustomer(customer){
              const url = `${API_URL}/api/customers/`;
              return axios.post(url,customer);
          }
          updateCustomer(customer){
              const url = `${API_URL}/api/customers/${customer.pk}`;
              return axios.put(url,customer);
          }
      }
      

      La clase CustomersService llamará a los siguientes métodos de Axios:

      • getCustomers(): obtiene la primera página de clientes.
      • getCustomersByURL(): obtiene clientes por URL. Esto permite obtener las siguientes páginas de clientes al pasar enlaces como /api/customers/?page=2.
      • get Customer(): obtiene un cliente por clave primaria.
      • createCustomer(): crea un cliente.
      • updateCustomer(): actualiza un cliente.
      • deleteCustomer(): elimina un cliente.

      Ahora, podemos mostrar los datos de nuestra API en nuestra IU de React al crear un componente CustomersList.

      Paso 7: visualización de datos de la API en la aplicación de React

      En este paso, crearemos el componente CustomersList de React. Un componente de React representa una parte de la IU; también le permite dividir la IU en piezas independientes y reutilizables.

      Comience por crear CustomersList.js en frontend/src:

      • nano ~/djangoreactproject/frontend/src/CustomersList.js

      Inicie la importación de React y Component para crear un componente de React:

      ~/djangoreactproject/frontend/src/CustomersList.js

      import  React, { Component } from  'react';
      

      A continuación, importe e instancie el módulo CustomersService que creó en el paso anterior, el cual proporciona métodos que interactúan con el backend de API REST:

      ~/djangoreactproject/frontend/src/CustomersList.js

      
      ...
      import  CustomersService  from  './CustomersService';
      
      const  customersService  =  new  CustomersService();
      

      A continuación, cree un componente CustomersList que extienda Component para llamar a la API REST. Un componente de React debería extender o crear una subclase de la clase Component. Para obtener más información acerca de las clases E6 y herencia, consulte nuestro tutorial sobre Comprensión de las clases de JavaScript.

      Añada el siguiente código para crear un componente de React que extienda react.Component:

      ~/djangoreactproject/frontend/src/CustomersList.js

      
      ...
      class  CustomersList  extends  Component {
      
          constructor(props) {
              super(props);
              this.state  = {
                  customers: [],
                  nextPageURL:  ''
              };
              this.nextPage  =  this.nextPage.bind(this);
              this.handleDelete  =  this.handleDelete.bind(this);
          }
      }
      export  default  CustomersList;
      

      Dentro del constructor, estamos inicializando el objeto state. Este almacena las variables de estado de nuestro componente utilizando una matriz customers vacía. Esta matriz almacenará clientes y una nextPageURL que contendrá la URL de la siguiente página que se obtendrá del back-end de la API. También procedemos a vincular los métodos nextPage() y handleDelete() a this para que sean accesibles desde el código HTML.

      A continuación, añada el método componentDidMount() y una llamada a getCustomers() dentro de la clase CustomersList, antes de la llave de cierre.

      El método componentDidMount() es un método de ciclo de vida del componente que se llama al crear el componente y se inserta en el DOM. getCustomers() llama al objeto Customers Service para obtener la primera página de datos y el enlace de la siguiente página del backend de Django:

      ~/djangoreactproject/frontend/src/CustomersList.js

      
      ...
      componentDidMount() {
          var  self  =  this;
          customersService.getCustomers().then(function (result) {
              self.setState({ customers:  result.data, nextPageURL:  result.nextlink})
          });
      }
      

      Ahora, añada el método handleDelete(), que gestiona la eliminación de un cliente, debajo de componentDidMount():

      ~/djangoreactproject/frontend/src/CustomersList.js

      
      ...
      handleDelete(e,pk){
          var  self  =  this;
          customersService.deleteCustomer({pk :  pk}).then(()=>{
              var  newArr  =  self.state.customers.filter(function(obj) {
                  return  obj.pk  !==  pk;
              });
              self.setState({customers:  newArr})
          });
      }
      

      El método handleDelete() llama al método deleteCustomer() para eliminar un cliente utilizando su pk (clave primaria). Si la operación se realiza correctamente, la matriz customers se filtra por el cliente eliminado.

      A continuación, añada un método nextPage() para obtener los datos de la siguiente página y actualice el enlace de la página siguiente:

      ~/djangoreactproject/frontend/src/CustomersList.js

      
      ...
      nextPage(){
          var  self  =  this;
          customersService.getCustomersByURL(this.state.nextPageURL).then((result) => {
              self.setState({ customers:  result.data, nextPageURL:  result.nextlink})
          });
      }
      

      El método nextPage() llama a un método getCustomersByURL(), que obtiene la URL de la página siguiente del objeto de estado, this.state.nextPageURL, y actualiza la matriz customers con los datos devueltos.

      Por último, añada el método render() del componente, que produce una tabla de clientes del estado de componente:

      ~/djangoreactproject/frontend/src/CustomersList.js

      
      ...
      render() {
      
          return (
          <div  className="customers--list">
              <table  className="table">
                  <thead  key="thead">
                  <tr>
                      <th>#</th>
                      <th>First Name</th>
                      <th>Last Name</th>
                      <th>Phone</th>
                      <th>Email</th>
                      <th>Address</th>
                      <th>Description</th>
                      <th>Actions</th>
                  </tr>
                  </thead>
                  <tbody>
                      {this.state.customers.map( c  =>
                      <tr  key={c.pk}>
                          <td>{c.pk}  </td>
                          <td>{c.first_name}</td>
                          <td>{c.last_name}</td>
                          <td>{c.phone}</td>
                          <td>{c.email}</td>
                          <td>{c.address}</td>
                          <td>{c.description}</td>
                          <td>
                          <button  onClick={(e)=>  this.handleDelete(e,c.pk) }> Delete</button>
                          <a  href={"/customer/" + c.pk}> Update</a>
                          </td>
                      </tr>)}
                  </tbody>
              </table>
              <button  className="btn btn-primary"  onClick=  {  this.nextPage  }>Next</button>
          </div>
          );
      }
      

      Este es el contenido completo del archivo:

      ~/djangoreactproject/frontend/src/CustomersList.js

      import  React, { Component } from  'react';
      import  CustomersService  from  './CustomersService';
      
      const  customersService  =  new  CustomersService();
      
      class  CustomersList  extends  Component {
      
      constructor(props) {
          super(props);
          this.state  = {
              customers: [],
              nextPageURL:  ''
          };
          this.nextPage  =  this.nextPage.bind(this);
          this.handleDelete  =  this.handleDelete.bind(this);
      }
      
      componentDidMount() {
          var  self  =  this;
          customersService.getCustomers().then(function (result) {
              console.log(result);
              self.setState({ customers:  result.data, nextPageURL:  result.nextlink})
          });
      }
      handleDelete(e,pk){
          var  self  =  this;
          customersService.deleteCustomer({pk :  pk}).then(()=>{
              var  newArr  =  self.state.customers.filter(function(obj) {
                  return  obj.pk  !==  pk;
              });
      
              self.setState({customers:  newArr})
          });
      }
      
      nextPage(){
          var  self  =  this;
          console.log(this.state.nextPageURL);        
          customersService.getCustomersByURL(this.state.nextPageURL).then((result) => {
              self.setState({ customers:  result.data, nextPageURL:  result.nextlink})
          });
      }
      render() {
      
          return (
              <div  className="customers--list">
                  <table  className="table">
                  <thead  key="thead">
                  <tr>
                      <th>#</th>
                      <th>First Name</th>
                      <th>Last Name</th>
                      <th>Phone</th>
                      <th>Email</th>
                      <th>Address</th>
                      <th>Description</th>
                      <th>Actions</th>
                  </tr>
                  </thead>
                  <tbody>
                  {this.state.customers.map( c  =>
                      <tr  key={c.pk}>
                      <td>{c.pk}  </td>
                      <td>{c.first_name}</td>
                      <td>{c.last_name}</td>
                      <td>{c.phone}</td>
                      <td>{c.email}</td>
                      <td>{c.address}</td>
                      <td>{c.description}</td>
                      <td>
                      <button  onClick={(e)=>  this.handleDelete(e,c.pk) }> Delete</button>
                      <a  href={"/customer/" + c.pk}> Update</a>
                      </td>
                  </tr>)}
                  </tbody>
                  </table>
                  <button  className="btn btn-primary"  onClick=  {  this.nextPage  }>Next</button>
              </div>
              );
        }
      }
      export  default  CustomersList;
      

      Ahora que hemos creado el componente CustomersList para visualizar la lista de clientes, podemos añadir el componente que gestiona la creación y la actualización de clientes.

      Paso 8: incorporación del componente de React de creación y actualización de clientes

      En este paso, crearemos el componente CustomerCreateUpdate, que se encargará de crear y actualizar clientes. Lo hará al proporcionar una forma que los usuarios puedan utilizar para ingresar datos sobre un cliente nuevo o actualizar una entrada existente.

      En frontend/src, cree un archivo CustomerCreateUpdate.js:

      • nano ~/djangoreactproject/frontend/src/CustomerCreateUpdate.js

      Añada el siguiente código para crear un componente de React, importando React y Component:

      ~/djangoreactproject/frontend/src/CustomerCreateUpdate.js

      import  React, { Component } from  'react';
      

      A continuación, también podemos importar e instanciar la clase CustomersService que creamos en el paso anterior, que proporciona métodos que interactúan con el backend de API REST:

      ~/djangoreactproject/frontend/src/CustomerCreateUpdate.js

      ...
      import  CustomersService  from  './CustomersService';
      
      const  customersService  =  new  CustomersService();
      

      Luego, cree un componente CustomerCreateUpdate que extienda Component para crear y actualizar clientes:

      ~/djangoreactproject/frontend/src/CustomerCreateUpdate.js

      
      ...
      class  CustomerCreateUpdate  extends  Component {
      
          constructor(props) {
              super(props);
          }
      
      }
      export default CustomerCreateUpdate;
      

      Dentro de la definición de clase, añada el método render() del componente, que produce un formulario HTML que toma información sobre el cliente:

      ~/djangoreactproject/frontend/src/CustomerCreateUpdate.js

      
      ...
      render() {
              return (
                <form onSubmit={this.handleSubmit}>
                <div className="form-group">
                  <label>
                    First Name:</label>
                    <input className="form-control" type="text" ref='firstName' />
      
                  <label>
                    Last Name:</label>
                    <input className="form-control" type="text" ref='lastName'/>
      
                  <label>
                    Phone:</label>
                    <input className="form-control" type="text" ref='phone' />
      
                  <label>
                    Email:</label>
                    <input className="form-control" type="text" ref='email' />
      
                  <label>
                    Address:</label>
                    <input className="form-control" type="text" ref='address' />
      
                  <label>
                    Description:</label>
                    <textarea className="form-control" ref='description' ></textarea>
      
      
                  <input className="btn btn-primary" type="submit" value="Submit" />
                  </div>
                </form>
              );
        }
      

      Para cada elemento de entrada del formulario, el método añade una propiedad ref para acceder al valor del elemento del formulario y establecerlo.

      A continuación, por encima del método render(), defina un método handleSubmit(event) de modo que tenga la funcionalidad correcta cuando un usuario haga clic en el botón de enviar:

      ~/djangoreactproject/frontend/src/CustomerCreateUpdate.js

      
      ...
      handleSubmit(event) {
          const { match: { params } } =  this.props;
          if(params  &&  params.pk){
              this.handleUpdate(params.pk);
          }
          else
          {
              this.handleCreate();
          }
          event.preventDefault();
      }
      
      ...
      

      El método handleSubmit(event) gestiona el envío del formulario y, dependiendo de la ruta, llama al método handleUpdate(pk) para actualizar el cliente con la pk correcta, o el método handleCreate() para crear un nuevo cliente. Procederemos a definir estos métodos en breve.

      De nuevo en el constructor del componente, vincule el método handleSubmit() recientemente añadido a this para poder acceder a él en su formulario:

      ~/djangoreactproject/frontend/src/CustomerCreateUpdate.js

      ...
      class CustomerCreateUpdate extends Component {
      
      constructor(props) {
          super(props);
          this.handleSubmit = this.handleSubmit.bind(this);
      }
      ...
      

      A continuación, defina el método handleCreate() para crear un cliente a partir de los datos del formulario. Encima del método handleSubmit(event), añada el siguiente código:

      ~/djangoreactproject/frontend/src/CustomerCreateUpdate.js

      
      ...
      handleCreate(){
          customersService.createCustomer(
              {
              "first_name":  this.refs.firstName.value,
              "last_name":  this.refs.lastName.value,
              "email":  this.refs.email.value,
              "phone":  this.refs.phone.value,
              "address":  this.refs.address.value,
              "description":  this.refs.description.value
              }).then((result)=>{
                      alert("Customer created!");
              }).catch(()=>{
                      alert('There was an error! Please re-check your form.');
              });
      }
      
      ...
      

      El método handleCreate() se utilizará para crear un cliente a partir de los datos ingresados. Llama al método CustomersService.createCustomer() correspondiente que provoca que la API real llame al backend para crear un cliente.

      A continuación, por debajo del método handleCreate(), defina el método handleUpdate(pk) para implementar actualizaciones:

      ~/djangoreactproject/frontend/src/CustomerCreateUpdate.js

      
      ...
      handleUpdate(pk){
      customersService.updateCustomer(
          {
          "pk":  pk,
          "first_name":  this.refs.firstName.value,
          "last_name":  this.refs.lastName.value,
          "email":  this.refs.email.value,
          "phone":  this.refs.phone.value,
          "address":  this.refs.address.value,
          "description":  this.refs.description.value
          }
          ).then((result)=>{
      
              alert("Customer updated!");
          }).catch(()=>{
              alert('There was an error! Please re-check your form.');
          });
      }
      

      El método updateCustomer() actualizará un cliente por pk, utilizando la nueva información del formulario de información de clientes. Llama al método customersService.updateCustomer().

      A continuación, añada un método componentDidMount(). Si el usuario visita una ruta customer/:pk, queremos que el formulario se complete con información relacionada con el cliente utilizando la clave primaria de la URL. Para ello, podemos añadir el método getCustomer(pk) una vez que el componente se monte en el evento de ciclo de vida de componentDidMount(). Añada el siguiente código por debajo del constructor del componente para añadir este método:

      ~/djangoreactproject/frontend/src/CustomerCreateUpdate.js

      
      ...
      componentDidMount(){
          const { match: { params } } =  this.props;
          if(params  &&  params.pk)
          {
              customersService.getCustomer(params.pk).then((c)=>{
                  this.refs.firstName.value  =  c.first_name;
                  this.refs.lastName.value  =  c.last_name;
                  this.refs.email.value  =  c.email;
                  this.refs.phone.value  =  c.phone;
                  this.refs.address.value  =  c.address;
                  this.refs.description.value  =  c.description;
              })
          }
      }
      

      Este es el contenido completo del archivo:

      ~/djangoreactproject/frontend/src/CustomerCreateUpdate.js

      import React, { Component } from 'react';
      import CustomersService from './CustomersService';
      
      const customersService = new CustomersService();
      
      class CustomerCreateUpdate extends Component {
          constructor(props) {
              super(props);
      
              this.handleSubmit = this.handleSubmit.bind(this);
            }
      
            componentDidMount(){
              const { match: { params } } = this.props;
              if(params && params.pk)
              {
                customersService.getCustomer(params.pk).then((c)=>{
                  this.refs.firstName.value = c.first_name;
                  this.refs.lastName.value = c.last_name;
                  this.refs.email.value = c.email;
                  this.refs.phone.value = c.phone;
                  this.refs.address.value = c.address;
                  this.refs.description.value = c.description;
                })
              }
            }
      
            handleCreate(){
              customersService.createCustomer(
                {
                  "first_name": this.refs.firstName.value,
                  "last_name": this.refs.lastName.value,
                  "email": this.refs.email.value,
                  "phone": this.refs.phone.value,
                  "address": this.refs.address.value,
                  "description": this.refs.description.value
              }          
              ).then((result)=>{
                alert("Customer created!");
              }).catch(()=>{
                alert('There was an error! Please re-check your form.');
              });
            }
            handleUpdate(pk){
              customersService.updateCustomer(
                {
                  "pk": pk,
                  "first_name": this.refs.firstName.value,
                  "last_name": this.refs.lastName.value,
                  "email": this.refs.email.value,
                  "phone": this.refs.phone.value,
                  "address": this.refs.address.value,
                  "description": this.refs.description.value
              }          
              ).then((result)=>{
                console.log(result);
                alert("Customer updated!");
              }).catch(()=>{
                alert('There was an error! Please re-check your form.');
              });
            }
            handleSubmit(event) {
              const { match: { params } } = this.props;
      
              if(params && params.pk){
                this.handleUpdate(params.pk);
              }
              else
              {
                this.handleCreate();
              }
      
              event.preventDefault();
            }
      
            render() {
              return (
                <form onSubmit={this.handleSubmit}>
                <div className="form-group">
                  <label>
                    First Name:</label>
                    <input className="form-control" type="text" ref='firstName' />
      
                  <label>
                    Last Name:</label>
                    <input className="form-control" type="text" ref='lastName'/>
      
                  <label>
                    Phone:</label>
                    <input className="form-control" type="text" ref='phone' />
      
                  <label>
                    Email:</label>
                    <input className="form-control" type="text" ref='email' />
      
                  <label>
                    Address:</label>
                    <input className="form-control" type="text" ref='address' />
      
                  <label>
                    Description:</label>
                    <textarea className="form-control" ref='description' ></textarea>
      
      
                  <input className="btn btn-primary" type="submit" value="Submit" />
                  </div>
                </form>
              );
            }  
      }
      
      export default CustomerCreateUpdate;
      

      Con el componente CustomerCreateUpdate creado, podemos actualizar el componente principal App para añadir enlaces a los diferentes componentes que hemos creado.

      Paso 9: actualización del componente principal App

      En esta sección, actualizaremos el componente App de nuestra aplicación para crear enlaces a los componentes que hemos creado en los pasos anteriores.

      Desde la carpeta frontend, ejecute el siguiente comando para instalar React Router, que le permite añadir enrutamiento y navegación entre varios componentes de React:

      • cd ~/djangoreactproject/frontend
      • npm install --save react-router-dom

      A continuación, abra ~/djangoreactproject/frontend/src/App.js:

      • nano ~/djangoreactproject/frontend/src/App.js

      Elimine todo lo que haya allí y añada el siguiente código para importar las clases necesarias para incorporar enrutamiento. Estas incluyen BrowserRouter, que crea un componente Router, y Route, que crea un componente de ruta:

      ~/djangoreactproject/frontend/src/App.js

      import  React, { Component } from  'react';
      import { BrowserRouter } from  'react-router-dom'
      import { Route, Link } from  'react-router-dom'
      import  CustomersList  from  './CustomersList'
      import  CustomerCreateUpdate  from  './CustomerCreateUpdate'
      import  './App.css';
      

      BrowserRoutermantiene la IU sincronizada con la URL utilizando la ](https://developer.mozilla.org/en-US/docs/Web/API/History_API)API de historial HTML5[.

      A continuación, cree un diseño base que proporcione el componente básico que envolverá el componente BrowserRouter:

      ~/djangoreactproject/frontend/src/App.js

      ...
      
      const  BaseLayout  = () => (
      <div  className="container-fluid">
          <nav  className="navbar navbar-expand-lg navbar-light bg-light">
              <a  className="navbar-brand"  href="https://www.digitalocean.com/#">Django React Demo</a>
              <button  className="navbar-toggler"  type="button"  data-toggle="collapse"  data-target="#navbarNavAltMarkup"  aria-controls="navbarNavAltMarkup"  aria-expanded="false"  aria-label="Toggle navigation">
              <span  className="navbar-toggler-icon"></span>
          </button>
          <div  className="collapse navbar-collapse"  id="navbarNavAltMarkup">
              <div  className="navbar-nav">
                  <a  className="nav-item nav-link"  href="/">CUSTOMERS</a>
                  <a  className="nav-item nav-link"  href="http://www.digitalocean.com/customer">CREATE CUSTOMER</a>
              </div>
          </div>
          </nav>
          <div  className="content">
              <Route  path="/"  exact  component={CustomersList}  />
              <Route  path="/customer/:pk"  component={CustomerCreateUpdate}  />
              <Route  path="/customer/"  exact  component={CustomerCreateUpdate}  />
          </div>
      </div>
      )
      

      Utilizamos el componente Route para definir las rutas de nuestra aplicación; el componente que el enrutador debe cargar cuando se encuentra una coincidencia. Cada ruta requiere un path que especifique la ruta que se debe seguir y un component que indique el componente que se debe cargar. La propiedad exact le indica al enrutador que siga la trayectoria exacta.

      Por último, cree el componente App, el componente root o de nivel superior de nuestra aplicación de React:

      ~/djangoreactproject/frontend/src/App.js

      ...
      
      class  App  extends  Component {
      
      render() {
          return (
          <BrowserRouter>
              <BaseLayout/>
          </BrowserRouter>
          );
      }
      }
      export  default  App;
      

      Hemos envuelto el componente BaseLayout con el componente BrowserRouter, dado que nuestra aplicación está diseñada para ejecutarse en un navegador.

      El archivo completo se ve de este modo:

      ~/djangoreactproject/frontend/src/App.js

      import React, { Component } from 'react';
      import { BrowserRouter } from 'react-router-dom'
      import { Route, Link } from 'react-router-dom'
      
      import  CustomersList from './CustomersList'
      import  CustomerCreateUpdate  from './CustomerCreateUpdate'
      import './App.css';
      
      const BaseLayout = () => (
        <div className="container-fluid">
      <nav className="navbar navbar-expand-lg navbar-light bg-light">
        <a className="navbar-brand" href="https://www.digitalocean.com/#">Django React Demo</a>
        <button className="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavAltMarkup" aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation">
          <span className="navbar-toggler-icon"></span>
        </button>
        <div className="collapse navbar-collapse" id="navbarNavAltMarkup">
          <div className="navbar-nav">
            <a className="nav-item nav-link" href="/">CUSTOMERS</a>
            <a className="nav-item nav-link" href="http://www.digitalocean.com/customer">CREATE CUSTOMER</a>
      
          </div>
        </div>
      </nav>  
      
          <div className="content">
            <Route path="/" exact component={CustomersList} />
            <Route path="/customer/:pk"  component={CustomerCreateUpdate} />
            <Route path="/customer/" exact component={CustomerCreateUpdate} />
      
          </div>
      
        </div>
      )
      
      class App extends Component {
        render() {
          return (
            <BrowserRouter>
              <BaseLayout/>
            </BrowserRouter>
          );
        }
      }
      
      export default App;
      

      Ahora que añadimos enrutamiento a nuestra aplicación, estamos listos para probarla. Navegue a http://localhost:3000. Debería ver la primera página de la aplicación:

      Página de inicio de la aplicación

      Con la implementación de esta aplicación, ahora, cuenta con la base para una aplicación de CRM.

      Conclusión

      En este tutorial, usted creó una aplicación de prueba utilizando Django y React. Utilizó Django REST framework para crear la API REST, Axios para consumir la API y Bootstrap 4 para dar estilo a su CSS. Puede encontrar el código fuente de este proyecto en este repositorio de GitHub.

      En la configuración de este tutorial, se utilizaron aplicaciones de front-end y back-end. Para obtener un enfoque diferente de la integración de React con Django, consulte este tutorial y este otro tutorial.

      Para obtener más información sobre la creación de aplicaciones con Django, puede seguir la serie de desarrollo de Django. También puede consultar la documentación oficial de Django.



      Source link