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

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

8da980a2f4466f05bf026b18c04984d6?s=128

Carlos Hernando

November 15, 2012
Tweet

Transcript

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

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

  3. Crispy forms! {% load crispy_forms_tags %} <form method="post" class="form-horizontal"> {{

    my_formset|crispy }} </form>
  4. Crispy forms! {% load crispy_forms_tags %} <form method="post" class="form-horizontal"> {{

    my_formset|crispy }} </form> El formulario es compatible Twitter Bootstrap
  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)
  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'))
  7. Y el template queda {% load crispy_forms_tags %} {% crispy

    example_form %}
  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') )
  9. Y el template queda igual {% load crispy_forms_tags %} {%

    crispy example_form %} WIN
  10. Más de crispy forms FormSets Cambiar layouts al vuelo Personalizar...

    todo :-) http://django-crispy-forms.readthedocs.org/
  11. south

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

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

    models.CharField(...) email = models.EmailField(...)
  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
  15. Pero... >>> p = Persona() >>> p.save() Traceback (most recent

    call last): ... DatabaseError: table tutsouth_persona has no column named email ;-(
  16. FAIL syncdb no modifica

  17. Soluciones Django ◦ Borrón y cuenta nueva manage flush &&

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

    manage syncdb ◦ Modificar manualmente las tablas manage sql South
  19. south South brings migrations to Django applications. • Automatic migration

    creation • Database independence • App-savvy • VCS-proof
  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 [...]
  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.
  22. south en dos patadas Migraciones: Primera: manage.py schemamigration APP --initial

    Siguientes: manage.py schemamigration APP --auto Aplicar: manage.py migrate [APP]
  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:
  24. Durante el desarrollo Reutilizar la migración: manage.py schemamigration --update --auto

    Conflictos manage.py migrate --merge Listar: manage.py migrate --list
  25. Más cosas interesantes Datamigrations ORM Freezing Dependencias ... http://south.readthedocs.org/

  26. None
  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.
  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:-)
  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'
  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
  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!")
  32. Pruebas en Django Por defecto: APP/tests.py manage.py test [[[APP].TestCase].test_method]

  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
  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)
  35. Selenium Utiliza un navegador real 1. Acciones que realiza 2.

    Cosas que espera encontrar
  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()
  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()
  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')
  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')
  40. Finalizando @8-)

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

  42. Preguntas :-?

  43. Gracias a todos! :-D