====== Integració de Django amb Reactjs ====== De manera simplificada, //Reactjs// és una biblioteca Javascript per desenvolupar aplicacions de pàgina única (SPA), amb una documentació molt detallada i ben estructurada. Per a aquest exemple, on gestionarem clients i els seus comptes associats, React servirà com a frontend, gestionant la interfície d'usuari (UI) a través de la petició al framework de Django i amb l'ajuda de Django REST Framework. Referències: * Web oficial de Reactjs: https://react.dev/ * Web oficial de Django Framework: https://www.djangoproject.com * Tutorial [[https://docs.djangoproject.com/en/stable/intro/tutorial01/|tutorial de la web oficial]]. {{tag> #FpInfor #Daw #DawMp06 #DawMp07 django framework python react javascript web}} ===== Creació del projecte ===== Els passos a seguir per crear el projecte a Django són els següents (si tens dubtes o vols repassar el procés, et recomano que revisis el [[django|tutorial]]): 1. Crea el projecte "project" a **l'entorn virtual**. Recorda instal·lar Django dins l'entorn virtual activat 2. Crea l'aplicació "customers". 3. Configura el projecte (urls, localització) i verifica que s'accedeix correctament des del navegador. 4. Crea el model de dades (dins del fitxer //models.py// de l'aplicació customers). En aquest cas, treballarem amb les dues classes següents: * **Customer**: customer_id (IntegerField) i customer_name (CharField(200)) * **Account**: account_id (IntegerField),customer (ForeignKey Customer) description (CharField(200)), limit(IntegerField) --> Proposta d'implementació Customer i Account# class Project(models.Model): class Customer(models.Model): customer_id = models.IntegerField(default=0) customer_name = models.CharField(max_length=200) def __str__(self): return self.customer_name class Account(models.Model): account_id = models.IntegerField(default=0) customer = models.ForeignKey(Customer, on_delete=models.CASCADE) description = models.CharField(max_length=200) limit = models.IntegerField(default=0) def __str__(self): return self.description <-- Aquest model no contempla que les claus primàries siguin autonumèriques ni la cardinalitat de la interrelació (//1 client pot tenir N comptes, però 1 compte només pot estar associat a 1 client//). Com ho faries? Recorda que estem treballant a SQlite. Quins passos caldria fer per treballar contra una base de dades MySQL? 5. Registra el model de dades (a //admin.py//), afegeix l'aplicació (a //settings.py//) i migra el model per poder realitzar les operacions CRUD. 6. Crea el superadmin, comprova que pots accedir correctament al site d'administració i executa instruccions CRUD per validar el model. Hauries de veure una pantalla similar a aquesta: {{ ::admin_django.jpg |}} ===== Integració de Reactjs (Creació de l'API) ===== **Important!** Verifica que tens instal·lat //node.js// a la teva màquina i, en cas contrari, instal·la la darrera versió. 1. Instal·la node.js al teu entorn virtual: (env) $ apt install nodejs \\ 2. Instal·la Django REST Framework (env) $ pip install djangorestframework \\ 3. Instal·la Django-cors-headers (env) $ pip install django-cors-headers \\ 4. Obre el fitxer //setting.py// i afegeix les dues dependències que s'acaben d'instal·lar a //INSTALL_APPS// com es mostra a continuació: INSTALLED_APPS = [ 'customers.apps.CustomersConfig', 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'corsheaders', 'rest_framework', ] També cal que el port localhost 3000 estigui en la llista blanca al fitxer //settings.py//. Si no ho fem, hi haurà un bloc entre el localhost:8000 i el localhost:3000. Afegeix el codi següent per a aconseguir el mateix: # White listing the localhost:3000 port # for React CORS_ORIGIN_WHITELIST = ( 'http://localhost:3000', ) 5. A la secció MIDDLEWARE cal afegir la configuració de les capçaleres dels cors, tal com es mostra a continuació: MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'corsheaders.middleware.CorsMiddleware' ] És important que vagis revisant el terminal, per veure que en cada modificació del fitxer //settings.py// no dóna error l'aplicació. 6. Ara hem de crear els Serializers per al model de dades de Customers. Els Serializers són responsables de convertir instàncies de model a JSON. Això ajudarà el frontend a treballar amb les dades rebudes fàcilment. El JSON és l'estàndard per a l'intercanvi de dades al web. Crea un fitxer dins de la carpeta "customers" i anomena'l //serializers.py//. Dins de la carpeta afegeix el codi següent: # import serializers from the REST framework from rest_framework import serializers # import the Customer data model from .models import Customer # create a serializer class class CustomerSerializer(serializers.ModelSerializer): # create a meta class class Meta: model = Customer fields = ('customer_id', 'customer_name') 7. Ara és el moment de crear les vistes. Per tant, obre el fitxer //views.py// i afegeix el codi següent al fitxer: # import view sets from the REST framework from rest_framework import viewsets # import the CustomerSerializer from the serializer file from .serializers import CustomerSerializer # import the Customer model from the models file from .models import Customer # create a class for the Customer model viewsets class CustomerView(viewsets.ModelViewSet): # create a serializer class and # assign it to the CustomerSerializerclass serializer_class = CustomerSerializer # define a variable and populate it # with the Customer list objects queryset = Customer.objects.all() 8. Obriu el fitxer urls.py i afegeix el codi següent: from django.urls import include,path from customers import views # import routers from the REST framework # it is necessary for routing from rest_framework import routers # create a router object router = routers.DefaultRouter() # register the router router.register(r'customers',views.CustomerView, 'customers') urlpatterns = [ path("", views.index), path("customers/", include("customers.urls")), path("admin/", admin.site.urls), path('api/', include(router.urls)) ] Aquest és el pas final per a crear l'API REST. Ara podem realitzar totes les operacions CRUD. Els encaminadors ens permeten fer consultes. Per exemple, si anem a les "customers", això retornarà la llista de els clients. Ara comprovem si estem avançant en la direcció correcta. Per tant, executeu el servidor i navegueu fins a l'URL següent: localhost:8000/api Si tot va bé, obtindrem el següent resultat: {{ ::api.jpg |}} Com podeu veure, la nostra API està en marxa. Ara, si provem d'accedir als "customers", podrem veure i interactuar amb les nostres tasques: localhost:8000/api/customers {{ ::api_customers_options.jpg |}} Fins i tot, podem canviar el format dels resultats (per exemple, retornar en formar JSON): {{ ::api_customers_json.jpg |}} ===== Integració de Reactjs (FrontEnd) ===== 1. Crea una "boilerplate" de l'aplicació Js React: npx create-react-app frontend on npx significa //Node Package Executable// Només funcionarà la sentència anterior amb versions de node.js superiors a la 14.0, així que si et dóna error, caldrà que l'actualitzis. Pots seguir aquest [[https://www.cyberithub.com/how-to-install-the-latest-version-of-node-js-on-ubuntu-debian/|tutorial]]. Tingues paciència, perquè aquest pas trigarà força! 2. Instal·la reactstrap i bootstrap al projecte (per donar una mica d'estil al disseny de la interfície d'usuari): npm install reactstrap bootstrap 3. Des de la terminal, accedeix al directori de frontend i executa la següent instrucció, per tal de verificar que tot funciona correctament: npm start Si és així, et sortirà una pantalla similar a aquesta (en l'adreça localhost:3000): {{ ::react_app.png |}} 4. Obre el fitxer //App.js// a la carpeta del frontend. Elimina el codi existent i substitueix-lo pel codi següent: import "./App.css"; function App() { return

Gestió de clients

; } export default App;
5. El pas anterior era un exemple per validar l'aplicació. Substitueix-lo, en el fitxer //App.js//, pel codi següent: // import Component from the react module import React, { Component } from "react"; import Modal from "./components/Modal"; import axios from 'axios'; class App extends Component { constructor(props) { super(props); this.state = { viewCompleted: false, activeItem: { title: "", description: "", completed: false }, customersList: [] }; } componentDidMount() { this.refreshList(); } refreshList = () => { axios //Axios to send and receive HTTP requests .get("http://localhost:8000/api/customers/") .then(res => this.setState({ customersList: res.data })) .catch(err => console.log(err)); }; displayCompleted = status => { if (status) { return this.setState({ viewCompleted: true }); } return this.setState({ viewCompleted: false }); }; renderTabList = () => { return (
this.displayCompleted(true)} className={this.state.viewCompleted ? "active" : ""} > completed this.displayCompleted(false)} className={this.state.viewCompleted ? "" : "active"} > Incompleted
); }; renderItems = () => { const { viewCompleted } = this.state; const newItems = this.state.taskList.filter( (item) => item.completed === viewCompleted ); return newItems.map((item) => (
  • {item.title}
  • )); }; toggle = () => { //add this after modal creation this.setState({ modal: !this.state.modal }); }; handleSubmit = (item) => { this.toggle(); alert("save" + JSON.stringify(item)); if (item.id) { // if old post to edit and submit axios .put(`http://localhost:8000/api/tasks/${item.id}/`, item) .then((res) => this.refreshList()); return; } axios .post("http://localhost:8000/api/customers/", item) .then((res) => this.refreshList()); }; handleDelete = (item) => { alert("delete" + JSON.stringify(item)); axios .delete(`http://localhost:8000/api/tasks/${item.id}/`) .then((res) => this.refreshList()); }; createItem = () => { const item = { title: "", description: "", completed: false }; this.setState({ activeItem: item, modal: !this.state.modal }); }; editItem = (item) => { this.setState({ activeItem: item, modal: !this.state.modal }); }; render() { return (

    GFG Task Manager

    {this.renderTabList()}
      {this.renderItems()}
    {this.state.modal ? ( ) : null}
    ); } } export default App;
    6. Obre el fitxer //Index.css//, neteja el CSS que hi ha a dins i afegeix el següent codi al fitxer: .customer-title { cursor: pointer; } .completed-customer { text-decoration: line-through; } .customer-list > span { padding: 5px 8px; border: 1px solid rgb(7, 167, 68); border-radius: 10px; margin-right: 5px; cursor: pointer; } .customer-list > span.active { background-color: rgb(6, 139, 12); color: #fff; } 7. Crea una carpeta nova anomenada "Components" al directori //src// i afegeix un fitxer //Modal.js//. Després, afegeix el codi següent: import React, { Component } from "react"; // importing all of these classes from reactstrap module import { Button, Modal, ModalHeader, ModalBody, ModalFooter, Form, FormGroup, Input, Label } from "reactstrap"; class CustomModal extends Component { constructor(props) { super(props); this.state = { activeItem: this.props.activeItem }; } // changes handler to check if a checkbox is checked or not handleChange = e => { let { name, value } = e.target; if (e.target.type === "checkbox") { value = e.target.checked; } const activeItem = { ...this.state.activeItem, [name]: value }; this.setState({ activeItem }); }; // rendering modal in the custommodal class received toggle and on save as props, render() { const { toggle, onSave } = this.props; return ( Customer Item
    {/* 3 formgroups 1 title label */} {/* 2 description label */} {/* 3 completed label */}
    {/* create a modal footer */}
    ); } } export default CustomModal
    8. Fes els canvis indicats a continuació al fitxer //index.js//: import React from "react"; import ReactDOM from "react-dom"; import "./index.css"; import App from "./App"; import "bootstrap/dist/css/bootstrap.min.css"; ReactDOM.render( , document.getElementById("root") ); 9. Per fer les peticions als endpoints de l'API al servidor del framework de Django, necessitarem instal·lar l'Axios. Utilitza l'ordre següent dins de la carpeta del framework per a instal·lar l'Axios: npm install axios I, amb aquest pas, ja tenim una aplicació Fullstack Django-React utilitzant el framework REST Django per establir la comunicació entre el frontend i el backend. **Exercici:** Aplica la serialització de manera que es puguin gestionar els comptes associats als clients. \\