Django Tricks José Ignacio Galarza @igalarzab Carlos Hernando @chernando
Nov 01, 2014
Django TricksJosé Ignacio Galarza @igalarzab
Carlos Hernando @chernando
django crispy forms
https://github.com/maraujop/django-crispy-forms
Crispy forms!
{% load crispy_forms_tags %}
<form method="post" class="form-horizontal">
{{ my_formset|crispy }}
</form>
Crispy forms!
{% load crispy_forms_tags %}
<form method="post" class="form-horizontal">
{{ my_formset|crispy }}
</form>
El formulario es compatible Twitter Bootstrap
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)
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'))
Y el template queda
{% load crispy_forms_tags %}
{% crispy example_form %}
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')
)
)
Y el template queda igual
{% load crispy_forms_tags %}
{% crispy example_form %}
WIN
Más de crispy forms
FormSets
Cambiar layouts al vuelo
Personalizar... todo :-)
http://django-crispy-forms.readthedocs.org/
south
Nuestro modelo cambia
class Persona(models.Model):
nombre = models.CharField(...)
apellidos = models.CharField(...)
Nuestro modelo cambia
class Persona(models.Model):
nombre = models.CharField(...)
apellidos = models.CharField(...)
email = models.EmailField(...)
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
Pero...
>>> p = Persona()
>>> p.save()
Traceback (most recent call last):
...
DatabaseError: table tutsouth_persona has no column named email
;-(
FAILsyncdb no modifica
Soluciones
Django
○ Borrón y cuenta nueva
manage flush && manage syncdb
○ Modificar manualmente las tablas
manage sql
Soluciones
Django
○ Borrón y cuenta nueva
manage flush && manage syncdb
○ Modificar manualmente las tablas
manage sql
South
south
South brings migrations to Django applications.
● Automatic migration creation● Database independence● App-savvy● VCS-proof
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 [...]
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.
south en dos patadas
Migraciones:
Primera:
manage.py schemamigration APP --initial
Siguientes:
manage.py schemamigration APP --auto
Aplicar:
manage.py migrate [APP]
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:
Durante el desarrollo
Reutilizar la migración:
manage.py schemamigration --update --auto
Conflictos
manage.py migrate --merge
Listar:
manage.py migrate --list
Más cosas interesantes
Datamigrations
ORM Freezing
Dependencias
...
http://south.readthedocs.org/
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.
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:-)
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'
"""
unittest
Forma parte de Python
Cumplir dos condiciones:a. Heredar de unittest.TestCaseb. El método empieza por test
Django enriquece con django.utils.unittest
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!")
Pruebas en Django
Por defecto:
APP/tests.py
manage.py test [[[APP].TestCase].test_method]
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
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)
Selenium
Utiliza un navegador real
1. Acciones que realiza2. Cosas que espera encontrar
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()
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()
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')
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')
Finalizando
@8-)
33 projects that make developing django apps awesome
Más...
http://elweb.co/programacion/33-projects-that-make-developing-django-apps-awesome/
Preguntas
:-?
Gracias a todos!
:-D