$30 off During Our Annual Pro Sale. View Details »

Django Tricks (2)

Django Tricks (2)

Curso de aplicaciones adicionales a tener en cuenta para un proyecto Django:
* django-crispy-forms
* south
* Pruebas y Selenium

Carlos Hernando

November 15, 2012
Tweet

More Decks by Carlos Hernando

Other Decks in Technology

Transcript

  1. Django Tricks
    José Ignacio Galarza @igalarzab
    Carlos Hernando @chernando

    View Slide

  2. django crispy forms
    https://github.com/maraujop/django-crispy-forms

    View Slide

  3. Crispy forms!
    {% load crispy_forms_tags %}

    {{ my_formset|crispy }}

    View Slide

  4. Crispy forms!
    {% load crispy_forms_tags %}

    {{ my_formset|crispy }}

    El formulario es compatible Twitter Bootstrap

    View Slide

  5. Un formulario
    from crispy_forms.helper import FormHelper
    class ExampleForm(forms.Form):
    [...]
    def __init__(self, *args, **kwargs):
    self.helper = FormHelper()
    super(ExampleForm, self).__init__(*args,
    **kwargs)

    View Slide

  6. Personalizamos el formulario
    [...]
    self.helper.form_id = 'id-exampleForm'
    self.helper.form_class = 'blueForms'
    self.helper.form_method = 'post'
    self.helper.form_action = 'submit_survey'
    self.helper.add_input(Submit('submit', 'Submit'))

    View Slide

  7. Y el template queda
    {% load crispy_forms_tags %}
    {% crispy example_form %}

    View Slide

  8. Aún más personalizado
    from crispy_forms.layout import Layout, Fieldset, ButtonHolder,
    Submit
    self.helper.layout = Layout(
    Fieldset(
    'first arg is the legend of the fieldset',
    'field1',
    'field2'
    ),
    ButtonHolder(
    Submit('submit', 'Submit', css_class='button white')
    )

    View Slide

  9. Y el template queda igual
    {% load crispy_forms_tags %}
    {% crispy example_form %}
    WIN

    View Slide

  10. Más de crispy forms
    FormSets
    Cambiar layouts al vuelo
    Personalizar... todo :-)
    http://django-crispy-forms.readthedocs.org/

    View Slide

  11. south

    View Slide

  12. Nuestro modelo cambia
    class Persona(models.Model):
    nombre = models.CharField(...)
    apellidos = models.CharField(...)

    View Slide

  13. Nuestro modelo cambia
    class Persona(models.Model):
    nombre = models.CharField(...)
    apellidos = models.CharField(...)
    email = models.EmailField(...)

    View Slide

  14. Ok, hago un syncdb :)
    ./manage.py syncdb
    Creating tables ...
    Creating table tutsouth_persona
    Installing custom SQL ...
    Installing indexes ...
    Installed 0 object(s) from 0 fixture(s)
    :-D

    View Slide

  15. Pero...
    >>> p = Persona()
    >>> p.save()
    Traceback (most recent call last):
    ...
    DatabaseError: table tutsouth_persona has no
    column named email
    ;-(

    View Slide

  16. FAIL
    syncdb no modifica

    View Slide

  17. Soluciones
    Django
    ○ Borrón y cuenta nueva
    manage flush && manage syncdb
    ○ Modificar manualmente las tablas
    manage sql

    View Slide

  18. Soluciones
    Django
    ○ Borrón y cuenta nueva
    manage flush && manage syncdb
    ○ Modificar manualmente las tablas
    manage sql
    South

    View Slide

  19. south
    South brings migrations to Django applications.
    ● Automatic migration creation
    ● Database independence
    ● App-savvy
    ● VCS-proof

    View Slide

  20. Migraciones
    RAE:
    Acción y efecto de pasar de un país a otro para
    establecerse en él.
    south:
    [...] a way of changing your database schema
    from one version into another [...]

    View Slide

  21. Migraciones
    RAE:
    Acción y efecto de pasar de un país a otro para
    establecerse en él.
    south:
    [...] a way of changing your database schema
    from one version into another [...]
    En ambos sentidos.

    View Slide

  22. south en dos patadas
    Migraciones:
    Primera:
    manage.py schemamigration APP --initial
    Siguientes:
    manage.py schemamigration APP --auto
    Aplicar:
    manage.py migrate [APP]

    View Slide

  23. Migraciones complicadas
    ? The field 'Votacion.autor' does not have a default specified, yet
    is NOT NULL.
    ? Since you are making this field non-nullable, you MUST specify
    a default
    ? value to use for existing rows. Would you like to:
    ? 1. Quit now, and add a default to the field in models.py
    ? 2. Specify a one-off value to use for existing columns now
    ? Please select a choice:

    View Slide

  24. Durante el desarrollo
    Reutilizar la migración:
    manage.py schemamigration --update --auto
    Conflictos
    manage.py migrate --merge
    Listar:
    manage.py migrate --list

    View Slide

  25. Más cosas interesantes
    Datamigrations
    ORM Freezing
    Dependencias
    ...
    http://south.readthedocs.org/

    View Slide

  26. View Slide

  27. Pruebas :-?
    ● When you’re writing new code, you can use
    tests to validate your code works as expected.
    ● When you’re refactoring or modifying old code,
    you can use tests to ensure your changes haven’
    t affected your application’s behavior
    unexpectedly.

    View Slide

  28. Pruebas :-?
    ● When you’re writing new code, you can use
    tests to validate your code works as expected.
    ● When you’re refactoring or modifying old code,
    you can use tests to ensure your changes haven’
    t affected your application’s behavior
    unexpectedly.
    Sí o sí 0:-)

    View Slide

  29. Métodos disponibles
    unittest
    class MyFuncTestCase(unittest.TestCase):
    def testBasic(self):
    a = ['larry', 'curly', 'moe']
    self.assertEqual(my_func(a, 0), 'larry')
    doctest
    def my_func(a_list, idx):
    """
    >>> a = ['larry', 'curly', 'moe']
    >>> my_func(a, 0)
    'larry'

    View Slide

  30. unittest
    Forma parte de Python
    Cumplir dos condiciones:
    a. Heredar de unittest.TestCase
    b. El método empieza por test
    Django enriquece con django.utils.unittest

    View Slide

  31. Ejemplo
    import unittest
    class TestDePrueba(unittest.TestCase):
    def test_prueba_1_1(self):
    self.assertEquals(1 + 1, 2)
    def test_con_error(self):
    self.assertEquals(1 + 1, 2.1, "Intel detected!")

    View Slide

  32. Pruebas en Django
    Por defecto:
    APP/tests.py
    manage.py test [[[APP].TestCase].test_method]

    View Slide

  33. Modelos
    Bases de datos de prueba
    By default the test databases get their names by
    prepending test_ to the value of the NAME
    settings for the databases defined in
    DATABASES.
    Ejercicio para el lector: fixtures

    View Slide

  34. Vistas
    Test Client simula un navegador
    from django.test.client import Client
    class SimpleTest(unittest.TestCase):
    def setUp(self):
    self.client = Client()
    def test_details(self):
    response = self.client.get('/customer/details/')
    self.assertEqual(response.status_code, 200)
    self.assertEqual(len(response.context['customers']), 5)

    View Slide

  35. Selenium
    Utiliza un navegador real
    1. Acciones que realiza
    2. Cosas que espera encontrar

    View Slide

  36. Introducción a Python + Selenium
    from selenium import webdriver
    from selenium.webdriver.common.keys import Keys
    driver = webdriver.Firefox()
    driver.get("http://www.python.org")
    assert "Python" in driver.title
    elem = driver.find_element_by_name("q")
    elem.send_keys("selenium")
    elem.send_keys(Keys.RETURN)
    assert "Google" in driver.title
    driver.close()

    View Slide

  37. Django + Selenium
    from django.test import LiveServerTestCase
    from selenium.webdriver.firefox.webdriver import WebDriver
    class MySeleniumTests(LiveServerTestCase):
    @classmethod
    def setUpClass(cls):
    cls.selenium = WebDriver()
    super(MySeleniumTests, cls).setUpClass()
    @classmethod
    def tearDownClass(cls):
    cls.selenium.quit()
    super(MySeleniumTests, cls).tearDownClass()

    View Slide

  38. Django + Selenium
    def test_home(self):
    self.selenium.get(self.live_server_url)
    votacion = self.selenium.
    find_element_by_link_text("Nueva")
    self.assertIsNotNone(votacion)
    votacion.click()
    self.selenium.save_screenshot('votacion.png')

    View Slide

  39. Django + Selenium
    self.selenium.get('%s%s' % (self.live_server_url,
    '/nueva_votacion/'))
    titulo_input = self.selenium.find_element_by_id("id_titulo")
    titulo_input.send_keys('prueba selenium')
    autor_input = self.selenium.find_element_by_id("id_autor")
    autor_input.send_keys('selenium')
    self.selenium.find_element_by_id('enviar').click()
    self.selenium.save_screenshot('nueva_votacion.png')
    titulo = self.selenium.find_element_by_id('titulo')
    self.assertEquals(titulo.text, 'prueba selenium')

    View Slide

  40. Finalizando
    @8-)

    View Slide

  41. 33 projects that make
    developing django apps
    awesome
    Más...
    http://elweb.co/programacion/33-projects-that-make-developing-django-apps-awesome/

    View Slide

  42. Preguntas
    :-?

    View Slide

  43. Gracias a todos!
    :-D

    View Slide