Programari Lliure, Tècnic

Django – creació ràpida i dinàmica de Web Apps

django-logoBreu tutorial sobre la creació d’un web dinàmic usant l’entorn Django basat en Python. Es tracta d’un entorn tipus Ruby on Rails, (comparació Django vs RoR) on es prioritza la convenció per sobre la configuració (convention over configuration), és a dir, no cal programar tot el que segueix la convenció, tan sols els casos “especials”. És més, és un entorn RAD  (Rapid Application Development) en que tenim l’aplicació funcional des del primer moment i l’anem construint iterativament (ideal per a fer prototipus funcionals).

Com a exemple crearem una aplicació per a gestió acadèmica de Competències Bàsiques, seguint les passes següents:

  1. Instal·lació
  2. Creació prototip d’administració
    1. Creem el projecte
    2. Creem una app dins el projecte
  3. Creació prototip d’usuari
  4. Evolució del prototip

Instal·lació

  • Guia d’instal·lació
  • Farem la instal·lació a Ubuntu, amb Python 3.2 (Django també funciona amb Python 2.7, 3.3…)
  • Assegurem que tenim Python 3:
    sudo apt-get install python3 python3-doc
    echo "alias python=python3" >> ~/.bash_aliases
    source ~/.bash_aliases
    
  • Instal·lem Django:
    • 1r Instal·lem PIP (el gestor de paquets de Python)
      • sudo apt-get install python3-pip
        
      • Si teniu una versió antiga d’Ubuntu és molt probable que no estigui disponible el paquet python3-pip, així que podeu fer el següent (+info):
        • sudo apt-get install python3-setuptools
          sudo easy_install3 pip
          sudo mv /usr/local/bin/pip /usr/local/bin/pip-3
          # en aquest cas quan useu el pip haureu de posar pip-3
          
    • 2n instal·lem Django des de PIP:
      • sudo pip install Django
        
    • 3r Comprovem Python 3 i accés a Django:
      • python
        # confirmar que indica que és la versió 3
        # teclejar el següent a la consola:
        import django
        print(django.get_version())
        
    • 4t Instalem complements
      • django-smart-selects: Útil per a fer camps desplegables que depenguin d’altres camps triats en el mateix formulari. Atenció només serveix per a relacions 1-a-n (no ManyToManyField!), suport Python3 encara amb alguna mancança (a continuació s’indica com “arreglar-ho”)
        
        
        •     sudo -H pip-3 install django-smart-selects
          
              # Arreglant problemes python3 enlloc de python2
              sudo vi /usr/local/lib/python3.2/dist-packages/smart_selects/utils.py
               # Python2(u"Unicode string") versus Python3("Unicode string")
               # Search and Replace :%s/u"/"/gc
          
              vi escola/urls.py # "escola" o el nom del vostre projecte django
              # Afegir
              urlpatterns = [
               # ...
               url(r'^chaining/', include('smart_selects.urls')),
              ]
              

Creació prototip d’administració

Creem el projecte

  • Primer tutorial de Django
  • Creem el projecte (que dins seu contindrà vàries apps per fer la feina)
    • django-admin startproject escola
      find escola/  # llistarà els fitxers que ha creat
      escola/
      escola/manage.py          # utilitat per a gestionar el web
      escola/escola
      escola/escola/wsgi.py     # definició per a servidors web compatibles amb http://wsgi.readthedocs.org/en/latest/what.html
      escola/escola/__init__.py # fitxer buit que indica que és un paquet de python
      escola/escola/settings.py # configuració del web
      escola/escola/urls.py     # índex de les URLs del projecte
      
  • Configuració inicial:
    • Base de Dades: usarem SQLite per facilitat (podeu configurar-ne d’altres).
      • La base de dades es guarda en un sol fitxer local.
      • Ideal per a fer prototipus, en la versió d’explotació és millor usar PostgreSQL…
      • No cal tocar res, ja està configurat per usar aquesta base de dades.
    • Internacionalització: ho configurarem en català (+codis) a la nostra zona horària (+codis).
    • vi escola/settings.py
      # Base de Dades: no cal tocar res
      DATABASES = {
       'default': {
       'ENGINE': 'django.db.backends.sqlite3',
       'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
       }
      }
      
      # Internacionalització
      LANGUAGE_CODE = 'ca'
      
      TIME_ZONE = 'Europe/Madrid'
      
      # Desem el fitxer i sortim a consola
      python manage.py migrate # així es crearà l'estructura inicial de la BD
      # haurà creat db.sqlite3
      
      # Comprovem la BD
      sudo apt-get install sqlite3
      sqlite3 db.sqlite3
      .schema # veureu totes les taules creades
      .quit
      
  • Provem el servidor:
    • La provem al servidor de desenvolupament (a Django podem fer canvis i proves al servidor de desenvolupament i quan ja n’estem segurs, passar-ho al servidor d’explotació)
    • python manage.py runserver
      firefox http://127.0.0.1:8000/
      

Creem una App dins el Projecte

  • Creem la nostra primera app (que inclourem dins el projecte que acabem de crear):
    • Django funciona amb un patró MVC (Model Vista Controlador) i per tant, cada element tindrà el seu codi associat (que d’entrada es genera automàticament i nosaltres el podem retocar).
    • python manage.py startapp registre
      # Mirem quina estructura crea:
      find registre
      registre/
      registre/views.py     # codi per a les VISTES
      registre/admin.py     # codi d'administració
      registre/tests.py     # tests unitaris
      registre/__init__.py  # indica paquet de python
      registre/migrations   # directori codi migracions progressives de la BD cada cop que es fa un canvi.
      registre/migrations/__init__.py
      registre/models.py    # codi per al MODELS
      
    • Creem el model de dades:
      • vi registre/models.py
        # Definim els models i camps:
        from django.db import models
        
        from smart_selects.db_fields import ChainedForeignKey, GroupedForeignKey
        # ChainedForeignKey: fa que un camp de múltiples valors depengui d'un altre (ex. un cop escollim el País s'omple la llista de Ciutats corresponent.
        # GroupedForeignKey: mostra un camp de múltiples valors agrupats (ex. mostra totes les Ciutats agrupades per País)
        
        class Alumne(models.Model):
         nom_text = models.CharField('nom', max_length=50)
         cognom1_text = models.CharField('primer cognom', max_length=50)
         cognom2_text = models.CharField('segon cognom', max_length=50)
         naixement_date = models.DateField('data de naixement')
        
         def __str__(self):
         return self.nom_text + ' ' + self.cognom1_text + ' ' + self.cognom2_text
        
        
        class Competencia(models.Model):
         nom_text = models.CharField(max_length=200)
         descripcio_text = models.TextField('descripció', max_length=600)
        
         def __str__(self):
          return self.nom_text
        
        
        class Activitat(models.Model):
         nom_text = models.CharField('nom', max_length=200)
         descripcio_text = models.TextField('descripció', max_length=600)
        
         def __str__(self):
          return self.nom_text
        
        
        class CompetenciaActivitat (models.Model):
         activitat = models.ForeignKey(Activitat)
         competencia = models.ForeignKey(Competencia)
        
         def __str__(self):
          return '"' + str(self.competencia) + '" a l"activitat "' + str(self.activitat) + '"'
        
        
        class Registre(models.Model):
         NOVELL = 0
         APRENENT = 1
         AVANCAT = 2
         EXPERT = 3
         GRAU_ASSOLIMENT_COMPETENCIA = (
         (NOVELL , 'Novell' ),
         (APRENENT , 'Aprenent' ),
         (AVANCAT , 'Avancat' ),
         (EXPERT , 'Expert' ),
         )
        
         alumne = models.ForeignKey(Alumne) # many-to-one
         activitat = models.ForeignKey(Activitat) # many-to-one
         #competenciaActivitat = models.ForeignKey(CompetenciaActivitat)
         # ChainedForeignKey: usem smart-selects per mostar només les competències d'aquella activitat
         competenciaActivitat = ChainedForeignKey(
          CompetenciaActivitat,
          chained_field="activitat",
          chained_model_field="activitat",
          show_all=False,
          auto_choose=True
         )
         ini_date = models.DateTimeField('inici')
         end_date = models.DateTimeField('final')
         grau_int = models.PositiveSmallIntegerField("grau d'assoliment", choices=GRAU_ASSOLIMENT_COMPETENCIA, default=0)
         coment_text = models.TextField('comentari', max_length=200)
        
         def __str__(self):
          return str(self.alumne) + " competència " + str(self.competenciaActivitat)
        
        
      • l’ordre de definició NO és important, si hem de referir-nos a alguna classe que encara no hem definit, n’hi ha prou amb posar-la entre comentes.
      • +info sobre:
    • Creem l’app:
      • vi escola/settings.py
        # Afegim la app "registre":
        INSTALLED_APPS = (
         'django.contrib.admin',
         'django.contrib.auth',
         'django.contrib.contenttypes',
         'django.contrib.sessions',
         'django.contrib.messages',
         'django.contrib.staticfiles',
         'registre',
        )
        
        # Creem el codi per a afegir l'app "registre" a la BD
        python manage.py makemigrations registre # crea codi
        python manage.py sqlmigrate registre 0001 # genera SQL
        python manage.py check # comprova que no hi haurà problemes
        python manage.py migrate # aplica SQL
        
    • Omplim les dades:
      • Creem un formulari per afegir dades:
        • vi registre/admin.py
          # Afegir el següent contingut:
          from .models import Alumne, Competencia, Activitat, CompetenciaActivitat, Registre
          
          admin.site.register(Alumne)
          admin.site.register(Competencia)
          admin.site.register(Registre)
          
          class CompetenciaActivitatInline(admin.StackedInline): # usar TabularInline per entrada en forma de taula
           model = CompetenciaActivitat
           extra = 3
          
          
          class ActivitatAdmin(admin.ModelAdmin):
           fieldsets = [
            ('Nom', {'fields': ['nom_text']}),
            ('Descripció', {'fields': ['descripcio_text']}),
           ]
           inlines = [CompetenciaActivitatInline]
          
          admin.site.register(Activitat, ActivitatAdmin)
          
      • python manage.py createsuperuser
        # Introdueix un nom d'usuari i clau
        python manage.py runserver
        firefox http://127.0.0.1:8000/admin
        

Evolució del prototip

  • python manage.py makemigrations registre
    python manage.py sqlmigrate registre <numMigracioSortidaAnterior>
    python manage.py check
    python manage.py migrate
    
    python manage.py runserver
    firefox http://127.0.0.1:8000/admin
    

Extensions

Llistat de Ciutats

Camps desplegables que depenen d’altres

  • Alternatives per a fer que uns camps desplegables depenguin de seleccions fetes en altres camps anteriors en el mateix formulari:
  • Sobre django-smart-selects: atenció només serveix per a relacions 1-a-n (no ManyToManyField!), suport Python3 encara amb alguna mancança (a continuació s’indica com “arreglar-ho”)
    • sudo -H pip-3 install django-smart-selects
      
      # Arreglant problemes python3 enlloc de python2
      sudo vi /usr/local/lib/python3.2/dist-packages/smart_selects/utils.py
       # Python2(u"Unicode string") versus Python3("Unicode string")
       #key1 = key1.replace(u"ä", u"a")
       #key1 = key1.replace(u"ö", u"o")
       #key1 = key1.replace(u"ü", u"u")
       #key1 = key1.replace(u"ß", u"ss")
       key1 = key1.replace("ä", "a")
       key1 = key1.replace("ö", "o")
       key1 = key1.replace("ü", "u")
       key1 = key1.replace("ß", "ss")
      
      # Proposta per crear una app d'exemple (opcional, no cal per a usar-ho al vostre projecte)
      python manage.py startapp test_smartselects
      
      vi escola/settings.py # "escola" o el nom del vostre projecte django
      # Afegir
      INSTALLED_APPS = (
       # ...
       'test_smartselects',
      )
      
      vi escola/urls.py # "escola" o el nom del vostre projecte django
      # Afegir
      urlpatterns = [
       # ...
       url(r'^chaining/', include('smart_selects.urls')),
      ]
      
      vi test_smartselects/models.py
      from django.db import models
      
      from smart_selects.db_fields import ChainedForeignKey, GroupedForeignKey
      
      class Continent(models.Model):
       name_text = models.CharField(max_length=50)
      
       def __str__(self):
        return self.name_text
      
      class Country(models.Model):
       name_text = models.CharField(max_length=50)
       continent = models.ForeignKey(Continent)
      
       def __str__(self):
        return self.name_text
      
      class City(models.Model):
       name_text = models.CharField(max_length=50)
       country = models.ForeignKey(Country)
      
       def __str__(self):
        return self.name_text
      
      class Location(models.Model):
       continent = models.ForeignKey(Continent)
      
       # ChainedForeignKey: mostra Països un cop escollit el continent
       country = ChainedForeignKey(
       Country,
       chained_field="continent",
       chained_model_field="continent",
       show_all=False,
       auto_choose=True
       )
       # GroupedForeignKey: mostra Països agrupats per Continents
       #country = GroupedForeignKey(Country, "continent")
      
       city = ChainedForeignKey(City, chained_field="country", chained_model_field="country")
       street = models.CharField(max_length=100)
      
       def __str__(self):
        return '' + str(self.continent) + '/' + str(self.country) + '/' + str(self.city) + '/' + str(self.street)
      
      </pre>
      <pre>vi test_smartselects/admin.py
      from django.contrib import admin
      
      from .models import Continent, Country, Area, Location
      
      admin.site.register(Continent)
      admin.site.register(Country)
      admin.site.register(Area)
      admin.site.register(Location)
      
      python manage.py makemigrations test_smartselects
      python manage.py sqlmigrate test_smartselects <numMigracioSortidaAnterior>
      python manage.py check
      python manage.py migrate
      
      python manage.py runserver
      firefox http://127.0.0.1:8000/admin
      
Anuncis

Deixa un comentari

Fill in your details below or click an icon to log in:

WordPress.com Logo

Esteu comentant fent servir el compte WordPress.com. Log Out / Canvia )

Twitter picture

Esteu comentant fent servir el compte Twitter. Log Out / Canvia )

Facebook photo

Esteu comentant fent servir el compte Facebook. Log Out / Canvia )

Google+ photo

Esteu comentant fent servir el compte Google+. Log Out / Canvia )

Connecting to %s