Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Django

 Django

#WIP

A04788bd45feba612272eaef0f4a01ee?s=128

Henoc Díaz

November 04, 2015
Tweet

Transcript

  1. Django (/ˈdʒæŋɡoʊ/ jang-goh) Not di-jang-goh ! @henocdz

  2. URL's Punto de acceso a nuestra app @henocdz

  3. Cómo funcionan? Se forman a través de expresiones regulares, por

    ejemplo: ^students/$ Si tuvieramos un dominio ejemplo.com, correspondería a: ejemplo.com/students/ @henocdz
  4. Más ejemplos # Parámetros con valor dinámico en las URLs

    ```python ^students/(.*)/$ @henocdz
  5. Forms Nos permiten tener de una manera más estructurada la

    entrada de información por parte del usuario y/o servicios externos. @henocdz
  6. Cómo crear un formulario? from django import forms # Para

    este caso en particular, # es buena idea importar todo el módulo class StudentForm(forms.Form): # Al igual que para modelos, # definimos los campos como atributos de clase nombre = forms.CharField() apellidos = forms.CharField() edad = forms.IntegerField() website = forms.URLField() @henocdz
  7. Cómo instanciar un formulario sin datos # app/views.py from django.shortcuts

    from app.forms import StudentForm def form_view(request): student_form = StudentForm() return render(request, 'app/form.html', {'form': student_form}) @henocdz
  8. Cómo mostrarlo en un template? <!-- Consideremos que desde la

    vista envíamos la variable form--> <h1> Opcion 1: </h1> <form method="POST"> <!-- Podemos utilizar alguno de estos tres métodos --> {{ form.as_p }} {{ form.as_table }} {{ form.as_ul }} </form> Esto nos mostrará todos los campos @henocdz
  9. Como alternativa, podemos iterar o acceder manualmente a todos los

    campos que tiene el formulario y renderearlos en el template a nuestro gusto <!-- Consideremos que desde la vista envíamos la variable form--> <h1> Opcion 2: </h1> <form method="POST"> {{ form.non_field_errors }} {% for campo in form %} {{ campo.label_tag }} <!-- <label /> --> {{ campo.errors }} <!-- <ul /> --> {{ campo }} <!-- <input|select|checkbox /> --> {% endfor %} </form> @henocdz
  10. <!-- Consideremos que desde la vista envíamos la variable form-->

    <h1> Opcion 3: </h1> <form method="POST"> {{ form.non_field_errors }} {{ form.apellidos.label_tag }} <!-- <label /> --> {{ form.apellidos.errors }} <!-- <ul /> --> {{ form.apellidos }} <!-- <input|select|checkbox /> --> {{ form.nombre.label_tag }} <!-- <label /> --> {{ form.nombre.errors }} <!-- <ul /> --> {{ form.nombre }} <!-- <input|select|checkbox /> --> </form> @henocdz
  11. Formulario con datos ligados def form_view(request): if request.method == 'POST':

    student_form = StudentForm(request.POST) if student_form.is_valid(): # form.is_valid(): nos dirá si los datos ingresados # cumplen con el formato correcto # Investigar: Messages framework return redirect('/') else: student_form = StudentForm() return render(request, 'app/form.html', {'form': student_form}) @henocdz
  12. Widgets Modifican el tipo de input/select/checkbox/etc que se mostrará en

    HTML así como la manera en que recolectará los datos. Por ejemplo: @henocdz
  13. from django import forms class StudentForm(forms.Form): GENERO_CHOICES = ( (0,

    'Masculino'), (1, 'Femenino') ) # ... genero = forms.IntegerField( widget=forms.SelectInput(choices=GENERO_CHOICES) ) website = forms.URLField() @henocdz
  14. Lo anterior mostraría esto en HTML <form> ... <select id="id_genero">

    <option value="0">Masculino</option> <option value="1">Femenino</option> </select> </form> @henocdz
  15. Validando formularios @henocdz

  16. class StudentForm(forms.Form): # ... username = forms.CharField() password = forms.CharField(widget=forms.PasswordInput())

    website = forms.CharField() def clean_website(self): website = self.cleaned_data['website'] if len(website) < 5: raise forms.ValidationError('Longitud de website inválida') def clean(self): # ... if not self.cleaned_data['password'] and not self.cleaned_data['username']: raise forms.ValidationError('Debes indicar password y nombre de usuario') @henocdz
  17. Model Forms Podemos crear formularios a partir de un modelo

    e incluir o excluir los campos que queramos. # Con este modelo... from django.db import models class Student(models.Model): username = models.CharField(max_length=40) password = models.CharField(max_length=30) registro = models.DateTimeField(auto_now_add=True) @henocdz
  18. # Podemos crear este formulario from django import forms from

    app.models import Student class StudentForm(forms.ModelForm): class Meta: # Esta clase es importante # Aquí _configuramos_ nuestro formulario model = Student exclude = ['registro'] @henocdz
  19. # O algo más sofisticado con Widgets from django import

    forms from app.models import Student class StudentForm(forms.ModelForm): class Meta: # Esta clase es importante # Aquí _configuramos_ nuestro formulario model = Student fields = ['username', 'password'] widgets = { 'password': forms.PasswordInput() } @henocdz
  20. Class Based Views Nos permiten organizar la lógica de vistas

    de mejor manera, además evitar duplicidad de código. @henocdz
  21. Cómo usar una vista en un formulario @henocdz

  22. Distintos tipos de Vistas @henocdz

  23. Sesiones en Django Por default, el framework guarda información relacionada

    a la sesiones en el lado del servidor dentro de una tabla de la base de datos y al cliente solo le envía un ID de sesión para después poder extraer la información nuevamente. Más sobre el tema: https:/ /docs.djangoproject.com/en/dev/topics/ http/sessions/ @henocdz
  24. Cómo manipular las sesiones Podemos crear o extraer sesiones como

    si fuese un diccionario, aunque en realidad es un modelo que se se puede comportar como diccionario con el poder de __magic__ methods Primero, veamos como leer todo lo que tenemos en la sesión: def my_view(request): print(request.session.items()) @henocdz
  25. Crear un nuevo valor en la sesión def my_view(request): request.session['is_jedi']

    = False return HttpResponse('...') Extraer valor de una sesión def my_view(request): is_jedi = request.session.get('is_jedi', True) # Alternativa NO recomendada: # request.session['is_jedi'] return HttpResponse() @henocdz
  26. ¿Qué sesiones crear? Dependerá de cada aplicación. Y ... ¿cómo

    hago persistente el login de un usuario? @henocdz
  27. Sistema de usuarios de Django Django incluye por default un

    sistema de usuarios bastante genérico, podemos encontrarlo en: from django.contrib.auth.models import User Y después podemos... @henocdz
  28. Crear usuarios from django.contrib.auth.models import User def my_view(request): u =

    User.objects.create(**params) @henocdz
  29. Relacionarlos from django.db import models class Task(models.Model): user = models.ForeignKey('django.contrib.auth.models.User')

    ... @henocdz
  30. Y lo más importante @henocdz

  31. Autenticarlos from django.contrib.auth import authenticate def my_view(request): user = authenticate(username='eme',

    password='123456') if not user: return HttpResponse('No existe el usuario') Aunque esto no significa que el usuario esté logeado y este login persista, para eso... @henocdz
  32. Django Login from django.contrib.auth import login def my_view(request): ... login(user)

    return HttpResponse('Bienvenido!') @henocdz
  33. Pero no todo es por arte de magia . .

    . ¿o sí? ! @henocdz
  34. No @henocdz

  35. def authenticate(**credentials): for backend, backend_path in _get_backends(return_tuples=True): try: inspect.getcallargs(backend.authenticate, **credentials)

    except TypeError: # This backend doesn't accept these credentials as arguments. Try the next one. continue try: user = backend.authenticate(**credentials) except PermissionDenied: # This backend says to stop in our tracks - this user should not be allowed in at all. return None if user is None: continue # Annotate the user object with the path of the backend. user.backend = backend_path return user # The credentials supplied are invalid to all backends, fire signal user_login_failed.send(sender=__name__, credentials=_clean_credentials(credentials)) @henocdz
  36. Django Authentication Backends @henocdz

  37. ¿ Qué es un backend? Una clase que tiene dos

    métodos básicos authenticate y get_user, los cuales definen de donde extraer el usuario que se va a logear, así: from django.contrib.auth.backends import ModelBackend class LeadBackend(ModelBackend): def authenticate(self, username=None, auth_lead=False): if not username or not auth_lead: return None return get_object_or_None(ClientUser, email=username) def get_user(self, user_pk): """Returns ClientUser based on their PK""" return get_object_or_None(ClientUser, pk=user_pk) @henocdz
  38. ¿Cómo sabe Django con que Backends probar? Toma los que

    estén definidos en AUTHENTICATION_BACKENDS dentro de settings.py que por default es: ... AUTHENTICATION_BACKENDS = ( 'django.contrib.auth.backends.ModelBackend', ) ... @henocdz
  39. Para agregar más solo debes escribir una clase similar a

    la anterior y especificar aquí qué backends utilizar. Más info: https:/ /docs.djangoproject.com/en/dev/topics/auth/ customizing/#authentication-backends @henocdz
  40. ¿Dónde quedó la diversión? ! @henocdz

  41. Sistema de usuarios extendido ¿No les ha pasado que tienen

    distintos tipos de usuarios pero estos comparten ciertos atributos en común y algunos son muy particulares según el tipo de usuario? Podemos simplificar esto, pero antes Modelos Abstractos @henocdz
  42. Modelos abstractos Para este tipo de modelos no se crea

    una tabla en la base de datos, como estamos acostumbrados, únicamente nos sirven como base (herencia) para otros modelos y los atributos que tenga, se crearán en la tabla del modelo que utiliza al modelo abstracto @henocdz
  43. Por ejemplo from django.db import models class Usuario(models.Model): nombre =

    models.CharField(max_length=100) password models.CharField(max_length=30) class Meta: # Aquí es donde la magia ocurre abstract = True @henocdz
  44. Para después class Company(Usuario): direccion = models.TextField() class Empleado(Usuario): nss

    = models.CharField(max_length=11) @henocdz
  45. ¿Y el sistema de usuarios extendido? @henocdz

  46. Primero necesitamos un modelo base: from django.contrib.auth.models import AbstractBaseUser as

    DjAbstractBaseUser, PermissionsMixin class BaseUser(DjAbstractBaseUser, PermissionsMixin): def __str__(self): return "{}".format(self.pk) @henocdz
  47. Después un modelo abstracto que defina los campos en común

    class AsistiaAbstractBaseUser(BaseUser): """Defines common attributes among Asistia User Types""" email = models.EmailField(unique=True, db_index=True) # NOQA is_admin = models.BooleanField(default=False) is_active = models.BooleanField(default=False) last_edit_date = models.DateTimeField(auto_now=True) objects = UserManager() USERNAME_FIELD = 'email' REQUIRED_FIELDS = ['first_name', 'surname'] class Meta: # This model should not be create in the database abstract = True @property def is_staff(self): """Returns if the user can access to Django Admin site""" return self.is_admin @henocdz
  48. ¿UserManager? Contiene las funciones a utilizar para crear un usuario,

    por ejemplo con el comando python manage.py createsuperuser @henocdz
  49. from django.contrib.auth.models import BaseUserManager class UserManager(BaseUserManager): def create_user(self, email, **kwargs):

    if not email: raise ValueError('Users must have an email') user = self.model( email=self.normalize_email(email), ... **kwargs ) password = kwargs.pop('password', None) user.set_password(password) return user def create_superuser(self, *args, **kwargs): user = self.create_user(*args, **kwargs) user.is_admin = True user.is_active = True user.is_superuser = True return user @henocdz
  50. Y después en cada tipo de usuario que tengamos, debemos

    heredar de el modelo abstracto class DefaultUser(AbstractBaseUser): """ Generic User Type - The one used in AUTH_USER_MODEL for Django Settings """ pass @henocdz
  51. Y lo más importante, decirle a Django que Modelo de

    usuario utilizar por default para python manage.py createsuperuser entre otras cosas. # En nuestro settings.py AUTH_USER_MODEL = 'users.DefaultUser' @henocdz