Categorías
Python

Raspar web con Scrapy y MongoDB

 

Tabla de Contenidos

  • Django redirecciones: Un simple estupendo Ejemplo
  • Por qué redirección
  • Detrás de las escenas: ¿Cómo una imprimación WorksA rápida redirección HTTP en HTTPHTTP redirecciones Estado CodesTemporary vs. redirecciones permanentes
  • Una cartilla rápida en HTTP
  • HTTP redirecciones Códigos de estado
  • temporal frente a la permanente redirecciones
  • redirecciones en DjangoThe HttpResponseRedirect ClassThe redirección () FunctionThe RedirectView Class-Based Ver
  • La Clase HttpResponseRedirect
  • La redirección () Función
  • El RedirectView Class-Based Ver
  • avanzada UsagePassing Los parámetros con códigos de redirección RedirectsSpecial
  • pasar parámetros con los códigos de redirecciones
  • de redireccionamiento especial
  • PitfallsRedirects que se acaba de no RedirectRedirects Eso sólo no se detendrá RedirectingPermanent redirecciones Redirecciones PermanentUnvalidated pueden comprometer la seguridad
  • redirecciones que el jus t Will no redirige
  • redireccionamientos que se acaba de parada no redireccionante
  • redirecciones permanentes son permanentes
  • no validados redireccionamientos pueden comprometer la seguridad
  • Resumen
  • Referencias
  • Una cartilla rápida sobre HTTP
  • redirecciones HTTP Códigos de estado
  • temporal vs. redirecciones permanentes
  • El HttpResponseRedirect Clase
  • La redirección () Función
  • El RedirectView Class-Based Ver
  • pasar parámetros con los códigos de redirecciones
  • de redireccionamiento especial
  • redirecciones que acaba de ganar’ t redireccionamiento
  • redireccionamientos que se acaba de parada no redireccionante
  • redirecciones permanentes son permanentes
  • no validados redireccionamientos pueden comprometer la seguridad

Cuando se construye una aplicación web de Python con el marco de Django, usted en algún momento tiene que redirección el usuario de un URL para anothe r.

En esta guía, aprenderá todo lo que necesita saber acerca de las redirecciones HTTP y cómo tratar con ellos en Django. Al final de este tutorial, podrás:

  • ser capaz de redirigir a un usuario de una URL a otra URL
  • saber la diferencia entre redirecciones temporales y permanentes
  • trampas Evitar comunes cuando se trabaja con redirecciones

Este tutorial asume que está familiarizado con los bloques de construcción básicos de una aplicación Django, como puntos de vista y patrones de URL.

Django redirecciones: Un simple estupendo Ejemplo

En Django, redirigir al usuario a otra URL devolviendo una instancia de HttpResponseRedirect o HttpResponsePermanentRedirect desde su punto de vista. La forma más sencilla de hacerlo es utilizar la redirección () la función de los django.shortcuts módulo. He aquí un ejemplo:

# views.py
from django.shortcuts import redirect

def redirect_view(request):
response = redirect('/redirect-success/')
return response

Sólo redirección de llamadas () con una dirección URL en la vista. Se volverá una clase HttpResponseRedirect, que luego regrese de su vista.

una vista que devuelve un redireccionamiento tiene que ser añadido a su urls.py, al igual que cualquier otro punto de vista:

# urls.py
from django.urls import path

from .views import redirect_view

urlpatterns = [
path('/redirect/', redirect_view)
# ... more URL patterns here
]

Asumiendo que este es el principal urls.py de su proyecto de Django, la URL / redirección / ahora redirige a / redirección éxito /.

Para evitar la codificación dura de la URL, puede llamar redirección () con el nombre de una vista o patrón de URL o un modelo para evitar la codificación dura de la URL de redirección. También puede crear una redirección permanente pasando el argumento de palabra clave = True permanente.

Este artículo podría terminar aquí, pero entonces no podría ser llamada “La última guía a Django vuelve a dirigir.” Vamos a echar un vistazo más de cerca a la función de redirección () en un minuto y también entrar en los detalles esenciales de los códigos de estado HTTP y diferentes clases HttpRedirectResponse, pero vamos a echar un paso atrás y empezar con una pregunta fundamental.

Por qué redirección

Usted podría preguntarse por qué usted quiere nunca para redirigir un usuario a una URL diferente en el primer lugar. Para tener una idea de dónde redirecciones tienen sentido, echar un vistazo a cómo Django incorpora redirecciones en las características que el marco proporciona de forma predeterminada:

  • Cuando no está en el sistema de entrada y solicita una dirección URL que requiere autenticación, como la administración de Django, Django le redirige a la página de inicio de sesión.
  • Al iniciar la sesión con éxito, Django le redirige a la URL solicitada originalmente.
  • Cuando cambie su contraseña a través del sitio administrativo, se le redirige a una página que indica que el cambio se ha realizado correctamente.
  • Cuando se crea un objeto en la administración de Django, Django le redirige a la lista de objetos.

¿Cómo sería una implementación alternativa sin redirecciones parece? Si un usuario tiene que iniciar sesión para ver una página, simplemente podría mostrar una página que dice algo así como “Haga clic aquí para iniciar sesión.” Esto funciona, pero sería inconveniente para el usuario. acortadores de URL como

http://bit.ly son otro ejemplo de que las redirecciones son útiles: escribir una breve URL en la barra de direcciones del navegador y luego redirige a una página con una URL larga, difícil de manejar.

En otros casos, las redirecciones no son sólo una cuestión de conveniencia. Redirecciones son instrumento fundamental para guiar al usuario a través de una aplicación web. Después de realizar algún tipo de operación con efectos secundarios, como la creación o eliminación de un objeto, es una buena práctica para redirigir a otra URL para evitar que realiza la operación dos veces por accidente.

Un ejemplo de este uso de redirecciones es de manipulación de formas, donde un usuario es redirigido a otro URL después de la presentación con éxito una forma. He aquí un ejemplo de código que ilustra cómo habitualmente se maneja un formulario:

1 from django import forms
2 from django.http import HttpResponseRedirect
3 from django.shortcuts import redirect, render
4
5 def send_message(name, message):
6 # Code for actually sending the message goes here
7
8 class ContactForm(forms.Form):
9 name = forms.CharField()
10 message = forms.CharField(widget=forms.Textarea)
11
12 def contact_view(request):
13 # The request method 'POST' indicates
14 # that the form was submitted
15 if request.method == 'POST': # 1
16 # Create a form instance with the submitted data
17 form = ContactForm(request.POST) # 2
18 # Validate the form
19 if form.is_valid(): # 3
20 # If the form is valid, perform some kind of
21 # operation, for example sending a message
22 send_message(
23 form.cleaned_data['name'],
24 form.cleaned_data['message']
25 )
26 # After the operation was successful,
27 # redirect to some other page
28 return redirect('/success/') # 4
29 else: # 5
30 # Create an empty form instance
31 form = ContactForm()
32
33 return render(request, 'contact_form.html', {'form': form})

El propósito de este punto de vista es mostrar y manejar un formulario de contacto que permite al usuario enviar un mensaje. Vamos a seguir paso a paso: En primer lugar

La vista se ve en el método de la petición. Cuando el usuario visita la URL conectado a este punto de vista, el navegador realiza una petición GET.

Si la vista es llamada con una solicitud POST, los datos POST se utiliza para crear instancias de un objeto ContactForm.

Si el formulario es válido, los datos del formulario se pasa a send_message (). Esta función no es relevante en este contexto y por lo tanto no se muestra aquí.

Después de enviar el mensaje, la vista devuelve una redirección a la URL / éxito /. Este es el paso que nos interesa. Por simplicidad, la URL está codificada aquí. Verá más adelante cómo se puede evitar eso.

Si la vista recibe una petición GET (o, para ser más precisos, cualquier tipo de petición que no es una petición POST), se crea una instancia de ContactForm y usos django.shortcuts.render () para hacer que la plantilla contact_form.html .

Si el usuario vuelve a cargar ahora, sólo el / éxito / URL se vuelve a cargar. Sin la redirección, volver a cargar la página sería volver a enviar el formulario y enviar otro mensaje.

Detrás de las escenas: ¿Cómo una redirección HTTP Obras

Ahora se sabe por qué redirecciones tienen sentido, pero ¿cómo funcionan? Vamos a echar un rápido resumen de lo que sucede cuando se introduce una URL en la barra de direcciones del navegador web.

Una cartilla rápida sobre HTTP de

Let asume que ha creado una aplicación Django con el fin de “Hello World” que se encarga de la ruta / hola /. Usted está ejecutando la aplicación con el servidor de desarrollo de Django, por lo que la URL completa es http://127.0.0.1:8000/hello/.

Cuando se introduce la URL en su navegador, se conecta al puerto 8000 en el servidor con la dirección IP 127.0.0.1 y envía una solicitud HTTP GET para la ruta / hola /. El servidor responde con una respuesta HTTP.

HTTP está basado en texto, por lo que es relativamente fácil mirar a la ida y vuelta entre el cliente y el servidor. Puede utilizar la herramienta de rizo línea de comandos con la opción –include a echar un vistazo a la respuesta HTTP completa, incluyendo las cabeceras, así:

$ curl --include http://127.0.0.1:8000/hello/
HTTP/1.1 200 OK
Date: Sun, 01 Jul 2018 20:32:55 GMT
Server: WSGIServer/0.2 CPython/3.6.3
Content-Type: text/html; charset=utf-8
X-Frame-Options: SAMEORIGIN
Content-Length: 11

Hello World

Como se puede ver, una respuesta HTTP se inicia con una línea de estado que contiene un estatus código y un mensaje de estado. La línea de estado es seguido por un número arbitrario de cabeceras HTTP. Una línea en blanco indica el final de las cabeceras y el inicio del cuerpo de la respuesta, que contiene los datos reales del servidor quiera guardar.

redirecciones HTTP Códigos de estado

¿Cómo es una respuesta de redirección como? Asumamos la ruta / redirección / es manejado por redirect_view (), se mostró anteriormente. Si accede a http://127.0.0.1:8000/redirect/ con rizo, su apariencia de la consola como esta:

$ curl --include http://127.0.0.1:8000/redirect/
HTTP/1.1 302 Found
Date: Sun, 01 Jul 2018 20:35:34 GMT
Server: WSGIServer/0.2 CPython/3.6.3
Content-Type: text/html; charset=utf-8
Location: /redirect-success/
X-Frame-Options: SAMEORIGIN
Content-Length: 0

Las dos respuestas pueden parecer similares, pero hay algunas diferencias clave. La redirección:

  • un código de estado diferente (302 frente a 200)
  • Contiene una cabecera Location con un pariente URL
  • termina con una línea vacía debido a que el cuerpo de la respuesta de redirección está vacía

El principal diferenciador es la código de estado. La especificación de la norma HTTP dice lo siguiente:

El 302 (encontrado) código de estado indica que reside el recurso objetivo temporalmente bajo una diferente URI. Dado que el cambio de dirección podría ser alterado en algunas ocasiones, el cliente debe seguir utilizando el URI de la solicitud efectiva para futuras solicitudes. El servidor debe generar un campo de cabecera Ubicación en la respuesta que contiene una referencia URI para los diferentes URI. El agente de usuario puede utilizar el valor del campo de localización de la redirección automática. (Fuente)

En otras palabras, cada vez que el servidor envía un código de estado de 302, que dice al cliente, “Hey, por el momento, lo que busca se puede encontrar en este otro lugar.”

Una frase clave en la especificación es “puede usar el valor del campo Ubicación para la redirección automática”. Esto significa que no se puede forzar al cliente a cargar otra URL. El cliente puede optar por esperar la confirmación del usuario o decidir no cargar la URL en absoluto.

Ahora se sabe que una redirección es sólo una respuesta HTTP con un código de estado 3xx y una cabecera Location. La conclusión clave aquí es que una redirección HTTP es como cualquier respuesta HTTP de edad, pero con un cuerpo vacío, código de estado 3xx, y una cabecera Location.

Eso es todo. Ataremos esta de nuevo en Django por un momento, pero primero vamos a echar un vistazo a dos tipos de redirecciones en ese rango de código de estado 3xx y ver por qué son importantes cuando se trata de desarrollo web.

temporal frente a la permanente redirecciones HTTP

Los previsto por la norma varios códigos de estado de redirección, todo en la gama 3xx. Los dos más comunes son los códigos de estado 301 Redirección permanente y 302 encontrados. código de estado

A 302 Encontrado indica una redirección temporal. Una redirección temporal dice, “Por el momento, lo que está buscando se puede encontrar en esta otra dirección.” Piense en ello como una señal de tienda que dice: “Nuestra tienda está cerrada por reformas. Por favor, vaya a nuestra otra tienda de la esquina “. Como esto es sólo temporal, usted comprueba la dirección original la próxima vez que vaya de compras.

Nota: En HTTP 1.0, el mensaje de código de estado 302 fue Redirección temporal. El mensaje fue cambiado a encontrados en HTTP 1.1.

Como su nombre lo indica, redirecciones permanentes se supone que deben ser permanentes. Una redirección permanente indica al navegador, “Lo que estás buscando ya no está en esta dirección. Es ahora en esta nueva dirección, y nunca estará en la antigua dirección de nuevo.”

Una redirección permanente es como un signo tienda que dice: “Nos mudamos. Nuestra nueva tienda está a la vuelta de la esquina “. Este cambio es permanente, por lo que la próxima vez que quiera ir a la tienda, que iría directamente a la nueva dirección.

Nota: redirecciones permanentes pueden tener consecuencias no deseadas. Termina esta guía antes de utilizar una redirección permanente o saltar directamente a la sección de “redirecciones permanentes son permanentes.”

Navegadores comportan de manera similar al manejar las redirecciones: cuando una URL devuelve una respuesta de redirección permanente, esta respuesta se almacena en caché. La próxima vez que el navegador encuentra la dirección de edad, recuerda la redirección y solicita directamente la nueva dirección. El almacenamiento en caché

una redirección ahorra una solicitud innecesario y hace que para una mejor y más rápida experiencia de usuario.

Por otra parte, la distinción entre las redirecciones temporales y permanentes es relevante para la optimización del motor de búsqueda.

redirecciones en Django

Ahora se sabe que una redirección es sólo una respuesta HTTP con un código de estado 3xx y una cabecera Location.

Se puede construir una respuesta así a sí mismo de un objeto HttpResponse normal:

def hand_crafted_redirect_view(request):
response = HttpResponse(status=302)
response['Location'] = '/redirect/success/'
return response

Esta solución es técnicamente correcto, pero se trata de un poco de escribir.

El HttpResponseRedirect Clase

Puede ahorrarse algo de tecleo con la clase HttpResponseRedirect, una subclase de HttpResponse. Sólo una instancia de la clase con la URL que desee redirigir como primer argumento, y la clase fijará el estado correcto y cabecera Location:

def redirect_view(request):
return HttpResponseRedirect('/redirect/success/')

Se puede jugar con la clase HttpResponseRedirect en el terminal de Python para ver lo que está recibiendo :

>>> from django.http import HttpResponseRedirect
>>> redirect = HttpResponseRedirect('/redirect/success/')
>>> redirect.status_code
302
>>> redirect['Location']
'/redirect/success/'

también hay una clase para redirecciones permanentes, que es bien llamado HttpResponsePermanentRedirect. Funciona de la misma como HttpResponseRedirect, la única diferencia es que no tiene un código de estado de 301 (movido permanentemente).

Note: En las ejemplos anteriores, las direcciones URL de redirección están codificadas. URL codificación dura es una mala práctica: si el URL cambia nunca, usted tiene que buscar a través de todo el código y cambiar cualquier ocurrencia. Vamos a arreglar eso!

Usted podría utilizar django.urls.reverse () para construir una URL, pero hay una manera más conveniente como se verá en la siguiente sección.

La redirección () Función

Para hacer la vida más fácil, Django proporciona la función de acceso directo versátil que ya hemos visto en la introducción: django.shortcuts.redirect ().

Usted puede llamar a esta función con: instancia de modelo

  • A, o cualquier otro objeto, con un método get_absolute_url ()
  • una URL o nombre de la vista y / argumentos posicionales y o palabra clave
  • Una URL

Será tomar las medidas apropiadas para hacer volver los argumentos en una URL y devolver un HTTPResponseRedirect.If que pase permanente = True, devolverá una instancia de HttpResponsePermanentRedirect, lo que resulta en una redirección permanente.

Aquí hay tres ejemplos para ilustrar los diferentes casos de uso:

Pasando un modelo: redirección

from django.shortcuts import redirect

def model_redirect_view(request):
product = Product.objects.filter(featured=True).first()
return redirect(product)

() llamará product.get_absolute_url () y utilizar el resultado como objetivo redireccionamiento. Si la clase determinada, en este caso del producto, no tiene un método get_absolute_url (), se producirá un error con un TypeError.

pasar un nombre de URL y argumentos:

from django.shortcuts import redirect

def fixed_featured_product_view(request):
...
product_id = settings.FEATURED_PRODUCT_ID
return redirect('product_detail', product_id=product_id)

redirección () tratará de utilizar sus argumentos dados para revertir una dirección URL. Este ejemplo asume sus patrones de URL contienen un patrón de esta manera:

path('/product//', 'product_detail_view', name='product_detail')

pasar una URL:

from django.shortcuts import redirect

def featured_product_view(request):
return redirect('/products/42/')

redirección () tratará cualquier cadena que contenga una / o. como una dirección URL y utilizarlo como objetivo del redireccionamiento.

El RedirectView Class-Based Ver

Si se tiene una vista que no hace más que devolver una redirección, se podría utilizar la clase de vista basados ​​en django.views.generic.base.RedirectView.

usted puede adaptar a sus necesidades RedirectView a través de diversos atributos.

Si la clase tiene un atributo .url, se utiliza como una URL de redireccionamiento. Cuerda marcadores de posición de formato se sustituyen con argumentos con nombre de la URL: Modelo

# urls.py
from django.urls import path
from .views import SearchRedirectView

urlpatterns = [
path('/search//', SearchRedirectView.as_view())
]

# views.py
from django.views.generic.base import RedirectView

class SearchRedirectView(RedirectView):
url = 'https://google.com/?q=%(term)s'

El URL define un plazo argumento, que se utiliza en SearchRedirectView para construir el URL de redirección. El camino / Búsqueda / gatitos / en su aplicación le redirigirá a https://google.com/?q=kittens.

En lugar de la subclasificación RedirectView para sobrescribir el atributo url, también puede pasar la URL argumento de palabra clave a as_view () en sus urlpatterns:

#urls.py
from django.views.generic.base import RedirectView

urlpatterns = [
path('/search//',
RedirectView.as_view(url='https://google.com/?q=%(term)s')),
]

Usted puede también get_redirect_url sobreescritura () para obtener un comportamiento completamente personalizado:

from random import choice
from django.views.generic.base import RedirectView

class RandomAnimalView(RedirectView):

animal_urls = ['/dog/', '/cat/', '/parrot/']
is_permanent = True

def get_redirect_url(*args, **kwargs):
return choice(self.animal_urls)

Esta clase basados ​​en vista redirige a una URL recogidos al azar de .animal_urls.

django.views.generic.base.RedirectView ofrece unos más ganchos para la personalización. Esta es la lista completa:

  • .urlIf este atributo se establece, debe ser una cadena con una URL para redirigir a. Si contiene el formato de cadenas como marcadores de posición% (name) s, que se expanden utilizando los argumentos de palabras clave se pasan a la vista.
  • .pattern_nameIf este atributo se establece, debe ser el nombre de un patrón de URL para redirigir a. Todos los argumentos posicionales y de palabras clave se pasan a la vista se utilizan para revertir el patrón de URL.
  • .permanentIf este atributo es cierto que la vista devuelve una redirección permanente. Por defecto es falso.
  • .query_stringIf este atributo es cierto que el punto de vista añade cualquier cadena de consulta proporcionada a la URL de redireccionamiento. Si es falsa, que es la predeterminada, la cadena de consulta se descarta. get_redirect_url
  • (args *, ** kwargs) Este método es responsable de construir la URL de redireccionamiento. Si este método devuelve Ninguno, la vista devuelve una implementación por defecto 410 status.The Atrás comprueba primero .url. Se trata .url como una cadena de formato “viejo estilo”, utilizando los parámetros de URL nombrados pasados ​​a la vista para expandir cualquier formato de .url specifiers.If llamada no se establece, comprueba si .pattern_name se establece. Si lo es, se lo utiliza para revertir una dirección URL con argumentos posicionales y de palabras clave que received.You puede cambiar ese comportamiento en la forma que desee al sobrescribir este método. Sólo asegúrese de que devuelve una cadena que contiene una URL.

.url

Si este atributo se establece, debe ser una cadena con una URL para redirigir a. Si contiene el formato de cadenas como marcadores de posición% (name) s, que se expanden utilizando los argumentos de palabras clave se pasan a la vista.

.pattern_name

Si este atributo se establece, debe ser el nombre de un patrón de URL para redirigir a. Todos los argumentos posicionales y de palabras clave se pasan a la vista se utilizan para revertir el patrón de URL.

.permanent

Si este atributo es cierto que la vista devuelve una redirección permanente. Por defecto es falso.

.query_string

Si este atributo es cierto que el punto de vista añade cualquier cadena de consulta proporcionada a la URL de redireccionamiento. Si es falsa, que es la predeterminada, la cadena de consulta se descarta.

get_redirect_url (* args, ** kwargs)

Este método es responsable de construir la URL de redireccionamiento. Si este método devuelve None, la vista devuelve un estado Atrás 410. comprueba primero

la implementación predeterminada .url. Se trata .url como una cadena de formato “viejo estilo”, utilizando los parámetros de URL con nombre que se pasan al objeto de ampliar los especificadores de formato mencionadas.

Si .url no está establecido, comprueba si es .pattern_name conjunto. Si lo es, se lo utiliza para revertir una dirección URL con argumentos posicionales y de palabras clave que ha recibido.

Puede cambiar ese comportamiento en la forma que desee al sobrescribir este método. Sólo asegúrese de que devuelve una cadena que contiene una URL.

Nota: puntos de vista basados ​​en la clase son un concepto poderoso, pero puede ser un poco difícil de envolver su cabeza alrededor. A diferencia de puntos de vista basados ​​en funciones regulares, en las que es relativamente fácil de seguir el flujo del código, puntos de vista basados ​​en clases se componen de una compleja jerarquía de mixins y clases base.

Una gran herramienta para dar sentido a una clase de vista basado en la clase es el sitio web Vistas con clase basada en la clase.

Se podría implementar la funcionalidad de RandomAnimalView en el ejemplo anterior con este simple vista basado en las funciones:

from random import choice
from django.shortcuts import redirect

def random_animal_view(request):
animal_urls = ['/dog/', '/cat/', '/parrot/']
return redirect(choice(animal_urls))

Como se puede ver, el enfoque basado en la clase no proporciona ningún beneficio obvio al tiempo que añade cierta complejidad oculta. Esto plantea la pregunta: ¿cuándo se debe utilizar RedirectView?

Si desea agregar una redirección directamente en su urls.py, utilizando RedirectView tiene sentido. Pero si usted se encuentra el sobreescribiendo get_redirect_url, una visión basada en la función podría ser más fácil de entender y más flexible para futuras mejoras. Uso

avanzada

Una vez que sabe que es probable que desee utilizar django.shortcuts.redirect (), redirigir a una URL diferente es bastante sencilla. Pero hay un par de casos de uso avanzadas que no son tan evidentes.

Paso de parámetros con redirecciones

A veces, se desea pasar algunos parámetros a la vista que se está realizando el redireccionamiento a. Su mejor opción es pasar los datos en la cadena de consulta de URL de redireccionamiento, que significa volver a dirigir a un URL como esta: de

http://example.com/redirect-path/?parameter=value

Let suponga que desea redirigir desde some_view () para product_view (), pero pasar a una categoría de parámetro opcional :

from django.urls import reverse
from urllib.parse import urlencode

def some_view(request):
...
base_url = reverse('product_view') # 1 /products/
query_string = urlencode({'category': category.id}) # 2 category=42
url = '{}?{}'.format(base_url, query_string) # 3 /products/?category=42
return redirect(url) # 4

def product_view(request):
category_id = request.GET.get('category') # 5
# Do something with category_id

el código de este ejemplo es bastante denso, así que vamos a seguir paso a paso:

en primer lugar, se utiliza django.urls.reverse () para obtener la asignación de dirección URL a product_view ().

A continuación, usted tiene que construir la cadena de consulta. Esa es la parte que sigue al signo de interrogación. Es aconsejable el uso de urllib.urlparse.urlencode () para que, a medida que se encargará de codificar correctamente todos los caracteres especiales.

Ahora usted tiene que unirse base_url y query_string con un signo de interrogación. Una cadena de formato funciona bien para eso.

Por último, se pasa url para django.shortcuts.redirect () o para una clase de respuesta de redirección.

En product_view (), el objetivo del redireccionamiento, el parámetro estará disponible en el diccionario request.GET. El parámetro puede faltar, por lo que debe utilizar requests.GET.get ( ‘categoría’) en lugar de requests.GET [ ‘categoría. El ex rendimientos Ninguno cuando no existe el parámetro, mientras que el último sería lanzar una excepción.

Nota: Asegúrese de que para validar los datos que se leen de las cadenas de consulta. Podría parecer que estos datos está bajo su control, ya que ha creado la URL de redirección.

En realidad, la redirección podría ser manipulado por el usuario y no debe ser de confianza, al igual que cualquier otra entrada del usuario. Sin validación adecuada, un atacante podría ser capaz de obtener acceso no autorizado. Códigos

de redireccionamiento especial

Django provee HTTP clases de respuesta de los códigos de estado 301 y 302. Los que deben cubrir la mayoría de los casos de uso, pero si alguna vez tiene que devolver los códigos de estado 303, 307, o 308, se puede crear fácilmente su propio la clase de respuesta. Simplemente subclase HttpResponseRedirectBase y sobrescribir el atributo status_code:

class HttpResponseTemporaryRedirect(HttpResponseRedirectBase):
status_code = 307

Alternativamente, se puede utilizar el método django.shortcuts.redirect () para crear un objeto de respuesta y cambiar el valor de retorno. Este enfoque tiene sentido cuando se tiene el nombre de una vista o una URL o un modelo que desea redirigir a:

def temporary_redirect_view(request):
response = redirect('success_view')
response.status_code = 307
return response

Nota: realidad, hay una tercera clase con un código de estado en la gama 3xx: HttpResponseNotModified, con la condición código 304. se indica que el URL contenido no ha cambiado y que el cliente puede utilizar una versión en caché.

Se podría argumentar que 304 Not Modified redirecciones de respuesta a la versión en caché de una URL, pero eso es un poco de un tramo. En consecuencia, se ya no aparece en la sección “redirección 3xx” de la norma HTTP.

Errores

redireccionamientos que se acaba de redirección no

La simplicidad de django.shortcuts.redirect () puede ser engañoso. La función en sí no realiza una redirección: simplemente devuelve un objeto de respuesta de redirección. Debe devolver este objeto respuesta de su punto de vista (o en un middleware). De lo contrario, sin redirección va a suceder.

Pero incluso si sabe que redirección simplemente llamando al () no es suficiente, es fácil introducir este error en una aplicación de trabajo a través de un simple refactorización. Aquí está un ejemplo para ilustrar que. de

Let asumen que usted está construyendo una tienda y tiene una vista que se encarga de mostrar un producto. Si el producto no existe, se redirige a la página de inicio:

def product_view(request, product_id):
try:
product = Product.objects.get(pk=product_id)
except Product.DoesNotExist:
return redirect('/')
return render(request, 'product_detail.html', {'product': product})

Ahora vamos a añadir un segundo objeto de críticas pantalla del cliente para un producto. También debe redirigir a la página de inicio para los productos no existentes, así como un primer paso, extraer esta funcionalidad de product_view () en un get_product_or_redirect función auxiliar ():

def get_product_or_redirect(product_id):
try:
return Product.objects.get(pk=product_id)
except Product.DoesNotExist:
return redirect('/')

def product_view(request, product_id):
product = get_product_or_redirect(product_id)
return render(request, 'product_detail.html', {'product': product})

Por desgracia, después de la refactorización, la redirección ya no funciona .

¿Se puede detectar el error? Mostrar / Ocultar

El resultado de redirección () se devuelve desde get_product_or_redirect (), pero product_view () no devuelve la misma. En su lugar, se pasa a la plantilla.

Dependiendo de cómo se utiliza la variable del producto en la plantilla product_detail.html, esto podría no resultar en un mensaje de error y simplemente mostrar los valores vacíos.

redireccionamientos que se acaba de parada no redireccionante

Cuando se trata de redirecciones, puede crear accidentalmente un bucle de redireccionamiento, por tener un retorno URL de una redirección que apunta al URL B que devuelve una redirección a URL A, y así sucesivamente. La mayoría de los clientes HTTP detectan este tipo de bucle de redireccionamiento y se mostrará un mensaje de error después de un número de peticiones.

Por desgracia, este tipo de error puede ser difícil de detectar porque todo se ve bien en el lado del servidor. A menos que sus usuarios se quejan de la cuestión, la única indicación de que algo no está bien es que usted tiene un número de peticiones de un cliente que todo el resultado de una respuesta de redirección en rápida sucesión, pero no hay respuesta con un estado 200 OK.

He aquí un ejemplo simple de un bucle de redireccionamiento:

def a_view(request):
return redirect('another_view')

def another_view(request):
return redirect('a_view')

Este ejemplo ilustra el principio, pero es demasiado simplista. Los bucles de redirección te vas a encontrar en la vida real son probablemente va a ser más difícil de detectar. Echemos un vistazo a un ejemplo más elaborado:

def featured_products_view(request):
featured_products = Product.objects.filter(featured=True)
if len(featured_products == 1):
return redirect('product_view', kwargs={'product_id': featured_products[0].id})
return render(request, 'featured_products.html', {'product': featured_products})

def product_view(request, product_id):
try:
product = Product.objects.get(pk=product_id, in_stock=True)
except Product.DoesNotExist:
return redirect('featured_products_view')
return render(request, 'product_detail.html', {'product': product})

featured_products_view () recupera todos los productos destacados, en otros casos las palabras de producto con el conjunto .featured en True. Si sólo existe un producto destacado, redirecciona directamente a product_view (). De lo contrario, se muestra una plantilla con el queryset featured_products.

El product_view parece familiar de la sección anterior, pero tiene dos diferencias menores:

  • La vista intenta obtener un producto que está en stock, indicado por tener .in_stock conjunto en True.
  • La vista se vuelve a dirigir a featured_products_view () si no hay producto en stock.

Esta lógica funciona bien hasta que su tienda se convierte en una víctima de su propio éxito y el producto ofrecido tiene actualmente sale de stock. Si se establece en False .in_stock pero se olvide de establecer .featured en False así, entonces cualquier visitante a su feature_product_view () ahora será atrapado en un bucle de redireccionamiento.

No hay manera a prueba de balas para evitar este tipo de error, sino un punto de partida bueno es comprobar si la vista está redirigiendo a los usos redirige a sí mismo. redirecciones

redirecciones permanentes son

Permanente

permanentes pueden ser como los malos tatuajes: podrían parecer una buena idea en el momento, pero una vez que te das cuenta de que eran un error, que puede ser muy difícil deshacerse de ellos.

Cuando un navegador recibe una respuesta de redirección permanente para una URL, almacena en caché esta respuesta de forma indefinida. Cualquier momento de solicitar la dirección de edad en el futuro, el navegador no se molesta en lo carga y se carga directamente a la nueva URL.

Puede ser muy difícil convencer a un navegador para cargar una URL que una vez que regresó una redirección permanente. Google Chrome es especialmente agresivo cuando se trata de redirecciones de almacenamiento en caché.

¿Por qué puede ser esto un problema?

Imagínese usted quiere construir una aplicación web con Django. Registre su dominio en myawesomedjangowebapp.com. Como primer paso, se instala una aplicación de blog en https://myawesomedjangowebapp.com/blog/ para construir una lista de correo de lanzamiento. página

de su sitio en https://myawesomedjangowebapp.com/ está todavía en construcción, por lo que redirecciona a https://myawesomedjangowebapp.com/blog/. Decide utilizar una redirección permanente porque has oído que redirecciones permanentes se almacenan en caché y caché de hacer las cosas más rápido y más rápido es mejor porque la velocidad es un factor para la clasificación en los resultados de búsqueda de Google.

Como resultado, usted no es sólo un gran desarrollador, sino también un escritor de talento. Su blog se hace popular, y su lista de correo lanzamiento crece. Después de un par de meses, su aplicación está lista. Ahora cuenta con una página de inicio brillante, y finalmente eliminar la redirección.

Usted envía un correo electrónico con un código de anuncio descuento especial a su lista de correo lanzamiento de tamaño considerable. De vuelta magra y esperar a que las notificaciones de registro para rodar en.

Para su horror, sus rellenos de buzón de mensajes de los visitantes confundido que quieren visitar su aplicación, pero siempre están siendo redirigidos a tu blog.

¿Qué ha pasado? Sus lectores del blog habían visitado https://myawesomedjangowebapp.com/ cuando la redirección a https://myawesomedjangowebapp.com/blog/ seguía activo. Debido a que era una redirección permanente, se almacena en caché en sus navegadores.

Cuando se hace clic en el enlace en su correo anuncio de lanzamiento, sus navegadores nunca se molestó en comprobar su nueva página de inicio y se dirigió directamente a su blog. En lugar de celebrar su exitoso lanzamiento, que está ocupado instruyendo a sus usuarios cómo jugar con chrome: // net-internals para restablecer la memoria caché de sus navegadores.

El carácter permanente de redirecciones permanentes también le puede morder mientras que el desarrollo de su ordenador local. rebobinado Vamos al momento en que se implementó que redirección permanente fatídico para myawesomedjangowebapp.com.

se inicia el servidor de desarrollo y http://127.0.0.1:8000/ abierta. Tal como se pretende, la aplicación redirige el navegador a http://127.0.0.1:8000/blog/. Satisfecho con su trabajo, se detiene el servidor de desarrollo e ir a comer.

enviar de regreso con el estómago lleno, listo para hacer frente a algunos de trabajo del cliente. El cliente quiere algunos cambios simples en su página web, de modo que cargue el proyecto del cliente e iniciar el servidor de desarrollo.

Pero espera, ¿qué está pasando aquí? La página principal está roto, ahora devuelve un 404! Debido a la caída de la tarde, que le lleva un tiempo darse cuenta de que estás siendo redirigido al http://127.0.0.1:8000/blog/, que no existe en el proyecto del cliente.

Para el navegador, no importa que el http://127.0.0.1:8000/ URL ahora sirve una aplicación completamente diferente. Lo único que importa es que el navegador que esta URL una vez en el pasado devolvió una redirección permanente a http://127.0.0.1:8000/blog/.

La lección de esta historia es que sólo se debe utilizar redirecciones permanentes en las direcciones URL que usted no tiene ninguna intención de volver a utilizar de nuevo. Hay un lugar para redirecciones permanentes, pero hay que ser conscientes de sus consecuencias.

Even if you’re confident that you really need a permanent redirect, it’s a good idea to implement a temporary redirect first and only switch to its permanent cousin once you’re 100% sure everything works as intended.

Unvalidated Redirects Can Compromise Security

From a security perspective, redirects are a relatively safe technique. An attacker cannot hack a website with a redirect. After all, a redirect just redirects to a URL that an attacker could just type in the address bar of their browser.

However, if you use some kind of user input, like a URL parameter, without proper validation as a redirect URL, this could be abused by an attacker for a phishing attack. This kind of redirect is called an open or unvalidated redirect.

There are legitimate use cases for redirecting to URL that is read from user input. A prime example is Django’s login view. It accepts a URL parameter next that contains the URL of the page the user is redirected to after login. To redirect the user to their profile after login, the URL might look like this:

https://myawesomedjangowebapp.com/login/?next=/profile/

Django does validate the next parameter, but let’s assume for a second that it doesn’t.

Without validation, an attacker could craft a URL that redirects the user to a website under their control, for example:

https://myawesomedjangowebapp.com/login/?next=https://myawesomedjangowebapp.co/profile/

The website myawesomedjangowebapp.co might then display an error message and trick the user into entering their credentials again.

The best way to avoid open redirects is to not use any user input when building a redirect URL.

If you cannot be sure that a URL is safe for redirection, you can use the function django.utils.http.is_safe_url() to validate it. The docstring explains its usage quite well:

is_safe_url(url, host=None, allowed_hosts=None, require_https=False)

Return True if the url is a safe redirection (i.e. it doesn’t point to a different host and uses a safe scheme).Always return False on an empty url.If require_https is True, only ‘https’ will be considered a valid scheme, as opposed to ‘http’ and ‘https’ with the default, False. (Source)

Let’s look at some examples.

A relative URL is considered safe:

>>> # Import the function first.
>>> from django.utils.http import is_safe_url
>>> is_safe_url('/profile/')
True

A URL pointing to another host is generally not considered safe:

>>> is_safe_url('https://myawesomedjangowebapp.com/profile/')
False

A URL pointing to another host is considered safe if its host is provided in allowed_hosts:

>>> is_safe_url('https://myawesomedjangowebapp.com/profile/',
... allowed_hosts={'myawesomedjangowebapp.com'})
True

If the argument require_https is True, a URL using the http scheme is not considered safe:

>>> is_safe_url('http://myawesomedjangowebapp.com/profile/',
... allowed_hosts={'myawesomedjangowebapp.com'},
... require_https=True)
False

Summary

This wraps up this guide on HTTP redirects with Django. Congratulations: you have now touched on every aspect of redirects all the way from the low-level details of the HTTP protocol to the high-level way of dealing with them in Django.

You learned how an HTTP redirect looks under the hood, what the different status codes are, and how permanent and temporary redirects differ. This knowledge is not specific to Django and is valuable for web development in any language.

You can now perform a redirect with Django, either by using the redirect response classes HttpResponseRedirect and HttpResponsePermanentRedirect, or with the convenience function django.shortcuts.redirect(). You saw solutions for a couple of advanced use cases and know how to steer clear of common pitfalls.

If you have any further question about HTTP redirects leave a comment below and in the meantime, happy redirecting!

References

  • Django documentation: django.http.HttpResponseRedirect
  • Django documentation: django.shortcuts.render()
  • Django documentation: django.views.generic.base.RedirectView
  • RFC 7231: Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content – 6.4 Redirection 3xx
  • CWE-601: URL Redirection to Untrusted Site (‘Open Redirect’)
Categorías
Python

Enchufe de Programación en Python (Guía)

 

Tabla de Contenidos

  • Django redirecciones: Un simple estupendo Ejemplo
  • Por qué redirección
  • Detrás de las escenas: ¿Cómo una imprimación WorksA rápida redirección HTTP en HTTPHTTP redirecciones Estado CodesTemporary vs. redirecciones permanentes
  • Una cartilla rápida en HTTP
  • HTTP redirecciones Códigos de estado
  • temporal frente a la permanente redirecciones
  • redirecciones en DjangoThe HttpResponseRedirect ClassThe redirección () FunctionThe RedirectView Class-Based Ver
  • La Clase HttpResponseRedirect
  • La redirección () Función
  • El RedirectView Class-Based Ver
  • avanzada UsagePassing Los parámetros con códigos de redirección RedirectsSpecial
  • pasar parámetros con los códigos de redirecciones
  • de redireccionamiento especial
  • PitfallsRedirects que se acaba de no RedirectRedirects Eso sólo no se detendrá RedirectingPermanent redirecciones Redirecciones PermanentUnvalidated pueden comprometer la seguridad
  • redirecciones que el jus t Will no redirige
  • redireccionamientos que se acaba de parada no redireccionante
  • redirecciones permanentes son permanentes
  • no validados redireccionamientos pueden comprometer la seguridad
  • Resumen
  • Referencias
  • Una cartilla rápida sobre HTTP
  • redirecciones HTTP Códigos de estado
  • temporal vs. redirecciones permanentes
  • El HttpResponseRedirect Clase
  • La redirección () Función
  • El RedirectView Class-Based Ver
  • pasar parámetros con los códigos de redirecciones
  • de redireccionamiento especial
  • redirecciones que acaba de ganar’ t redireccionamiento
  • redireccionamientos que se acaba de parada no redireccionante
  • redirecciones permanentes son permanentes
  • no validados redireccionamientos pueden comprometer la seguridad

Cuando se construye una aplicación web de Python con el marco de Django, usted en algún momento tiene que redirección el usuario de un URL para anothe r.

En esta guía, aprenderá todo lo que necesita saber acerca de las redirecciones HTTP y cómo tratar con ellos en Django. Al final de este tutorial, podrás:

  • ser capaz de redirigir a un usuario de una URL a otra URL
  • saber la diferencia entre redirecciones temporales y permanentes
  • trampas Evitar comunes cuando se trabaja con redirecciones

Este tutorial asume que está familiarizado con los bloques de construcción básicos de una aplicación Django, como puntos de vista y patrones de URL.

Django redirecciones: Un simple estupendo Ejemplo

En Django, redirigir al usuario a otra URL devolviendo una instancia de HttpResponseRedirect o HttpResponsePermanentRedirect desde su punto de vista. La forma más sencilla de hacerlo es utilizar la redirección () la función de los django.shortcuts módulo. He aquí un ejemplo:

# views.py
from django.shortcuts import redirect

def redirect_view(request):
response = redirect('/redirect-success/')
return response

Sólo redirección de llamadas () con una dirección URL en la vista. Se volverá una clase HttpResponseRedirect, que luego regrese de su vista.

una vista que devuelve un redireccionamiento tiene que ser añadido a su urls.py, al igual que cualquier otro punto de vista:

# urls.py
from django.urls import path

from .views import redirect_view

urlpatterns = [
path('/redirect/', redirect_view)
# ... more URL patterns here
]

Asumiendo que este es el principal urls.py de su proyecto de Django, la URL / redirección / ahora redirige a / redirección éxito /.

Para evitar la codificación dura de la URL, puede llamar redirección () con el nombre de una vista o patrón de URL o un modelo para evitar la codificación dura de la URL de redirección. También puede crear una redirección permanente pasando el argumento de palabra clave = True permanente.

Este artículo podría terminar aquí, pero entonces no podría ser llamada “La última guía a Django vuelve a dirigir.” Vamos a echar un vistazo más de cerca a la función de redirección () en un minuto y también entrar en los detalles esenciales de los códigos de estado HTTP y diferentes clases HttpRedirectResponse, pero vamos a echar un paso atrás y empezar con una pregunta fundamental.

Por qué redirección

Usted podría preguntarse por qué usted quiere nunca para redirigir un usuario a una URL diferente en el primer lugar. Para tener una idea de dónde redirecciones tienen sentido, echar un vistazo a cómo Django incorpora redirecciones en las características que el marco proporciona de forma predeterminada:

  • Cuando no está en el sistema de entrada y solicita una dirección URL que requiere autenticación, como la administración de Django, Django le redirige a la página de inicio de sesión.
  • Al iniciar la sesión con éxito, Django le redirige a la URL solicitada originalmente.
  • Cuando cambie su contraseña a través del sitio administrativo, se le redirige a una página que indica que el cambio se ha realizado correctamente.
  • Cuando se crea un objeto en la administración de Django, Django le redirige a la lista de objetos.

¿Cómo sería una implementación alternativa sin redirecciones parece? Si un usuario tiene que iniciar sesión para ver una página, simplemente podría mostrar una página que dice algo así como “Haga clic aquí para iniciar sesión.” Esto funciona, pero sería inconveniente para el usuario. acortadores de URL como

http://bit.ly son otro ejemplo de que las redirecciones son útiles: escribir una breve URL en la barra de direcciones del navegador y luego redirige a una página con una URL larga, difícil de manejar.

En otros casos, las redirecciones no son sólo una cuestión de conveniencia. Redirecciones son instrumento fundamental para guiar al usuario a través de una aplicación web. Después de realizar algún tipo de operación con efectos secundarios, como la creación o eliminación de un objeto, es una buena práctica para redirigir a otra URL para evitar que realiza la operación dos veces por accidente.

Un ejemplo de este uso de redirecciones es de manipulación de formas, donde un usuario es redirigido a otro URL después de la presentación con éxito una forma. He aquí un ejemplo de código que ilustra cómo habitualmente se maneja un formulario:

1 from django import forms
2 from django.http import HttpResponseRedirect
3 from django.shortcuts import redirect, render
4
5 def send_message(name, message):
6 # Code for actually sending the message goes here
7
8 class ContactForm(forms.Form):
9 name = forms.CharField()
10 message = forms.CharField(widget=forms.Textarea)
11
12 def contact_view(request):
13 # The request method 'POST' indicates
14 # that the form was submitted
15 if request.method == 'POST': # 1
16 # Create a form instance with the submitted data
17 form = ContactForm(request.POST) # 2
18 # Validate the form
19 if form.is_valid(): # 3
20 # If the form is valid, perform some kind of
21 # operation, for example sending a message
22 send_message(
23 form.cleaned_data['name'],
24 form.cleaned_data['message']
25 )
26 # After the operation was successful,
27 # redirect to some other page
28 return redirect('/success/') # 4
29 else: # 5
30 # Create an empty form instance
31 form = ContactForm()
32
33 return render(request, 'contact_form.html', {'form': form})

El propósito de este punto de vista es mostrar y manejar un formulario de contacto que permite al usuario enviar un mensaje. Vamos a seguir paso a paso: En primer lugar

La vista se ve en el método de la petición. Cuando el usuario visita la URL conectado a este punto de vista, el navegador realiza una petición GET.

Si la vista es llamada con una solicitud POST, los datos POST se utiliza para crear instancias de un objeto ContactForm.

Si el formulario es válido, los datos del formulario se pasa a send_message (). Esta función no es relevante en este contexto y por lo tanto no se muestra aquí.

Después de enviar el mensaje, la vista devuelve una redirección a la URL / éxito /. Este es el paso que nos interesa. Por simplicidad, la URL está codificada aquí. Verá más adelante cómo se puede evitar eso.

Si la vista recibe una petición GET (o, para ser más precisos, cualquier tipo de petición que no es una petición POST), se crea una instancia de ContactForm y usos django.shortcuts.render () para hacer que la plantilla contact_form.html .

Si el usuario vuelve a cargar ahora, sólo el / éxito / URL se vuelve a cargar. Sin la redirección, volver a cargar la página sería volver a enviar el formulario y enviar otro mensaje.

Detrás de las escenas: ¿Cómo una redirección HTTP Obras

Ahora se sabe por qué redirecciones tienen sentido, pero ¿cómo funcionan? Vamos a echar un rápido resumen de lo que sucede cuando se introduce una URL en la barra de direcciones del navegador web.

Una cartilla rápida sobre HTTP de

Let asume que ha creado una aplicación Django con el fin de “Hello World” que se encarga de la ruta / hola /. Usted está ejecutando la aplicación con el servidor de desarrollo de Django, por lo que la URL completa es http://127.0.0.1:8000/hello/.

Cuando se introduce la URL en su navegador, se conecta al puerto 8000 en el servidor con la dirección IP 127.0.0.1 y envía una solicitud HTTP GET para la ruta / hola /. El servidor responde con una respuesta HTTP.

HTTP está basado en texto, por lo que es relativamente fácil mirar a la ida y vuelta entre el cliente y el servidor. Puede utilizar la herramienta de rizo línea de comandos con la opción –include a echar un vistazo a la respuesta HTTP completa, incluyendo las cabeceras, así:

$ curl --include http://127.0.0.1:8000/hello/
HTTP/1.1 200 OK
Date: Sun, 01 Jul 2018 20:32:55 GMT
Server: WSGIServer/0.2 CPython/3.6.3
Content-Type: text/html; charset=utf-8
X-Frame-Options: SAMEORIGIN
Content-Length: 11

Hello World

Como se puede ver, una respuesta HTTP se inicia con una línea de estado que contiene un estatus código y un mensaje de estado. La línea de estado es seguido por un número arbitrario de cabeceras HTTP. Una línea en blanco indica el final de las cabeceras y el inicio del cuerpo de la respuesta, que contiene los datos reales del servidor quiera guardar.

redirecciones HTTP Códigos de estado

¿Cómo es una respuesta de redirección como? Asumamos la ruta / redirección / es manejado por redirect_view (), se mostró anteriormente. Si accede a http://127.0.0.1:8000/redirect/ con rizo, su apariencia de la consola como esta:

$ curl --include http://127.0.0.1:8000/redirect/
HTTP/1.1 302 Found
Date: Sun, 01 Jul 2018 20:35:34 GMT
Server: WSGIServer/0.2 CPython/3.6.3
Content-Type: text/html; charset=utf-8
Location: /redirect-success/
X-Frame-Options: SAMEORIGIN
Content-Length: 0

Las dos respuestas pueden parecer similares, pero hay algunas diferencias clave. La redirección:

  • un código de estado diferente (302 frente a 200)
  • Contiene una cabecera Location con un pariente URL
  • termina con una línea vacía debido a que el cuerpo de la respuesta de redirección está vacía

El principal diferenciador es la código de estado. La especificación de la norma HTTP dice lo siguiente:

El 302 (encontrado) código de estado indica que reside el recurso objetivo temporalmente bajo una diferente URI. Dado que el cambio de dirección podría ser alterado en algunas ocasiones, el cliente debe seguir utilizando el URI de la solicitud efectiva para futuras solicitudes. El servidor debe generar un campo de cabecera Ubicación en la respuesta que contiene una referencia URI para los diferentes URI. El agente de usuario puede utilizar el valor del campo de localización de la redirección automática. (Fuente)

En otras palabras, cada vez que el servidor envía un código de estado de 302, que dice al cliente, “Hey, por el momento, lo que busca se puede encontrar en este otro lugar.”

Una frase clave en la especificación es “puede usar el valor del campo Ubicación para la redirección automática”. Esto significa que no se puede forzar al cliente a cargar otra URL. El cliente puede optar por esperar la confirmación del usuario o decidir no cargar la URL en absoluto.

Ahora se sabe que una redirección es sólo una respuesta HTTP con un código de estado 3xx y una cabecera Location. La conclusión clave aquí es que una redirección HTTP es como cualquier respuesta HTTP de edad, pero con un cuerpo vacío, código de estado 3xx, y una cabecera Location.

Eso es todo. Ataremos esta de nuevo en Django por un momento, pero primero vamos a echar un vistazo a dos tipos de redirecciones en ese rango de código de estado 3xx y ver por qué son importantes cuando se trata de desarrollo web.

temporal frente a la permanente redirecciones HTTP

Los previsto por la norma varios códigos de estado de redirección, todo en la gama 3xx. Los dos más comunes son los códigos de estado 301 Redirección permanente y 302 encontrados. código de estado

A 302 Encontrado indica una redirección temporal. Una redirección temporal dice, “Por el momento, lo que está buscando se puede encontrar en esta otra dirección.” Piense en ello como una señal de tienda que dice: “Nuestra tienda está cerrada por reformas. Por favor, vaya a nuestra otra tienda de la esquina “. Como esto es sólo temporal, usted comprueba la dirección original la próxima vez que vaya de compras.

Nota: En HTTP 1.0, el mensaje de código de estado 302 fue Redirección temporal. El mensaje fue cambiado a encontrados en HTTP 1.1.

Como su nombre lo indica, redirecciones permanentes se supone que deben ser permanentes. Una redirección permanente indica al navegador, “Lo que estás buscando ya no está en esta dirección. Es ahora en esta nueva dirección, y nunca estará en la antigua dirección de nuevo.”

Una redirección permanente es como un signo tienda que dice: “Nos mudamos. Nuestra nueva tienda está a la vuelta de la esquina “. Este cambio es permanente, por lo que la próxima vez que quiera ir a la tienda, que iría directamente a la nueva dirección.

Nota: redirecciones permanentes pueden tener consecuencias no deseadas. Termina esta guía antes de utilizar una redirección permanente o saltar directamente a la sección de “redirecciones permanentes son permanentes.”

Navegadores comportan de manera similar al manejar las redirecciones: cuando una URL devuelve una respuesta de redirección permanente, esta respuesta se almacena en caché. La próxima vez que el navegador encuentra la dirección de edad, recuerda la redirección y solicita directamente la nueva dirección. El almacenamiento en caché

una redirección ahorra una solicitud innecesario y hace que para una mejor y más rápida experiencia de usuario.

Por otra parte, la distinción entre las redirecciones temporales y permanentes es relevante para la optimización del motor de búsqueda.

redirecciones en Django

Ahora se sabe que una redirección es sólo una respuesta HTTP con un código de estado 3xx y una cabecera Location.

Se puede construir una respuesta así a sí mismo de un objeto HttpResponse normal:

def hand_crafted_redirect_view(request):
response = HttpResponse(status=302)
response['Location'] = '/redirect/success/'
return response

Esta solución es técnicamente correcto, pero se trata de un poco de escribir.

El HttpResponseRedirect Clase

Puede ahorrarse algo de tecleo con la clase HttpResponseRedirect, una subclase de HttpResponse. Sólo una instancia de la clase con la URL que desee redirigir como primer argumento, y la clase fijará el estado correcto y cabecera Location:

def redirect_view(request):
return HttpResponseRedirect('/redirect/success/')

Se puede jugar con la clase HttpResponseRedirect en el terminal de Python para ver lo que está recibiendo :

>>> from django.http import HttpResponseRedirect
>>> redirect = HttpResponseRedirect('/redirect/success/')
>>> redirect.status_code
302
>>> redirect['Location']
'/redirect/success/'

también hay una clase para redirecciones permanentes, que es bien llamado HttpResponsePermanentRedirect. Funciona de la misma como HttpResponseRedirect, la única diferencia es que no tiene un código de estado de 301 (movido permanentemente).

Note: En las ejemplos anteriores, las direcciones URL de redirección están codificadas. URL codificación dura es una mala práctica: si el URL cambia nunca, usted tiene que buscar a través de todo el código y cambiar cualquier ocurrencia. Vamos a arreglar eso!

Usted podría utilizar django.urls.reverse () para construir una URL, pero hay una manera más conveniente como se verá en la siguiente sección.

La redirección () Función

Para hacer la vida más fácil, Django proporciona la función de acceso directo versátil que ya hemos visto en la introducción: django.shortcuts.redirect ().

Usted puede llamar a esta función con: instancia de modelo

  • A, o cualquier otro objeto, con un método get_absolute_url ()
  • una URL o nombre de la vista y / argumentos posicionales y o palabra clave
  • Una URL

Será tomar las medidas apropiadas para hacer volver los argumentos en una URL y devolver un HTTPResponseRedirect.If que pase permanente = True, devolverá una instancia de HttpResponsePermanentRedirect, lo que resulta en una redirección permanente.

Aquí hay tres ejemplos para ilustrar los diferentes casos de uso:

Pasando un modelo: redirección

from django.shortcuts import redirect

def model_redirect_view(request):
product = Product.objects.filter(featured=True).first()
return redirect(product)

() llamará product.get_absolute_url () y utilizar el resultado como objetivo redireccionamiento. Si la clase determinada, en este caso del producto, no tiene un método get_absolute_url (), se producirá un error con un TypeError.

pasar un nombre de URL y argumentos:

from django.shortcuts import redirect

def fixed_featured_product_view(request):
...
product_id = settings.FEATURED_PRODUCT_ID
return redirect('product_detail', product_id=product_id)

redirección () tratará de utilizar sus argumentos dados para revertir una dirección URL. Este ejemplo asume sus patrones de URL contienen un patrón de esta manera:

path('/product//', 'product_detail_view', name='product_detail')

pasar una URL:

from django.shortcuts import redirect

def featured_product_view(request):
return redirect('/products/42/')

redirección () tratará cualquier cadena que contenga una / o. como una dirección URL y utilizarlo como objetivo del redireccionamiento.

El RedirectView Class-Based Ver

Si se tiene una vista que no hace más que devolver una redirección, se podría utilizar la clase de vista basados ​​en django.views.generic.base.RedirectView.

usted puede adaptar a sus necesidades RedirectView a través de diversos atributos.

Si la clase tiene un atributo .url, se utiliza como una URL de redireccionamiento. Cuerda marcadores de posición de formato se sustituyen con argumentos con nombre de la URL: Modelo

# urls.py
from django.urls import path
from .views import SearchRedirectView

urlpatterns = [
path('/search//', SearchRedirectView.as_view())
]

# views.py
from django.views.generic.base import RedirectView

class SearchRedirectView(RedirectView):
url = 'https://google.com/?q=%(term)s'

El URL define un plazo argumento, que se utiliza en SearchRedirectView para construir el URL de redirección. El camino / Búsqueda / gatitos / en su aplicación le redirigirá a https://google.com/?q=kittens.

En lugar de la subclasificación RedirectView para sobrescribir el atributo url, también puede pasar la URL argumento de palabra clave a as_view () en sus urlpatterns:

#urls.py
from django.views.generic.base import RedirectView

urlpatterns = [
path('/search//',
RedirectView.as_view(url='https://google.com/?q=%(term)s')),
]

Usted puede también get_redirect_url sobreescritura () para obtener un comportamiento completamente personalizado:

from random import choice
from django.views.generic.base import RedirectView

class RandomAnimalView(RedirectView):

animal_urls = ['/dog/', '/cat/', '/parrot/']
is_permanent = True

def get_redirect_url(*args, **kwargs):
return choice(self.animal_urls)

Esta clase basados ​​en vista redirige a una URL recogidos al azar de .animal_urls.

django.views.generic.base.RedirectView ofrece unos más ganchos para la personalización. Esta es la lista completa:

  • .urlIf este atributo se establece, debe ser una cadena con una URL para redirigir a. Si contiene el formato de cadenas como marcadores de posición% (name) s, que se expanden utilizando los argumentos de palabras clave se pasan a la vista.
  • .pattern_nameIf este atributo se establece, debe ser el nombre de un patrón de URL para redirigir a. Todos los argumentos posicionales y de palabras clave se pasan a la vista se utilizan para revertir el patrón de URL.
  • .permanentIf este atributo es cierto que la vista devuelve una redirección permanente. Por defecto es falso.
  • .query_stringIf este atributo es cierto que el punto de vista añade cualquier cadena de consulta proporcionada a la URL de redireccionamiento. Si es falsa, que es la predeterminada, la cadena de consulta se descarta. get_redirect_url
  • (args *, ** kwargs) Este método es responsable de construir la URL de redireccionamiento. Si este método devuelve Ninguno, la vista devuelve una implementación por defecto 410 status.The Atrás comprueba primero .url. Se trata .url como una cadena de formato “viejo estilo”, utilizando los parámetros de URL nombrados pasados ​​a la vista para expandir cualquier formato de .url specifiers.If llamada no se establece, comprueba si .pattern_name se establece. Si lo es, se lo utiliza para revertir una dirección URL con argumentos posicionales y de palabras clave que received.You puede cambiar ese comportamiento en la forma que desee al sobrescribir este método. Sólo asegúrese de que devuelve una cadena que contiene una URL.

.url

Si este atributo se establece, debe ser una cadena con una URL para redirigir a. Si contiene el formato de cadenas como marcadores de posición% (name) s, que se expanden utilizando los argumentos de palabras clave se pasan a la vista.

.pattern_name

Si este atributo se establece, debe ser el nombre de un patrón de URL para redirigir a. Todos los argumentos posicionales y de palabras clave se pasan a la vista se utilizan para revertir el patrón de URL.

.permanent

Si este atributo es cierto que la vista devuelve una redirección permanente. Por defecto es falso.

.query_string

Si este atributo es cierto que el punto de vista añade cualquier cadena de consulta proporcionada a la URL de redireccionamiento. Si es falsa, que es la predeterminada, la cadena de consulta se descarta.

get_redirect_url (* args, ** kwargs)

Este método es responsable de construir la URL de redireccionamiento. Si este método devuelve None, la vista devuelve un estado Atrás 410. comprueba primero

la implementación predeterminada .url. Se trata .url como una cadena de formato “viejo estilo”, utilizando los parámetros de URL con nombre que se pasan al objeto de ampliar los especificadores de formato mencionadas.

Si .url no está establecido, comprueba si es .pattern_name conjunto. Si lo es, se lo utiliza para revertir una dirección URL con argumentos posicionales y de palabras clave que ha recibido.

Puede cambiar ese comportamiento en la forma que desee al sobrescribir este método. Sólo asegúrese de que devuelve una cadena que contiene una URL.

Nota: puntos de vista basados ​​en la clase son un concepto poderoso, pero puede ser un poco difícil de envolver su cabeza alrededor. A diferencia de puntos de vista basados ​​en funciones regulares, en las que es relativamente fácil de seguir el flujo del código, puntos de vista basados ​​en clases se componen de una compleja jerarquía de mixins y clases base.

Una gran herramienta para dar sentido a una clase de vista basado en la clase es el sitio web Vistas con clase basada en la clase.

Se podría implementar la funcionalidad de RandomAnimalView en el ejemplo anterior con este simple vista basado en las funciones:

from random import choice
from django.shortcuts import redirect

def random_animal_view(request):
animal_urls = ['/dog/', '/cat/', '/parrot/']
return redirect(choice(animal_urls))

Como se puede ver, el enfoque basado en la clase no proporciona ningún beneficio obvio al tiempo que añade cierta complejidad oculta. Esto plantea la pregunta: ¿cuándo se debe utilizar RedirectView?

Si desea agregar una redirección directamente en su urls.py, utilizando RedirectView tiene sentido. Pero si usted se encuentra el sobreescribiendo get_redirect_url, una visión basada en la función podría ser más fácil de entender y más flexible para futuras mejoras. Uso

avanzada

Una vez que sabe que es probable que desee utilizar django.shortcuts.redirect (), redirigir a una URL diferente es bastante sencilla. Pero hay un par de casos de uso avanzadas que no son tan evidentes.

Paso de parámetros con redirecciones

A veces, se desea pasar algunos parámetros a la vista que se está realizando el redireccionamiento a. Su mejor opción es pasar los datos en la cadena de consulta de URL de redireccionamiento, que significa volver a dirigir a un URL como esta: de

http://example.com/redirect-path/?parameter=value

Let suponga que desea redirigir desde some_view () para product_view (), pero pasar a una categoría de parámetro opcional :

from django.urls import reverse
from urllib.parse import urlencode

def some_view(request):
...
base_url = reverse('product_view') # 1 /products/
query_string = urlencode({'category': category.id}) # 2 category=42
url = '{}?{}'.format(base_url, query_string) # 3 /products/?category=42
return redirect(url) # 4

def product_view(request):
category_id = request.GET.get('category') # 5
# Do something with category_id

el código de este ejemplo es bastante denso, así que vamos a seguir paso a paso:

en primer lugar, se utiliza django.urls.reverse () para obtener la asignación de dirección URL a product_view ().

A continuación, usted tiene que construir la cadena de consulta. Esa es la parte que sigue al signo de interrogación. Es aconsejable el uso de urllib.urlparse.urlencode () para que, a medida que se encargará de codificar correctamente todos los caracteres especiales.

Ahora usted tiene que unirse base_url y query_string con un signo de interrogación. Una cadena de formato funciona bien para eso.

Por último, se pasa url para django.shortcuts.redirect () o para una clase de respuesta de redirección.

En product_view (), el objetivo del redireccionamiento, el parámetro estará disponible en el diccionario request.GET. El parámetro puede faltar, por lo que debe utilizar requests.GET.get ( ‘categoría’) en lugar de requests.GET [ ‘categoría. El ex rendimientos Ninguno cuando no existe el parámetro, mientras que el último sería lanzar una excepción.

Nota: Asegúrese de que para validar los datos que se leen de las cadenas de consulta. Podría parecer que estos datos está bajo su control, ya que ha creado la URL de redirección.

En realidad, la redirección podría ser manipulado por el usuario y no debe ser de confianza, al igual que cualquier otra entrada del usuario. Sin validación adecuada, un atacante podría ser capaz de obtener acceso no autorizado. Códigos

de redireccionamiento especial

Django provee HTTP clases de respuesta de los códigos de estado 301 y 302. Los que deben cubrir la mayoría de los casos de uso, pero si alguna vez tiene que devolver los códigos de estado 303, 307, o 308, se puede crear fácilmente su propio la clase de respuesta. Simplemente subclase HttpResponseRedirectBase y sobrescribir el atributo status_code:

class HttpResponseTemporaryRedirect(HttpResponseRedirectBase):
status_code = 307

Alternativamente, se puede utilizar el método django.shortcuts.redirect () para crear un objeto de respuesta y cambiar el valor de retorno. Este enfoque tiene sentido cuando se tiene el nombre de una vista o una URL o un modelo que desea redirigir a:

def temporary_redirect_view(request):
response = redirect('success_view')
response.status_code = 307
return response

Nota: realidad, hay una tercera clase con un código de estado en la gama 3xx: HttpResponseNotModified, con la condición código 304. se indica que el URL contenido no ha cambiado y que el cliente puede utilizar una versión en caché.

Se podría argumentar que 304 Not Modified redirecciones de respuesta a la versión en caché de una URL, pero eso es un poco de un tramo. En consecuencia, se ya no aparece en la sección “redirección 3xx” de la norma HTTP.

Errores

redireccionamientos que se acaba de redirección no

La simplicidad de django.shortcuts.redirect () puede ser engañoso. La función en sí no realiza una redirección: simplemente devuelve un objeto de respuesta de redirección. Debe devolver este objeto respuesta de su punto de vista (o en un middleware). De lo contrario, sin redirección va a suceder.

Pero incluso si sabe que redirección simplemente llamando al () no es suficiente, es fácil introducir este error en una aplicación de trabajo a través de un simple refactorización. Aquí está un ejemplo para ilustrar que. de

Let asumen que usted está construyendo una tienda y tiene una vista que se encarga de mostrar un producto. Si el producto no existe, se redirige a la página de inicio:

def product_view(request, product_id):
try:
product = Product.objects.get(pk=product_id)
except Product.DoesNotExist:
return redirect('/')
return render(request, 'product_detail.html', {'product': product})

Ahora vamos a añadir un segundo objeto de críticas pantalla del cliente para un producto. También debe redirigir a la página de inicio para los productos no existentes, así como un primer paso, extraer esta funcionalidad de product_view () en un get_product_or_redirect función auxiliar ():

def get_product_or_redirect(product_id):
try:
return Product.objects.get(pk=product_id)
except Product.DoesNotExist:
return redirect('/')

def product_view(request, product_id):
product = get_product_or_redirect(product_id)
return render(request, 'product_detail.html', {'product': product})

Por desgracia, después de la refactorización, la redirección ya no funciona .

¿Se puede detectar el error? Mostrar / Ocultar

El resultado de redirección () se devuelve desde get_product_or_redirect (), pero product_view () no devuelve la misma. En su lugar, se pasa a la plantilla.

Dependiendo de cómo se utiliza la variable del producto en la plantilla product_detail.html, esto podría no resultar en un mensaje de error y simplemente mostrar los valores vacíos.

redireccionamientos que se acaba de parada no redireccionante

Cuando se trata de redirecciones, puede crear accidentalmente un bucle de redireccionamiento, por tener un retorno URL de una redirección que apunta al URL B que devuelve una redirección a URL A, y así sucesivamente. La mayoría de los clientes HTTP detectan este tipo de bucle de redireccionamiento y se mostrará un mensaje de error después de un número de peticiones.

Por desgracia, este tipo de error puede ser difícil de detectar porque todo se ve bien en el lado del servidor. A menos que sus usuarios se quejan de la cuestión, la única indicación de que algo no está bien es que usted tiene un número de peticiones de un cliente que todo el resultado de una respuesta de redirección en rápida sucesión, pero no hay respuesta con un estado 200 OK.

He aquí un ejemplo simple de un bucle de redireccionamiento:

def a_view(request):
return redirect('another_view')

def another_view(request):
return redirect('a_view')

Este ejemplo ilustra el principio, pero es demasiado simplista. Los bucles de redirección te vas a encontrar en la vida real son probablemente va a ser más difícil de detectar. Echemos un vistazo a un ejemplo más elaborado:

def featured_products_view(request):
featured_products = Product.objects.filter(featured=True)
if len(featured_products == 1):
return redirect('product_view', kwargs={'product_id': featured_products[0].id})
return render(request, 'featured_products.html', {'product': featured_products})

def product_view(request, product_id):
try:
product = Product.objects.get(pk=product_id, in_stock=True)
except Product.DoesNotExist:
return redirect('featured_products_view')
return render(request, 'product_detail.html', {'product': product})

featured_products_view () recupera todos los productos destacados, en otros casos las palabras de producto con el conjunto .featured en True. Si sólo existe un producto destacado, redirecciona directamente a product_view (). De lo contrario, se muestra una plantilla con el queryset featured_products.

El product_view parece familiar de la sección anterior, pero tiene dos diferencias menores:

  • La vista intenta obtener un producto que está en stock, indicado por tener .in_stock conjunto en True.
  • La vista se vuelve a dirigir a featured_products_view () si no hay producto en stock.

Esta lógica funciona bien hasta que su tienda se convierte en una víctima de su propio éxito y el producto ofrecido tiene actualmente sale de stock. Si se establece en False .in_stock pero se olvide de establecer .featured en False así, entonces cualquier visitante a su feature_product_view () ahora será atrapado en un bucle de redireccionamiento.

No hay manera a prueba de balas para evitar este tipo de error, sino un punto de partida bueno es comprobar si la vista está redirigiendo a los usos redirige a sí mismo. redirecciones

redirecciones permanentes son

Permanente

permanentes pueden ser como los malos tatuajes: podrían parecer una buena idea en el momento, pero una vez que te das cuenta de que eran un error, que puede ser muy difícil deshacerse de ellos.

Cuando un navegador recibe una respuesta de redirección permanente para una URL, almacena en caché esta respuesta de forma indefinida. Cualquier momento de solicitar la dirección de edad en el futuro, el navegador no se molesta en lo carga y se carga directamente a la nueva URL.

Puede ser muy difícil convencer a un navegador para cargar una URL que una vez que regresó una redirección permanente. Google Chrome es especialmente agresivo cuando se trata de redirecciones de almacenamiento en caché.

¿Por qué puede ser esto un problema?

Imagínese usted quiere construir una aplicación web con Django. Registre su dominio en myawesomedjangowebapp.com. Como primer paso, se instala una aplicación de blog en https://myawesomedjangowebapp.com/blog/ para construir una lista de correo de lanzamiento. página

de su sitio en https://myawesomedjangowebapp.com/ está todavía en construcción, por lo que redirecciona a https://myawesomedjangowebapp.com/blog/. Decide utilizar una redirección permanente porque has oído que redirecciones permanentes se almacenan en caché y caché de hacer las cosas más rápido y más rápido es mejor porque la velocidad es un factor para la clasificación en los resultados de búsqueda de Google.

Como resultado, usted no es sólo un gran desarrollador, sino también un escritor de talento. Su blog se hace popular, y su lista de correo lanzamiento crece. Después de un par de meses, su aplicación está lista. Ahora cuenta con una página de inicio brillante, y finalmente eliminar la redirección.

Usted envía un correo electrónico con un código de anuncio descuento especial a su lista de correo lanzamiento de tamaño considerable. De vuelta magra y esperar a que las notificaciones de registro para rodar en.

Para su horror, sus rellenos de buzón de mensajes de los visitantes confundido que quieren visitar su aplicación, pero siempre están siendo redirigidos a tu blog.

¿Qué ha pasado? Sus lectores del blog habían visitado https://myawesomedjangowebapp.com/ cuando la redirección a https://myawesomedjangowebapp.com/blog/ seguía activo. Debido a que era una redirección permanente, se almacena en caché en sus navegadores.

Cuando se hace clic en el enlace en su correo anuncio de lanzamiento, sus navegadores nunca se molestó en comprobar su nueva página de inicio y se dirigió directamente a su blog. En lugar de celebrar su exitoso lanzamiento, que está ocupado instruyendo a sus usuarios cómo jugar con chrome: // net-internals para restablecer la memoria caché de sus navegadores.

El carácter permanente de redirecciones permanentes también le puede morder mientras que el desarrollo de su ordenador local. rebobinado Vamos al momento en que se implementó que redirección permanente fatídico para myawesomedjangowebapp.com.

se inicia el servidor de desarrollo y http://127.0.0.1:8000/ abierta. Tal como se pretende, la aplicación redirige el navegador a http://127.0.0.1:8000/blog/. Satisfecho con su trabajo, se detiene el servidor de desarrollo e ir a comer.

enviar de regreso con el estómago lleno, listo para hacer frente a algunos de trabajo del cliente. El cliente quiere algunos cambios simples en su página web, de modo que cargue el proyecto del cliente e iniciar el servidor de desarrollo.

Pero espera, ¿qué está pasando aquí? La página principal está roto, ahora devuelve un 404! Debido a la caída de la tarde, que le lleva un tiempo darse cuenta de que estás siendo redirigido al http://127.0.0.1:8000/blog/, que no existe en el proyecto del cliente.

Para el navegador, no importa que el http://127.0.0.1:8000/ URL ahora sirve una aplicación completamente diferente. Lo único que importa es que el navegador que esta URL una vez en el pasado devolvió una redirección permanente a http://127.0.0.1:8000/blog/.

La lección de esta historia es que sólo se debe utilizar redirecciones permanentes en las direcciones URL que usted no tiene ninguna intención de volver a utilizar de nuevo. Hay un lugar para redirecciones permanentes, pero hay que ser conscientes de sus consecuencias.

Even if you’re confident that you really need a permanent redirect, it’s a good idea to implement a temporary redirect first and only switch to its permanent cousin once you’re 100% sure everything works as intended.

Unvalidated Redirects Can Compromise Security

From a security perspective, redirects are a relatively safe technique. An attacker cannot hack a website with a redirect. After all, a redirect just redirects to a URL that an attacker could just type in the address bar of their browser.

However, if you use some kind of user input, like a URL parameter, without proper validation as a redirect URL, this could be abused by an attacker for a phishing attack. This kind of redirect is called an open or unvalidated redirect.

There are legitimate use cases for redirecting to URL that is read from user input. A prime example is Django’s login view. It accepts a URL parameter next that contains the URL of the page the user is redirected to after login. To redirect the user to their profile after login, the URL might look like this:

https://myawesomedjangowebapp.com/login/?next=/profile/

Django does validate the next parameter, but let’s assume for a second that it doesn’t.

Without validation, an attacker could craft a URL that redirects the user to a website under their control, for example:

https://myawesomedjangowebapp.com/login/?next=https://myawesomedjangowebapp.co/profile/

The website myawesomedjangowebapp.co might then display an error message and trick the user into entering their credentials again.

The best way to avoid open redirects is to not use any user input when building a redirect URL.

If you cannot be sure that a URL is safe for redirection, you can use the function django.utils.http.is_safe_url() to validate it. The docstring explains its usage quite well:

is_safe_url(url, host=None, allowed_hosts=None, require_https=False)

Return True if the url is a safe redirection (i.e. it doesn’t point to a different host and uses a safe scheme).Always return False on an empty url.If require_https is True, only ‘https’ will be considered a valid scheme, as opposed to ‘http’ and ‘https’ with the default, False. (Source)

Let’s look at some examples.

A relative URL is considered safe:

>>> # Import the function first.
>>> from django.utils.http import is_safe_url
>>> is_safe_url('/profile/')
True

A URL pointing to another host is generally not considered safe:

>>> is_safe_url('https://myawesomedjangowebapp.com/profile/')
False

A URL pointing to another host is considered safe if its host is provided in allowed_hosts:

>>> is_safe_url('https://myawesomedjangowebapp.com/profile/',
... allowed_hosts={'myawesomedjangowebapp.com'})
True

If the argument require_https is True, a URL using the http scheme is not considered safe:

>>> is_safe_url('http://myawesomedjangowebapp.com/profile/',
... allowed_hosts={'myawesomedjangowebapp.com'},
... require_https=True)
False

Summary

This wraps up this guide on HTTP redirects with Django. Congratulations: you have now touched on every aspect of redirects all the way from the low-level details of the HTTP protocol to the high-level way of dealing with them in Django.

You learned how an HTTP redirect looks under the hood, what the different status codes are, and how permanent and temporary redirects differ. This knowledge is not specific to Django and is valuable for web development in any language.

You can now perform a redirect with Django, either by using the redirect response classes HttpResponseRedirect and HttpResponsePermanentRedirect, or with the convenience function django.shortcuts.redirect(). You saw solutions for a couple of advanced use cases and know how to steer clear of common pitfalls.

If you have any further question about HTTP redirects leave a comment below and in the meantime, happy redirecting!

References

  • Django documentation: django.http.HttpResponseRedirect
  • Django documentation: django.shortcuts.render()
  • Django documentation: django.views.generic.base.RedirectView
  • RFC 7231: Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content – 6.4 Redirection 3xx
  • CWE-601: URL Redirection to Untrusted Site (‘Open Redirect’)
Categorías
Python

Las variables en Python

 

Tabla de Contenidos

  • conocer a los Python tortuga Biblioteca
  • Introducción a la tortuga
  • Programación Con turtleMoving la TurtleDrawing un ShapeDrawing preestablecido FiguresChanging la pantalla Colorchanging la pantalla TitleChanging la tortuga SizeChanging la pluma SizeChanging la tortuga y la pluma ColorFilling en una ImageChanging la tortuga cambiar de forma la pluma SpeedCustomizing en uno LinePicking la pluma de arriba DownUndoing ChangesClearing la ScreenResetting la EnvironmentLeaving un StampCloning su tortuga
  • Traslado de la tortuga
  • dibujando una forma
  • dibujo preestablecido Figuras
  • Cambiar el color de la pantalla
  • Cambio de la pantalla título
  • Cambio del tamaño de la tortuga
  • Cambio de la pluma Tamaño
  • Cambiar el llenado de la tortuga y la pluma de color
  • en una imagen
  • Cambio de la forma de la tortuga
  • Cambio de la
  • pluma Personalización velocidad en una línea
  • Recogiendo la pluma de arriba hacia abajo
  • deshacer los cambios
  • borrar la pantalla
  • Restablecimiento del Medio Ambiente
  • Dejando un sello
  • Clonación su tortuga
  • mediante bucles y sentencias condicionales Statementsfor Loopswhile LoopsConditional
  • para Loops
  • mientras Loops
  • declaraciones

  • condicionales
  • Proyecto Fin de Carrera: la tortuga Python RaceSetting el juego EnvironmentSetting Hasta las tortugas y HomesCreating la DieDeveloping el Juego
  • Configuración del Juego para el Medio Ambiente
  • Configuración de las tortugas y Casas
  • Creación del Die
  • desarrollo del juego
  • Conclusión
  • Traslado de la tortuga
  • dibujando una forma
  • dibujo preestablecido Figuras
  • Cambiar el color de la pantalla
  • Cambio de la pantalla de título
  • Cambio de la tortuga Tamaño
  • Cambio del tamaño de la pluma
  • Cambio de la tortuga y Relleno Pluma del color
  • en una imagen
  • Cambio de la forma de la tortuga
  • Cambio de la pluma velocidad
  • Personalización en una línea
  • Recogiendo la pluma de arriba hacia abajo
  • deshacer los cambios
  • borrar la pantalla
  • Restablecimiento del Medio Ambiente
  • dejando un sello
  • clonación su tortuga
  • para Loops
  • while bucles
  • condicionales
  • Configuración del Juego para el Medio Ambiente
  • Configuración de las tortugas y Casas
  • Creación del Die
  • desarrollo del Juego

Cuando yo era un niño, he usado para aprender logotipo, un lenguaje de programación que involucró a una tortuga que se puede mover por la pantalla con unos pocos comandos. Recuerdo sentir como un genio de la informática como yo controlaba este pequeño objeto en la pantalla, y esto fue lo que me interesó en la programación en el primer lugar. La biblioteca tortuga Python viene con una función interactiva similar que da nuevos programadores una muestra de lo que es trabajar con Python.

En este tutorial, será:

  • entender lo que la biblioteca de tortuga Python es
  • aprender a configurar tortuga en el equipo del programa
  • con la biblioteca tortuga Python

  • Agarre algunos conceptos importantes de Python y comandos de tortuga
  • Desarrollar un corto pero entretenido juego usando lo aprendido

Si usted es un principiante a Python, entonces este tutorial le ayudará a medida que toma sus primeros pasos en el mundo de la programación con la ayuda de la tortuga Python ¡biblioteca! Bono

gratuito: Haga clic aquí para obtener una hoja de trucos Python y aprender los conceptos básicos de Python 3, como trabajar con tipos de datos, diccionarios, listas y funciones de Python.

Introducción a la Biblioteca de Python tortuga

tortuga es una biblioteca de pre-instalado Python que permite a los usuarios crear imágenes y formas, proporcionándoles un lienzo virtual. La pluma en pantalla que se utiliza para el dibujo se llama el tortuga y esto es lo que da la biblioteca de su nombre. En resumen, la biblioteca de Python tortuga ayuda a los nuevos programadores tener una idea de lo que la programación con Python es como en una forma divertida e interactiva. tortuga

se utiliza principalmente para introducir a los niños al mundo de los ordenadores. Es un sencillo pero versátil manera de entender los conceptos de Python. Esto hace que sea una gran avenida para que los niños dan sus primeros pasos en la programación Python. Una vez dicho esto, la biblioteca tortuga Python no se limita a pequeños solos! También se demostró ser extremadamente útil para los adultos que están tratando de sus manos en Python, lo que lo hace ideal para principiantes de Python.

Con la biblioteca tortuga Python, se puede dibujar y crear varios tipos de formas e imágenes. He aquí una muestra de los tipos de dibujos que puede hacer con la tortuga:

frío, ¿verdad? Este es sólo uno de muchos dibujos diferentes que usted puede hacer uso de la biblioteca tortuga Python. La mayoría de los desarrolladores utilizan tortuga para dibujar formas, crear diseños y hacer imágenes. Otros utilizan tortuga para crear mini-juegos y animaciones, al igual que el que usted vio anteriormente.

Introducción a la tortuga

Antes de continuar, hay dos cosas importantes que usted necesita hacer para aprovechar al máximo este tutorial: Medio ambiente Python

: Asegúrese de que usted está familiarizado con el entorno de programación . Puede utilizar aplicaciones como inactivo o Jupyter portátil con el programa con la tortuga. Sin embargo, si no se siente cómodo con ellos, entonces se puede programar con el REPL, que vamos a usar en este tutorial.

versión de Python: Asegúrese de que tiene la versión 3 de Python en su ordenador. Si no es así, puede descargarlo desde el sitio web de Python. Para el ajuste de la ayuda las cosas, echa un vistazo a Python 3 Instalación y Guía de configuración.

Lo bueno de tortuga es que se trata de una biblioteca incorporada, por lo que no necesita instalar cualquier paquete nuevo. Todo lo que necesita hacer es importar la biblioteca de Python en su entorno, que en este caso sería el REPL. Una vez que abra la aplicación REPL, puede ejecutar Python 3 en él escribiendo la siguiente línea de código:

>>> python3

Esto requiere Python 3 en su aplicación REPL y abre el medio ambiente para usted.

Antes de comenzar la programación Python, es necesario comprender lo que es una biblioteca de es. En el mundo no-computadora, una biblioteca es un lugar donde se almacenan diferentes tipos de libros. Se puede acceder a estos libros en cualquier momento, toma toda la información que necesita de ellos, y devolverlos al mismo lugar.

En el mundo de la informática, una biblioteca funciona de manera similar. Por definición, una biblioteca es un conjunto de funciones y métodos importantes que se puede acceder para hacer su programación más fácil. La tortuga Python biblioteca contiene todos los métodos y funciones que usted necesita para crear sus imágenes. Para acceder a una biblioteca de Python , es necesario importarlo en su entorno de Python, así:

>>> import turtle

Ahora que tiene tortuga en su entorno Python, puede empezar a programar con ella. tortuga es una biblioteca gráfica, lo que significa que tendrá que crear una ventana separada (llamada la pantalla ) para llevar a cabo cada una orden de dibujar. Puede crear esta pantalla inicializando una variable para ello.

En Python, se utilizan variables para almacenar información que va a utilizar más adelante en su programa. Usted initialize una variable cuando se asigna un valor a partir de ella. Dado que el valor de la variable no es constante, puede cambiar varias veces durante la ejecución de su programa.

Ahora, para abrir la pantalla de tortuga, que inicializar una variable para ello de la siguiente manera:

>>> s = turtle.getscreen()

Debería ver una ventana separada abierta hasta:

Esta ventana se llama la pantalla . Es donde se puede ver el resultado de su código. La pequeña forma triangular negro en el centro de la pantalla se llama el tortuga .

Nota : Tenga en cuenta que al dar nombre a una variable, es necesario escoger un nombre que puede ser fácilmente entendido por cualquier persona que está mirando su programa. Sin embargo, también debe elegir un nombre que sea conveniente para su uso, sobre todo porque se le llama muy a menudo a través de su programa!

Por ejemplo, la elección de un nombre como my_turtle_ pantalla _name sería tedioso para seguir escribiendo, mientras que un nombre como Joe o una aparecerá habría de ser muy aleatorio. El uso de un único carácter del alfabeto, como s en este caso, sería mucho más adecuado. Eso es porque es corto y dulce, y está claro que recordar que la letra s refiere a la pantalla .

A continuación, se inicializa la variable t, que usted luego usar durante todo el programa para referirse a la tortuga:

>>> t = turtle.Turtle()

Al igual que para la pantalla, también se puede dar a esta variable como un otro nombre o Jane o incluso my_turtle, pero en este caso, usted se pega con t.

Ahora tiene su pantalla y su tortuga. La pantalla actúa como un lienzo, mientras que la tortuga actúa como una pluma. Se puede programar la tortuga para desplazarse por la pantalla. La tortuga tiene ciertas características cambiantes, tamaño como, el color y la velocidad. Siempre apunta en una dirección específica, y se moverá en esa dirección, a menos que usted le indique lo contrario:

  • Cuando le toca, que significa que ninguna línea se dibujará cuando se mueve.
  • cuando está abajo, significa que una línea se dibujará cuando se mueve.

En la siguiente sección, explorará los diferentes modos de programación con la biblioteca tortuga Python.

Programación Con tortuga

La primera cosa que usted aprenderá lo que se refiere a la programación con la biblioteca de Python tortuga es cómo hacer que el movimiento de la tortuga en la dirección que quiere que vaya. A continuación, usted aprenderá cómo personalizar su tortuga y su entorno. Por último, aprenderá un par de comandos adicionales con las que se pueden realizar algunas tareas especiales.

Moviendo la tortuga

Hay cuatro direcciones que una tortuga puede mover en:

  • adelante hacia atrás
  • Izquierda Derecha

la tortuga se mueve .forward () o .backward () en el sentido de que se enfrenta. Puede cambiar esta dirección girándolo en .Left () o .RIGHT () por un cierto grado. Usted puede tratar cada uno de estos comandos, así:

>>> t.right(90)
>>> t.forward(100)
>>> t.left(90)
>>> t.backward(100)

Al ejecutar estas órdenes, la tortuga se gira a la derecha por noventa grados, ir hacia adelante por un centenar de unidades, gire a la izquierda por noventa grados, y se mueven hacia atrás por un centenar de unidades. Se puede ver cómo esto se ve en la imagen de abajo:

Puede utilizar las versiones abreviadas de estos comandos, así:

  • t.rt () en lugar de t.right ()
  • t.fd () en lugar de t.forward ()
  • t.lt () en lugar de t.left ()
  • t.bk () en lugar de t.backward ()

también puede dibujar una línea desde su posición actual a cualquier otra posición arbitraria en la pantalla. Esto se realiza con la ayuda de las coordenadas:

La pantalla se divide en cuatro cuadrantes. El punto donde la tortuga se posiciona inicialmente en el comienzo de su programa es (0,0). Esto se llama Inicio . Para mover la tortuga para cualquier otra área de la pantalla, se utiliza .goto () e introduce las coordenadas de esta manera:

>>> t.goto(100,100)

Su salida se vería así:

que ha dibujado una línea desde su posición actual hasta el punto (100,100) en la pantalla.

Para traer la parte posterior de la tortuga a su posición inicial, escribe lo siguiente:

>>> t.home()

Esto es como un comando de acceso directo que envía la parte posterior de la tortuga hasta el punto (0,0). Es más rápido que t.goto tipificación (0,0).

Dibujo

una forma de

Ahora que ya conoce los movimientos de la tortuga, se puede pasar a la creación de formas reales. Puede comenzar dibujando polígonos ya que todos ellos consisten en líneas rectas conectadas en ciertos ángulos. He aquí un ejemplo que puede probar:

>>> t.fd(100)
>>> t.rt(90)
>>> t.fd(100)
>>> t.rt(90)
>>> t.fd(100)
>>> t.rt(90)
>>> t.fd(100)

Su salida se vería así:

Bien hecho! Usted sólo ha dibujado un cuadrado. De esta manera, la tortuga puede ser programado para crear diferentes formas e imágenes .

Ahora, trate de dibujar un rectángulo, usando este código como una plantilla. Recuerde, en un rectángulo, los cuatro lados no son iguales. Tendrá que cambiar el código en consecuencia. Una vez hecho eso, incluso se puede intentar crear otros polígonos, aumentando el número de lados y cambiar los ángulos.

dibujo preestablecido Figuras

Supongamos que desea dibujar un círculo . Si intenta sacarla de la misma manera como se ha dibujado la plaza, entonces sería muy tedioso, y que tendría que pasar mucho tiempo sólo para que uno forma. Afortunadamente, la biblioteca tortuga Python proporciona una solución para esto. Puede utilizar un solo comando para dibujar un círculo :

>>> t.circle(60)

Usted obtendrá una salida como esta:

El número entre paréntesis es el radio de del círculo. Puede aumentar o disminuir el tamaño del círculo cambiando el valor de su radio de .

De la misma manera, también se puede dibujar un punto , que no es sino un círculo rellenado es. Escriba en este orden:

>>> t.dot(20)

Usted obtendrá un círculo relleno de esta manera:

El número entre paréntesis es el diámetro del punto. Al igual que con el círculo, se puede aumentar o disminuir el tamaño del punto al cambiar el valor de su diámetro.

gran trabajo hasta ahora! Usted ha aprendido cómo mover la tortuga alrededor y crear diferentes formas de la misma. En las siguientes secciones, verá cómo se pueden personalizar a su tortuga y su entorno, en función de sus necesidades.

Cambiar el color de la pantalla

Por defecto, la tortuga siempre se abre una pantalla con un fondo blanco. Sin embargo, puede cambiar el color de de la pantalla en cualquier momento utilizando el siguiente comando:

>>> turtle.bgcolor("blue")

Puede reemplazar «azul» con cualquier otro color. Tratar «verde» o «rojo». Usted obtendrá un resultado como este:

Se puede utilizar una variedad de colores para su pantalla con tan sólo escribir en su número de código hexadecimal. Para obtener más información sobre el uso de diferentes colores, echa un vistazo a la documentación de la biblioteca tortuga Python.

Cambio de la pantalla de título

A veces, es posible que desee cambiar el título de la pantalla. Puede hacerlo más personal, como «Programa de Tortuga Mi», o más adecuada a lo que está trabajando, como «Dibujo de formas con la tortuga». Puede cambiar el título de la pantalla con la ayuda de este comando:

>>> turtle.title("My Turtle Program")

su barra de título mostrará ahora esto:

De esta manera, se puede cambiar el rumbo de la pantalla según sus preferencias.

Cambio del tamaño de la tortuga

Puede aumentar o disminuir el tamaño de la tortuga en pantalla para hacerlo más grande o más pequeño. Esto cambia sólo el tamaño de la forma sin afectar a la salida de la pluma, ya que llama en la pantalla. Pruebe a escribir en los siguientes comandos:

>>> t.shapesize(1,5,10)
>>> t.shapesize(10,5,1)
>>> t.shapesize(1,10,5)
>>> t.shapesize(10,1,5)

Sus salidas se vería así:

Los números dados son la parámetros para el tamaño de la tortuga:

  • longitud estiramiento
  • estiramiento ancho
  • Anchura de contorno

puede cambiar estos de acuerdo a su preferencia. En el ejemplo anterior, se puede ver una diferencia visible en la apariencia de la tortuga. Para obtener más información sobre cómo se puede cambiar el tamaño de la tortuga, echa un vistazo a la documentación de la biblioteca tortuga Python.

Cambio del tamaño de la pluma

El comando anterior cambia el tamaño de la forma única de la tortuga. Sin embargo, a veces, puede que tenga que aumentar o disminuir el espesor de su pluma. Usted puede hacer esto mediante el siguiente comando:

>>> t.pensize(5)
>>> t.forward(100)

Esto resulta en un resultado como éste:

Como se puede ver, el tamaño de su pluma es ahora cinco veces su tamaño original (que era uno). Intenta dibujar algunas líneas más de varios tamaños, y comparar la diferencia de espesor entre ellos.

Cambio de la tortuga y del color de la pluma

primera vez que abra una nueva pantalla, la tortuga comienza como una figura de negro y dibuja con tinta negro. En función de sus necesidades, puede hacer dos cosas:

  • cambiar el color de la tortuga: Esto cambia el color de relleno.
  • Cambiar el color de la pluma: Esto cambia el esquema o el color de la tinta.

Usted puede incluso elegir ambos si así lo desea. Antes de cambiar los colores, aumentar el tamaño de su tortuga para ayudarle a ver la diferencia de color más claro. Escriba este código:

>>> t.shapesize(3,3,3)

Ahora, para cambiar el color de la tortuga (o el relleno), escribe la siguiente:

>>> t.fillcolor("red")

su tortuga se verá así:

Para cambiar el color de la pluma (o el contorno), escribe la siguiente:

>>> t.pencolor("green")

su tortuga se verá así:

Para cambiar el color de ambos, escribe la siguiente:

>>> t.color("green", "red")

su tortuga se verá así:

Aquí, el primer color es para la pluma, y ​​el segundo es para el relleno. Tenga en cuenta que al cambiar el color de la pluma y el relleno también cambia el color de la tortuga en pantalla en consecuencia.

La cumplimentación de una imagen

colorear una imagen en general hace que se vea mejor, ¿no? La biblioteca tortuga Python le da la opción de añadir color a sus dibujos. Pruebe a escribir en el siguiente código y ver lo que sucede:

>>> t.begin_fill()
>>> t.fd(100)
>>> t.lt(120)
>>> t.fd(100)
>>> t.lt(120)
>>> t.fd(100)
>>> t.end_fill()

Cuando se ejecuta este código, se obtendrá un triángulo que está llena con un color sólido, como esto:

Cuando se utiliza .beginfill (), usted está diciendo a su programa que va a ser dibujar una forma cerrada que tendrá que ser rellenado. a continuación, utilizar .endfill () para indicar que ya está creando su forma y ahora puede ser rellenado .

Cambio de la forma de la tortuga

la forma inicial de la tortuga no es realmente una tortuga, pero una figura triangular. Sin embargo, puede cambiar la forma de la tortuga se ve , y usted tiene un par de opciones cuando se trata de hacerlo. Puede echar un vistazo a algunos de ellos escribiendo los siguientes comandos:

>>> t.shape("turtle")
>>> t.shape("arrow")
>>> t.shape("circle")

La forma de la tortuga cambiará en consecuencia, de esta manera:

Usted tiene un par de otras opciones que se pueden tratar así:

  • Plaza
  • Flecha
  • Círculo
  • tortuga
  • Triángulo
  • clásico

la forma clásica es la forma original. Echa un vistazo a la documentación de la biblioteca tortuga Python para obtener más información sobre los tipos de formas que se pueden utilizar.

Cambio de la velocidad de la pluma

La tortuga generalmente se mueve a un ritmo moderado. Si desea aumentar o disminuir la velocidad para hacer su movimiento tortuga más lento o más rápido, a continuación, puede hacerlo escribiendo lo siguiente:

>>> t.speed(1)
>>> t.forward(100)
>>> t.speed(10)
>>> t.forward(100)

Este código será primera disminuir la velocidad y mover la tortuga hacia adelante y luego aumentar la velocidad y mover la tortuga de nuevo hacia delante, como este:

la velocidad puede ser cualquier número que va de 0 (la velocidad más baja) a 10 (la velocidad más alta). Puede jugar con su código para ver qué tan rápido o más lento que la tortuga pueda.

Personalización en una línea

Supongamos que desea establecer las características de su tortuga a lo siguiente: el color

  • Pen: púrpura color de relleno
  • : naranja tamaño
  • Pen: 10
  • Pen velocidad: 9

Por lo que acaba de aprender, el código debe ser algo como esto: de

>>> t.pencolor("purple")
>>> t.fillcolor("orange")
>>> t.pensize(10)
>>> t.speed(9)
>>> t.begin_fill()
>>> t.circle(90)
>>> t.end_fill()

Es bastante largo, pero no es tan malo, ¿verdad?

Ahora, imagínese si usted tenía diez tortugas diferentes . Modificación de la totalidad de sus características sería muy tedioso para que hagas! La buena noticia es que usted puede reducir su carga de trabajo mediante la alteración de los parámetros en una sola línea de código, así:

>>> t.pen(pencolor="purple", fillcolor="orange", pensize=10, speed=9)
>>> t.begin_fill()
>>> t.circle(90)
>>> t.end_fill()

Esto le dará un resultado como este:

Esta sola línea de código cambia la totalidad pluma, sin tener que cambiar cada característica individual. Para obtener más información sobre este comando, consulte la documentación de la biblioteca tortuga Python.

Gran trabajo! Ahora que ha aprendido a personalizar su tortuga y la pantalla, echar un vistazo a algunos otros comandos importantes que son necesarios mientras se dibuja con la biblioteca tortuga Python.

Recogiendo la pluma de arriba hacia abajo

A veces, es posible que desee mover su tortuga a otro punto de la pantalla sin dibujar cualquier cosa en la propia pantalla. Para ello, se utiliza .penup (). Entonces, cuando se quiere volver a dibujar, se utiliza .pendown (). Darle un tiro usando el código que ha utilizado anteriormente para dibujar un cuadrado. Intente introducir el siguiente código:

>>> t.fd(100)
>>> t.rt(90)
>>> t.penup()
>>> t.fd(100)
>>> t.rt(90)
>>> t.pendown()
>>> t.fd(100)
>>> t.rt(90)
>>> t.penup()
>>> t.fd(100)
>>> t.pendown()

Cuando se ejecuta este código, la salida tendrá el siguiente aspecto:

Aquí, hemos obtenido dos líneas paralelas en lugar de un cuadrado mediante la adición de algunos comandos adicionales entre el programa original .

deshacer los cambios

No importa qué tan cuidadoso sea, siempre hay una posibilidad de cometer un error. No se preocupe, sin embargo! La biblioteca tortuga Python le da la opción de deshacer lo que has hecho. Si desea deshacer la última cosa que hizo, a continuación, escriba en la siguiente:

>>> t.undo()

Esto deshace el último comando que se ejecutó. Si desea deshacer los últimos tres comandos, a continuación, tendría que escribir t.undo () tres veces.

borrar la pantalla

En este momento, es probable que tenga muchas cosas en la pantalla desde que ha comenzado este tutorial. Para hacer espacio para más, sólo tiene que escribir el siguiente comando:

>>> t.clear()

Esto va a limpiar su pantalla para que pueda continuar el dibujo. Tenga en cuenta aquí que las variables no va a cambiar, y la tortuga permanecerá en la misma posición. Si usted tiene otras tortugas en su pantalla que no sea la tortuga original, a continuación, sus dibujos no se borrarán a menos que usted los llama a cabo específicamente en el código.

Restablecimiento del Medio Ambiente

También tiene la opción de comenzar con una pizarra limpia con un reset . La pantalla de ser anulado, y la configuración de la tortuga todo será restaurado a sus parámetros por defecto. Todo lo que necesita hacer es escribir el siguiente comando:

>>> t.reset()

Esto borra la pantalla y toma la parte posterior de la tortuga a su posición inicial. Sus ajustes por defecto, como el tamaño de la tortuga, forma, color y otras características, también serán restauradas.

Ahora que ha aprendido los fundamentos de la programación con la biblioteca tortuga Python, se le echa un vistazo a algunos de bonificación características que es posible que desee utilizar durante la programación.

Dejando un sello

Usted tiene la opción de dejar un sello de su tortuga en la pantalla, que no es sino una impresión de la tortuga es. Pruebe a escribir en este código para ver cómo funciona:

>>> t.stamp()
8
>>> t.fd(100)
>>> t.stamp()
9
>>> t.fd(100)

Su salida se vería así:

Los números que aparecen son la ubicación de la tortuga o el sello ID . Ahora bien, si desea eliminar un sello particular, entonces sólo tiene que utilizar la siguiente:

>>> t.clearstamp(8)

Esto borrará el que tiene el sello de identificación de 8.

Clonación su tortuga

A veces, puede que tenga que tener más de una tortuga en su pantalla. Vas a ver un ejemplo de esto más adelante en el proyecto final. Por ahora, puede obtener otra tortuga por clonación su tortuga actual en su entorno. Intente ejecutar este código para crear un clon de tortuga, c, y luego mover tanto las tortugas en la pantalla:

>>> c = t.clone()
>>> t.color("magenta")
>>> c.color("red")
>>> t.circle(100)
>>> c.circle(60)

La salida tendrá el siguiente aspecto:

impresionante!

Ahora que tiene una idea de algunos comandos importantes de la biblioteca de tortuga Python, ya está listo para pasar a unos cuantos conceptos que usted necesita entender. Estos conceptos son muy necesarias cuando se trata de programar en cualquier lenguaje.

mediante bucles e instrucciones condicionales

Al entrar en la programación de alto nivel, se encontrará usando bucles e instrucciones condicionales muy a menudo. Es por eso que, en esta sección, se le va a través de un par de programas de tortugas que hacen uso de este tipo de comandos. Esto le dará un enfoque práctico a la hora de entender estos conceptos. Antes de comenzar, sin embargo, aquí hay tres definiciones que deben tenerse en cuenta:

Ahora, vamos a seguir adelante y explorar estos comandos!

para Loops

¿Recuerdas el programa que utilizó para crear un cuadrado? Había que repetir la misma línea de código en cuatro ocasiones, como esta:

>>> t.fd(100)
>>> t.rt(90)
>>> t.fd(100)
>>> t.rt(90)
>>> t.fd(100)
>>> t.rt(90)
>>> t.fd(100)
>>> t.rt(90)

Una manera mucho más corto de hacerlo es con la ayuda de un bucle. Pruebe a ejecutar este código:

>>> for i in range(4):
... t.fd(100)
... t.rt(90)

Aquí, el i es como un contador que parte de cero y sigue aumentando en 1. Cuando se dicen en el rango (4), que está diciendo el programa que el valor de esta I Should sea ​​inferior a 4. se dará por terminado el programa antes de que yo llegue a 4.

he aquí un desglose de cómo funciona el programa:

la tortuga se salga del bucle. Para comprobar el valor de i, tipo I y luego pulse la tecla Intro. Usted obtendrá el valor de i igual a 3:

>>> i
3

Tenga en cuenta que el espacio en blanco que viene antes de la línea 2 y la línea 3 en el programa es la sangría . Esto indica que las 3 líneas forman un solo bloque de código. Para obtener más información sobre los bucles en Python, echa un vistazo a Python “para” Loops (iteración definido).

mientras Loops

El bucle while se utiliza para realizar una determinada tarea, mientras que una condición todavía está satisfecho. Si la condición ya no se cumple, entonces su código dará por terminado el proceso. Se puede utilizar un bucle while para crear una serie de círculos escribiendo este código:

>>> n=10
>>> while n <= 40: ... t.circle(n) ... n = n+10

Cuando se ejecuta este código, verá los círculos que aparecen uno tras otro, y cada nuevo círculo será más grande que la anterior :

Aquí, n se utiliza como un contador. Tendrá que especificar en qué medida desea que el valor de n para aumentar en cada bucle. Echar un vistazo a este mini recorrido para ver cómo funciona el programa:

Para leer más sobre los bucles while, echa un vistazo a Python “mientras que” Loops (Indefinida iteración). Declaraciones

condicionales

Se utiliza sentencias condicionales para comprobar si una determinada condición es verdadera. Si es así, entonces se ejecuta el comando correspondiente. Pruebe a escribir en este programa: entrada

>>> u = input("Would you like me to draw a shape? Type yes or no: ")
>>> if u == "yes":
... t.circle(50)

() se utiliza para obtener entrada del usuario. A continuación, almacenará la respuesta del usuario en la variable u. A continuación, se comparará el valor de u de la condición establecida y comprobar si el valor de u es "sí". Si es "sí", entonces su programa dibuja un círculo. Si el usuario escribe en cualquier otra cosa, entonces el programa no hará nada.

Nota: El operador comparación == indica una comparación . Se utiliza para comprobar si el valor de algo es igual a otra cosa. El operador de asignación = se utiliza para asignar un valor a algo. Para obtener más información sobre las diferencias entre los dos, echa un vistazo a los operadores y expresiones en Python.

Cuando se agrega una cláusula else a una sentencia if, puede especificar dos resultados en función de si la condición es verdadera o falsa. Veamos esto en un programa:

>>> u = input("Would you like me to draw a shape? Type yes or no: ")
>>> if u == "yes":
... t.circle(50)
>>> else:
... print("Okay")

Aquí, se indica al programa para mostrar una salida particular, incluso cuando el usuario no dice "sí". Se utiliza de impresión () para mostrar algunos caracteres predefinidos en la pantalla.

Tenga en cuenta que el usuario no tiene que escribir "no". Se puede escribir cualquier otra cosa, en cuyo caso, el resultado siempre será "Está bien", porque no se está diciendo de forma explícita el programa que el usuario necesita para escribir "no". No hay que preocuparse, sin embargo, ya que puede ser fijo. Se puede añadir una cláusula de elif para proporcionar el programa con varias condiciones y sus respectivas salidas, como se puede observar aquí:

>>> u = input("Would you like me to draw a shape? Type yes or no: ")
>>> if u == "yes":
... t.circle(50)
>>> elif u == "no":
... print("Okay")
>>> else:
... print("Invalid Reply")

Como se puede ver, este programa cuenta ahora con más de un resultado, dependiendo de la entrada que recibe. Así es como funciona este código:

  • Si el tipo de "sí", entonces el código procesa la entrada y dibuja un círculo, según sus instrucciones.
  • Si el tipo de "NO", entonces el código imprime fuera "bien" y el programa se termina.
  • Si escribe en cualquier otra cosa, como "Hola" o "sandwich", entonces el código imprime "no válida Responder" y el programa se termina.

Tenga en cuenta que este programa es entre mayúsculas y minúsculas, así que cuando usted está tratando de salir, asegúrese de poner las cadenas en mayúsculas o minúsculas en consecuencia.

Para obtener más información sobre las sentencias condicionales, echa un vistazo a Sentencias condicionales en Python.

Proyecto Fin de Carrera

: La raza de la tortuga Python

Hasta ahora, usted ha aprendido cómo personalizar el entorno de tortuga, programar su tortuga para desplazarse por la pantalla, y los bucles de uso e instrucciones condicionales para mejorar su código. Ahora es el momento para la parte más importante de su viaje de programación. En esta sección, se le implementa todo lo que ha aprendido en un solo programa mediante la creación de un juego divertido que se puede jugar con sus amigos.

Antes de empezar, esto es lo que necesita saber sobre el juego:

El Objetivo: El jugador cuyo tortuga llega a su casa primero, gana el juego.

Cómo Jugar:

  • Cada jugador tira un dado para obtener un número.
  • Entonces, el jugador mueve su tortuga esa cantidad de pasos.
  • Los jugadores se alternan turnos hasta que uno de ellos gana.

la estructura:

  • Cada jugador tenía una tortuga indicado por un color diferente. Puede tener más de dos jugadores, pero por el bien de este tutorial, que va a crear un juego de dos jugadores.
  • Cada tortuga tiene una posición inicial que se debe alcanzar.
  • Cada jugador usa un dado para elegir un valor al azar para su turno. In your program, the die is represented by a list of numbers from 1 to 6.

Now that you’ve understood the logic of the game, you can go ahead and begin creating it! First, you’ll need to set up the environment.

Setting Up the Game Environment

Start by importing the Python turtle library. After this, import the built-in random library, which you’ll use randomly select an item from a list:

>>> import turtle
>>> import random

Once these libraries are successfully called into your environment, you can proceed with the rest of your program.

Setting Up the Turtles and Homes

You now have to create the two turtles that will represent the players. Each turtle will be a different color, corresponding to the different players. Here, player one is green and player two is blue :

>>> player_one = turtle.Turtle()
>>> player_one.color("green")
>>> player_one.shape("turtle")
>>> player_one.penup()
>>> player_one.goto(-200,100)
>>> player_two = player_one.clone()
>>> player_two.color("blue")
>>> player_two.penup()
>>> player_two.goto(-200,-100)

One you’ve created the turtles, you place them at their starting positions and make sure that these positions are aligned. Note that you created player two’s turtle by cloning player one’s turtle, changing its color, and placing it at a different starting point.

You now need to set up homes for the turtles. These homes will act as the finishing points for each turtle. Each of the turtles’ homes will be represented by a circle. Here, you need to make sure that both homes are equidistant from the starting point:

>>> player_one.goto(300,60)
>>> player_one.pendown()
>>> player_one.circle(40)
>>> player_one.penup()
>>> player_one.goto(-200,100)
>>> player_two.goto(300,-140)
>>> player_two.pendown()
>>> player_two.circle(40)
>>> player_two.penup()
>>> player_two.goto(-200,-100)

After drawing the respective homes, you send the turtles back to their starting positions:

Awesome! The visual aspects of your game are complete. You can now create the die that you’ll be using to play the game.

Creating the Die

You can create a virtual die for your game with a list , which is an ordered sequence of items. In real life, you might prepare grocery list s and to-do list s to help you stay organized. In Python, list s work in a similar way.

In this case, you’ll be using a list to create your die. First, you define your list of numbers in ascending order from 1 to 6. You can define a list by giving it a name and then enclosing its items within square brackets, like this:

>>> die = [1,2,3,4,5,6]

This list has now become your die. To roll the dice, all you have to do is program your system to randomly select a number from it. The number that is selected will be considered as the output of the die.

Developing the Game

It’s time to develop the code for the rest of the game. You’ll be using loops and conditional statements here, so you need to be careful with the indentations and spaces. To start, take a look at the steps your program will need to take to run the game:

The program keeps repeating this process, and stops once one of the turtles reaches the goal. Here’s how the code looks:

1 >>> for i in range(20):
2 ... if player_one.pos() >= (300,100):
3 ... print("Player One Wins!")
4 ... break
5 ... elif player_two.pos() >= (300,-100):
6 ... print("Player Two Wins!")
7 ... break
8 ... else:
9 ... player_one_turn = input("Press 'Enter' to roll the die ")
10 ... die_outcome = random.choice(die)
11 ... print("The result of the die roll is: ")
12 ... print(die_outcome)
13 ... print("The number of steps will be: ")
14 ... print(20*die_outcome)
15 ... player_one.fd(20*die_outcome)
16 ... player_two_turn = input("Press 'Enter' to roll the die ")
17 ... d = random.choice(die)
18 ... print("The result of the die roll is: ")
19 ... print(die_outcome)
20 ... print("The number of steps will be: ")
21 ... print(20*die_outcome)
22 ... player_two.fd(20*die_outcome)

Your final output will look a little something like this:

In summary, this is what the code is doing:

Line 1 sets up a for loop with a range from 1 to 20.

Lines 2 through 7 check if either player has reached their goal. If one of them has, then the program prints out the corresponding statement and breaks the loop.

Line 8 moves the program on to the next set of steps if neither player has won.

Line 9 prints out a statement asking player one to press the Enter key to roll the die.

Line 10 takes a random value from the list die and stores it in dice_outcome.

Line 11 prints a statement prior to displaying the outcome of the dice roll.

Line 12 prints the dice outcome.

Line 14 multiplies this value by 20 to reduce the overall number of steps required to complete the game.

Line 15 moves player one’s turtle forward by this number of steps.

Lines 16 to 22 repeat these steps for player two.

The entire for loop is repeated until one of the player’s turtles reaches the final position.

Note: In Python, you use the asterisk (*) to indicate multiplication. This is known as an arithmetic operator . You can also use the plus sign (+) for addition, the minus sign (-) for subtraction, and a slash (/) for division. To learn more about arithmetic operator s, check out the Arithmetic Operators section of Operators and Expressions in Python.

Remember, you can customize the game however you want, so go ahead and play around with it! You can add more turtles, change the colors, change the speed, or even create some obstacles to challenge your players. It’s all up to you as the developer of the game!

Conclusion

In this tutorial, you’ve learned how to program with the Python turtle library and grasped some very important programming concepts. You know how to deal with variable initialization, loops, conditional statements, indentations, lists, and operators. This is a great start for you, especially if you’re new to the Python programming language!

Now you can:

  • Set up the Python turtle library
  • Move your turtle around
  • Customize your turtle and its environment
  • Program your turtle
  • Use basic programming concepts
  • Create a game that you can play with friends

Now you’re ready to venture into some higher-level Python programming. To progress further in your Python journey, check out Introduction to Python and 11 Beginner Tips for Learning Python Programming. Just remember to work hard and keep practicing, and you’ll find that you’re a Python expert in no time!

Categorías
Python

Instalación de Python en Windows, MacOS y Linux

 

Tabla de Contenidos

  • Diferenciando SciPy el ecosistema y SciPy la Biblioteca
  • Comprender SciPy Módulos
  • Instalación SciPy en su ComputerAnacondaPip
  • Anaconda
  • Pip
  • Uso del módulo Cluster en SciPy
  • Uso del módulo Optimizar en SciPyMinimizing una función con un VariableMinimizing una función con muchas variables
  • minimización de una función con una variable
  • minimización de una función con muchas variables
  • Conclusión
  • Anaconda
  • Pip
  • minimización de una función con una variable
  • minimización de una función con muchas variables

Cuando usted quiere hacer el trabajo científico en Python, la primera biblioteca se puede recurrir es SciPy . Como se verá en este tutorial, SciPy no es sólo una biblioteca, pero en su conjunto ecosistema de bibliotecas que trabajan en conjunto para ayudar a lograr complicado tareas científicas forma rápida y fiable.

En este tutorial, aprenderá a:

  • buscar información sobre todas las cosas que puede hacer con SciPy
  • Instalar SciPy en su ordenador
  • Uso SciPy a agruparse un conjunto de datos de varias variables
  • Uso SciPy para encontrar el óptimo de una función de buceo

Vamos en el maravilloso mundo de SciPy! Bono

gratuito: Haga clic aquí para obtener acceso a una hoja de trucos Conda con ejemplos de uso práctico para la gestión de su medio ambiente y los paquetes de Python.

Diferenciando SciPy el ecosistema y SciPy la Biblioteca

Cuando se desea utilizar Python para tareas de computación científica, hay varias bibliotecas que es probable que se aconseja el uso, incluyendo:

  • NumPy
  • SciPy
  • Matplotlib
  • IPython
  • sympy
  • pandas

Colectivamente, estas bibliotecas constituyen el ecosistema SciPy y están diseñados para trabajar juntos. Muchos de ellos se basan directamente en las matrices NumPy hacer cálculos. En este tutorial se espera que usted tiene cierta familiaridad con la creación de matrices NumPy y operar en ellos.

Nota: Si necesita una cartilla rápida o de actualización sobre NumPy, a continuación, puede consultar los siguientes tutoriales:

  • Look Ma, pero no los fines de Bucles: Programación matriz con NumPy
  • NumPy arange (): cómo usar np.arange ()
  • MATLAB vs Python: una visión general de la matriz de operaciones básicas

En este tutorial, aprenderá acerca de la SciPy biblioteca , uno de los componentes básicos del ecosistema SciPy. El SciPy biblioteca es la biblioteca fundamental para la computación científica en Python. Proporciona muchas interfaces eficientes y fáciles de usar para tareas tales como la integración numérica, optimización, procesamiento de señales, álgebra lineal, y más. La comprensión de biblioteca SciPy Módulos

El SciPy

se compone de un número de módulos de que separan la biblioteca en unidades funcionales distintas. Si usted quiere aprender acerca de los diferentes módulos que SciPy incluye, a continuación, puede ejecutar la ayuda () en scipy, como se muestra a continuación:

>>> import scipy
>>> help(scipy)

Esto produce alguna salida ayuda para toda la biblioteca SciPy, una parte del cual se muestra a continuación : código

Subpackages
-----------

Using any of these subpackages requires an explicit import. For example,
``import scipy.cluster``.

::

cluster --- Vector Quantization / Kmeans
fft --- Discrete Fourier transforms
fftpack --- Legacy discrete Fourier transforms
integrate --- Integration routines
...

Este bloque muestra la porción de subpaquetes de la salida de la ayuda, que es una lista de todos los módulos disponibles dentro SciPy que se puede utilizar para los cálculos.

Tenga en cuenta el texto en la parte superior de la sección que establece: «El uso de cualquiera de estos sub-paquetes requiere una importación explícita.» Cuando se desea utilizar la funcionalidad de un módulo en SciPy, debe importar el módulo que desea utilizar específicamente . Vas a ver algunos ejemplos de esto un poco más adelante en el tutorial, y las directrices para la importación de bibliotecas de SciPy se muestran en la documentación SciPy.

Una vez que decida qué módulo que desea utilizar, puede revisar la referencia de la API SciPy, que contiene todos los detalles acerca de cada módulo en SciPy. Si usted está buscando algo con un poco más de la exposición, a continuación, las notas de la conferencia SciPy son un gran recurso para ir a fondo de muchos de los módulos SciPy.

Más adelante en este tutorial, usted aprenderá acerca de cluster y Optimizar, que son dos de los módulos de la biblioteca SciPy. Pero en primer lugar, tendrá que instalar SciPy en su ordenador.

Instalación SciPy en el equipo

Al igual que con la mayoría de los paquetes de Python, hay dos formas principales para instalar en su ordenador SciPy:

Aquí, usted aprenderá cómo utilizar estos dos enfoques para instalar la biblioteca. única dependencia directa de SciPy es el paquete NumPy. Cualquiera de los métodos de instalación instalará automáticamente NumPy además de SciPy, si es necesario.

Anaconda

Anaconda es una popular distribución de Python, principalmente debido a que incluye versiones de los paquetes de la mayoría de divulgación científica Python pre-construidos para Windows, MacOS y Linux. Si usted no tiene Python instalado en el equipo en absoluto, sin embargo, a continuación, Anaconda es una gran opción para empezar a utilizar. Anaconda viene pre-instalado con SciPy y sus dependencias requeridas, así que una vez que haya instalado anaconda, que no es necesario hacer nada más!

Puede descargar e instalar Anaconda desde su página de descargas. Asegúrese de descargar la versión más reciente de Python 3. Una vez que tenga el instalador en su ordenador, se puede seguir el procedimiento de configuración por defecto para una aplicación, dependiendo de la plataforma.

Nota: Asegúrese de instalar Anaconda en un directorio que no requiere permisos de administrador modificar. Esta es la configuración predeterminada en el instalador.

Si ya tiene instalado Anaconda, pero desea instalar o actualizar SciPy, entonces usted puede hacer eso, también. Abrir una aplicación de terminal en MacOS o Linux, o la Anaconda Prompt en Windows y escriba una de las siguientes líneas de código:

$ conda install scipy
$ conda update scipy

Se debe utilizar la primera línea si necesita instalar SciPy o la segunda línea si lo que desea actualizar SciPy. Para asegurarse de SciPy está instalado, Python ejecuta en su terminal y tratar de importar SciPy:

>>> import scipy
>>> print(scipy.__file__)
/.../lib/python3.7/site-packages/scipy/__init__.py

En este código, que haya importado scipy e impreso la ubicación del archivo desde donde se carga scipy. El ejemplo anterior es para MacOS. El ordenador mostrará probablemente un lugar diferente. Ahora usted tiene SciPy instalado en su computadora lista para su uso. Puede pasar directamente a la siguiente sección para empezar a utilizar SciPy!

Pip

Si ya tiene una versión de Python instalado que no es Anaconda, o que no quieren utilizar Anaconda, entonces usted va a utilizar para instalar pip SciPy. Para aprender más acerca de lo que es pip, echa un vistazo a ¿Qué es la pipa? Una guía para Nueva Pythonistas.

Nota: pip instala los paquetes utilizando un formato llamado ruedas . En el formato de la rueda, el código se compila antes de que sea enviada a su ordenador. Esto es casi el mismo enfoque que toma Anaconda, aunque los archivos de formato de las ruedas son ligeramente diferentes que el formato Anaconda, y los dos no son intercambiables.

Para instalar SciPy usando pip, abra la aplicación de terminal y escriba la siguiente línea de código:

$ python -m pip install -U scipy

El código instalará SciPy si no está ya instalado, o actualizar SciPy si está instalado. Para asegurarse de SciPy está instalado, Python ejecuta en su terminal y tratar de importar SciPy:

>>> import scipy
>>> print(scipy.__file__)
/.../lib/python3.7/site-packages/scipy/__init__.py

En este código, que haya importado scipy e impreso la ubicación del archivo desde donde se carga scipy. El ejemplo anterior es para MacOS utilizando pyenv. El ordenador mostrará probablemente un lugar diferente. Ahora usted tiene SciPy instalado en su ordenador. Vamos a ver cómo se puede utilizar SciPy para resolver un par de problemas que pueden surgir!

Uso del módulo Cluster en SciPy

La agrupación es una técnica popular para categorizar los datos mediante la asociación en grupos. La biblioteca SciPy incluye una implementación de la k-medias algoritmo de agrupamiento así como varios algoritmos de agrupación jerárquica. En este ejemplo, podrás utilizar las k-medias algoritmo en scipy.cluster.vq, donde VQ representa cuantificación vectorial .

primer lugar, usted debe echar un vistazo a la base de datos que va a utilizar para este ejemplo. El conjunto de datos consta de 4827 reales y 747 de texto de spam (o SMS). El conjunto de datos en bruto se puede encontrar en la UCI Machine Learning repositorio o la página web de los autores.

Nota: Los datos fueron recogidos por Tiago A. Almeida y José María Gómez Hidalgo y publicados en un artículo titulado “Contribución al estudio de los SMS de filtrado de spam: Nueva colección y Resultados” en el Actas del Simposio ACM 2011 Documento de Ingeniería (DOCENG’11) sede en Mountain View, California, EE.UU. en 2011.

en el conjunto de datos, cada mensaje tiene una de dos etiquetas:

jamón para los mensajes legítimos

correo no deseado para correo no deseado mensajes

El mensaje de texto completo está asociado con cada etiqueta. Al escanear a través de los datos, se puede notar que los mensajes de spam tienden a tener una gran cantidad de dígitos numéricos en ellos. A menudo incluyen un número de teléfono o el premio ganancias. Vamos a predecir si un mensaje es spam basado en el número de dígitos en el mensaje. Para ello, se le cúmulo los datos en tres grupos en función del número de dígitos que aparecen en el mensaje:

No spam: Los mensajes con el menor número de dígitos no se predicen para ser spam.

Desconocido: mensajes con un número intermedio de dígitos son desconocidos y necesidad de ser procesado por algoritmos más avanzados.

Spam: Los mensajes con el mayor número de dígitos se prevé que sea correo no deseado. get de

Let comenzó con la agrupación de los mensajes de texto. En primer lugar, debe importar las bibliotecas que utilizará en este ejemplo:

1 from pathlib import Path
2 import numpy as np
3 from scipy.cluster.vq import whiten, kmeans, vq

Se puede ver que va a importar tres funciones de scipy.cluster.vq. Cada una de estas funciones acepta un array NumPy como entrada. Estas matrices deben tener el cuenta del conjunto de datos en las columnas y las observaciones en las filas.

Una característica es una variable de interés, mientras se crea una observación cada vez que se graba cada función. En este ejemplo, hay 5.574 observaciones, o mensajes individuales, en el conjunto de datos. Además, se verá que hay dos características:

A continuación, debe cargar el archivo de datos de la base de la UCI. Los datos se presenta como un archivo de texto, donde la clase del mensaje se separa del mensaje por un carácter de tabulación, y cada mensaje es en su propia línea. Debe leer los datos en una lista utilizando pathlib.Path:

4 data = Path("SMSSpamCollection").read_text()
5 data = data.strip()
6 data = data.split("\n")

En este código, se utiliza pathlib.Path.read_text () para leer el archivo en una cadena. A continuación, utiliza .strip () para eliminar cualquier espacio final y dividir la cadena en una lista con .split ().

A continuación, puede empezar a analizar los datos. Es necesario para contar el número de dígitos que aparecen en cada mensaje de texto. Python incluye collections.Counter en la biblioteca estándar para recoger el recuento de objetos en un diccionario-como la estructura. Sin embargo, ya que todas las funciones en scipy.cluster.vq esperan matrices NumPy como entrada, no se puede utilizar collections.Counter para este ejemplo. En su lugar, se utiliza una matriz NumPy e implementar el recuento manual.

Una vez más, usted está interesado en el número de dígitos en un mensaje SMS dado, y el número de mensajes SMS tienen ese número de dígitos. En primer lugar, se debe crear una matriz NumPy que se asocia el número de dígitos en un mensaje dado con el resultado del mensaje, si era el jamón o el correo no deseado:

7 digit_counts = np.empty((len(data), 2), dtype=int)

En este código, que está creando una matriz NumPy vacío, digit_counts, que tiene dos columnas y 5.574 filas. El número de filas es igual al número de mensajes en el conjunto de datos. Usted va a utilizar digit_counts asociar el número de dígitos en el mensaje con si o no el mensaje era spam.

Debe crear la matriz antes de entrar en el bucle, por lo que no tiene que asignar la nueva memoria como sus expande la matriz. Esto mejora la eficiencia de su código. A continuación, se debe procesar los datos para registrar el número de dígitos y el estado del mensaje:

8 for i, line in enumerate(data):
9 case, message = line.split("\t")
10 num_digits = sum(c.isdigit() for c in message)
11 digit_counts[i, 0] = 0 if case == "ham" else 1
12 digit_counts[i, 1] = num_digits

He aquí un desglose de línea por línea de cómo funciona este código:

  • Línea 8: Bucle sobre los datos. Se utiliza enumerate () para poner el valor de la lista en línea y crear un índice i para esta lista. Para obtener más información sobre enumerate (), echa un vistazo uso de enumeración () para mantener un índice de carrera.
  • Línea 9: Dividir la línea en el carácter de tabulación para crear el caso y el mensaje. caso es una cadena que dice si el mensaje es el jamón o el correo no deseado, mientras que el mensaje es una cadena con el texto del mensaje.
  • Línea 10: Calcular el número de dígitos en el mensaje mediante el uso de la suma () de una comprensión. En la comprensión, se comprueba cada carácter en el mensaje utilizando isdigit (), que devuelve verdadero si el elemento es un numeral y False en caso contrario. sum () y luego trata a cada resultado como una verdadera 1 y cada Falso como un 0. Por lo tanto, el resultado de la suma () en esta comprensión es el número de caracteres para los que isdigit () retorna true.
  • Línea 11: Asignar valores en digit_counts. Se asigna la primera columna de la fila i sea 0 si el mensaje era legítima (jamón) o 1 si el mensaje era spam.
  • Línea 12: Asignar valores en digit_counts. Se asigna la segunda columna de la fila i ser el número de dígitos en el mensaje.

Línea 8: bucle sobre los datos. Se utiliza enumerate () para poner el valor de la lista en línea y crear un índice i para esta lista. Para obtener más información sobre enumerate (), echa un vistazo uso de enumeración () para mantener un índice de carrera.

Línea 9: dividir la línea en el carácter de tabulación para crear el caso y el mensaje. caso es una cadena que dice si el mensaje es el jamón o el correo no deseado, mientras que el mensaje es una cadena con el texto del mensaje.

Línea 10: Calcular el número de dígitos en el mensaje mediante la suma () de una comprensión. En la comprensión, se comprueba cada carácter en el mensaje utilizando isdigit (), que devuelve verdadero si el elemento es un numeral y False en caso contrario. sum () y luego trata a cada resultado como una verdadera 1 y cada Falso como un 0. Por lo tanto, el resultado de la suma () en esta comprensión es el número de caracteres para los que isdigit () retorna true.

Línea 11: Los valores de Asignar en digit_counts. Se asigna la primera columna de la fila i sea 0 si el mensaje era legítima (jamón) o 1 si el mensaje era spam.

Línea 12: Los valores de Asignar en digit_counts. Se asigna la segunda columna de la fila i ser el número de dígitos en el mensaje.

Ahora usted tiene una matriz NumPy que contiene el número de dígitos en cada mensaje. Sin embargo, desea aplicar el algoritmo de agrupamiento a una matriz que tiene el número de mensajes con un cierto número de dígitos. En otras palabras, es necesario crear una matriz en donde la primera columna tiene el número de dígitos en un mensaje, y la segunda columna es el número de mensajes que tienen ese número de dígitos. Mira el código de abajo:

13 unique_counts = np.unique(digit_counts[:, 1], return_counts=True)

np.unique () toma una matriz como primer argumento y regresa otra matriz con los elementos únicos de la discusión. También tiene varios argumentos opcionales. En este caso, se utiliza return_counts = true para instruir np.unique () para devolver también una matriz con el número de veces que cada elemento único está presente en la matriz de entrada. Estas dos salidas se devuelven como una tupla que se almacenan en unique_counts.

Después, usted necesita para transformar unique_counts en una forma que es adecuada para la agrupación:

14 unique_counts = np.transpose(np.vstack(unique_counts))

se combinan las dos salidas de 1xN np.unique () en una matriz usando 2xN np.vstack (), y luego trasladarlas a un NX2 formación. Este formato es lo que vamos a usar en las funciones de agrupamiento. Cada fila de unique_counts ahora tiene dos elementos:

Un subconjunto de la salida de estas dos operaciones se muestra a continuación:

[[ 0 4110]
[ 1 486]
[ 2 160]
...
[ 40 4]
[ 41 2]
[ 47 1]]

En el conjunto de datos, hay 4110 mensajes que no tienen dígitos, 486 que tienen 1 dígitos, y así sucesivamente. Ahora, usted debe aplicar los kmeans algoritmo de agrupamiento a esta matriz:

15 whitened_counts = whiten(unique_counts)
16 codebook, _ = kmeans(whitened_counts, 3)

Usted uso blanquear () para normalizar cada característica de tener variación de la unidad, lo que mejora los resultados de kmeans (). Entonces, kmeans () toma los datos de blanqueado y el número de grupos para crear como argumentos. En este ejemplo, desea crear 3 grupos, por definitivamente jamón , definitivamente el spam y desconocida . kmeans () devuelve dos valores: array

Una con tres filas y dos columnas que representan los centroides de cada grupo: Los kmeans () algoritmo calcula la ubicación óptima del centroide de cada grupo, reduciendo al mínimo la distancia desde las observaciones a cada centroide. Esta matriz se asigna a libro de códigos.

La distancia euclidiana media de las observaciones a los centroides: no será necesario que el valor para el resto de este ejemplo, por lo que se puede asignar a _.

A continuación, debe determinar qué agruparse cada observación pertenece a mediante el uso de vq ():

17 codes, _ = vq(unique_counts, codebook)

VQ () asigna los códigos del libro de códigos a cada observación. Se devuelve dos valores:

El primer valor es una matriz de la misma longitud que unique_counts, donde el valor de cada elemento es un entero que representa la cual se agrupan que la observación se asigna a. Desde que utilizó tres grupos en este ejemplo, cada observación se asigna a clúster 0, 1, o 2.

El segundo valor es una matriz de la distancia euclidiana entre cada observación y su centroide.

Ahora que tiene los datos agrupados, se debe utilizar para hacer predicciones acerca de los mensajes SMS. Puede inspeccionar las cuentas para determinar en cuántos dígitos del algoritmo de agrupamiento dibujó la línea entre definitivamente jamón y desconocida, y entre desconocidos y sin duda spam:

18 print(unique_counts[codes == 0][-1])
19 print(unique_counts[codes == 1][-1])
20 print(unique_counts[codes == 2][-1])

En este código, cada línea es cada vez las filas de unique_counts donde asignado VQ () diferentes valores de los códigos, ya sea 0, 1 ó 2. Dado que la operación devuelve una matriz, debe obtener la última fila de la matriz para determinar el mayor número de dígitos asignados a cada grupo. La salida se muestra a continuación:

definitely spam [47 1]
definitely ham [ 0 4110]
unknown [20 18]

En esta salida, se ve que el definitivamente jamón mensajes son los mensajes con cero dígitos en el mensaje, los desconocidos mensajes son todo entre 1 y 20 dígitos, y definitivamente el spam los mensajes son todo, desde 21 hasta 47 dígitos, que es el número máximo de dígitos en el conjunto de datos.

Ahora, usted debe comprobar la forma precisa sus predicciones son en este conjunto de datos. En primer lugar, crear algunas máscaras para digit_counts para que pueda agarrar fácilmente el estado de jamón o spam de los mensajes:

21 digits = digit_counts[:, 1]
22 predicted_hams = digits == 0
23 predicted_spams = digits > 20
24 predicted_unknowns = np.logical_and(digits > 0, digits <= 20)

En este código, que está creando los predicted_hams máscara, donde no hay dígitos en un mensaje. A continuación, crear los predicted_spams enmascaran para todos los mensajes con más de 20 dígitos. Por último, los mensajes en el centro son predicted_unknowns.

A continuación, se aplican estas máscaras con los recuentos reales dígitos para recuperar las predicciones:

25 spam_cluster = digit_counts[predicted_spams]
26 ham_cluster = digit_counts[predicted_hams]
27 unk_cluster = digit_counts[predicted_unknowns]

Aquí, va a aplicar las máscaras que ha creado en el último bloque de código a la matriz digit_counts. Esto crea tres nuevas matrices con sólo los mensajes que han sido agrupadas en cada grupo. Por último, se puede ver cuántos de cada tipo de mensaje han caído en cada grupo:

28 print("hams:", np.unique(ham_cluster[:, 0], return_counts=True))
29 print("spams:", np.unique(spam_cluster[:, 0], return_counts=True))
30 print("unknowns:", np.unique(unk_cluster[:, 0], return_counts=True))

Este código imprime los cargos de cada valor único de los racimos. Recuerde que 0 significa que un mensaje ha sido jamón y 1 significa que el mensaje era spam. Los resultados se muestran a continuación:

hams: (array([0, 1]), array([4071, 39]))
spams: (array([0, 1]), array([ 1, 232]))
unknowns: (array([0, 1]), array([755, 476]))

De esta salida, se puede ver que los mensajes de 4110 cayeron en el definitivamente jamón grupo, de los cuales 4071 eran en realidad jamón y sólo 39 eran spam. Por el contrario, de los 233 mensajes que cayeron en la definitivamente el spam grupo , a sólo 1 fue en realidad el jamón y el resto eran spam.

Por supuesto, más de 1200 mensajes cayó en la categoría desconocido, por lo que sería necesario un análisis más avanzado para clasificar los mensajes. Es posible que desee ver en algo así como el procesamiento del lenguaje natural para ayudar a mejorar la precisión de la predicción, y se puede utilizar Python y Keras para ayudar.

Uso del módulo Optimizar en SciPy

Cuando necesite optimizar la los parámetros de entrada para una función, scipy. optimizar contiene una serie de métodos útiles para la optimización de diferentes tipos de funciones: minimize_scalar

  • () y minimizar () para minimizar una función de una variable y muchas variables, respectivamente
  • curve_fit () para adaptarse a una función a un conjunto de los datos
  • root_scalar () y raíz () para encontrar los ceros de una función de una variable y de muchas variables, respectivamente
  • linprog () para minimizar una función objetivo lineal con la desigualdad y la igualdad de restricciones lineales

En la práctica, todos de estas funciones están realizando optimización de un tipo u otro. En esta sección, usted aprenderá acerca de las dos funciones de minimización, minimize_scalar () y reducir al mínimo ().

minimizar una función con una variable

una función matemática que acepta un número y los resultados en una salida se llama una función escalar . Por lo general es contrastada con funciones multivariantes que aceptan varios números y también dan lugar a varios números de salida. Usted verá un ejemplo de optimización de las funciones multivariantes en la siguiente sección.

Para esta sección, su función escalar será un cuártica polinomio, y su objetivo es encontrar el valor mínimo de la función. La función es y = 3x⁴ - 2x + 1. La función se representa en la siguiente imagen para una serie de x de 0 a 1:

En la figura, se puede ver que hay un valor mínimo de esta función en aproximadamente x = 0,55. Puede utilizar minimize_scalar () para determinar las exactas x y coordenadas xey del mínimo. En primer lugar, minimize_scalar importación () desde scipy.optimize. Entonces, es necesario definir la función objetivo a minimizar:

1 from scipy.optimize import minimize_scalar
2
3 def objective_function(x):
4 return 3 * x ** 4 - 2 * x + 1

objective_function () toma la entrada x y aplica las operaciones matemáticas necesarias para que, a continuación, devuelve el resultado. En la definición de la función, se puede utilizar cualquier función matemática deseada. El único límite es que la función debe devolver un solo número al final.

A continuación, el uso minimize_scalar () para encontrar el valor mínimo de esta función.

5 res = minimize_scalar(objective_function)

La salida del minimize_scalar () es una instancia de OptimizeResult: minimize_scalar () sólo tiene una entrada, que es el nombre de la definición de la función objetivo requerido. Esta clase reúne a muchos de los detalles relevantes de la carrera del optimizador, incluyendo si o no la optimización se ha realizado correctamente y, si tiene éxito, ¿cuál fue el resultado final. La salida del minimize_scalar () para esta función se muestra a continuación:

fun: 0.17451818777634331
nfev: 16
nit: 12
success: True
x: 0.5503212087491959

Estos resultados son todos los atributos de OptimizeResult. el éxito es un valor booleano que indica si o no la optimización completada con éxito. Si la optimización se ha realizado correctamente, entonces la diversión es el valor de la función objetivo en el valor óptimo de x. Se puede ver en la salida que, como era de esperar, el valor óptimo para esta función estaba cerca de x = 0,55.

Nota: Como ya sabrán, no cada función tiene un mínimo . Por ejemplo, tratar de ver lo que sucede si su función objetivo es y = x ³. Para minimize_scalar (), funciones objetivo con ningún mínimo a menudo resultan en una OverflowError porque el optimizador finalmente intentó el número que es demasiado grande para ser calculada por el ordenador.

En el lado opuesto de funciones sin mínimo son funciones que tienen varios mínimos . En estos casos, minimize_scalar () no está garantizado para encontrar el mínimo global de la función. Sin embargo, minimize_scalar () tiene un argumento de palabra clave método que se puede especificar para controlar el programa de solución que se utiliza para la optimización. La biblioteca SciPy tiene tres métodos integrados para la minimización de escalar:

Cuando método es bien Brent o dorado, minimize_scalar () toma otro argumento llamado soporte. Esta es una secuencia de dos o tres elementos que proporcionan una aproximación inicial para los límites de la región con el mínimo. Sin embargo, estos solucionadores no garantizan que el mínimo se encontró estará dentro de este rango.

Por otro lado, cuando está delimitada método, minimize_scalar () toma otro argumento denominado límites. Esta es una secuencia de dos elementos que estrictamente ligadas la región de búsqueda para el mínimo. Pruebe el método acotado con la función y = X $ ⁴ $ - x². Esta función se representa en la figura siguiente:

Utilizando el código de ejemplo anterior, se puede redefinir objective_function (), así:

7 def objective_function(x):
8 return x ** 4 - x ** 2

En primer lugar, intente el método de Brent por defecto:

9 res = minimize_scalar(objective_function)

En este código, no lo hiciste t pasar un valor para el método, por lo minimize_scalar () utiliza el método de Brent por defecto. La salida es la siguiente:

fun: -0.24999999999999994
nfev: 15
nit: 11
success: True
x: 0.7071067853059209

Se puede ver que la optimización se ha realizado correctamente. Se encontró que la óptima cerca de x = 0,707 e Y = -1/4. Si usted ha resuelto por el mínimo de la ecuación analíticamente, a continuación, que iba a encontrar el mínimo en x = 1 / √2, que está muy cerca de la respuesta encontrada por la función de minimización. Sin embargo, lo que si se quería encontrar el mínimo simétrica en x = -1 / √2? Puede devolver el mismo resultado, proporcionando el argumento de soporte al método de Brent:

10 res = minimize_scalar(objective_function, bracket=(-1, 0))

En este código, se proporciona la secuencia (-1, 0) en el soporte para iniciar la búsqueda en la región entre -1 y 0. Espera que haya un mínimo en esta región desde la función objetivo es simétrica sobre el eje y. Sin embargo, incluso con el soporte, el método Brent todavía devuelve el mínimo en x = + 1 / √2. Para encontrar el mínimo en x = -1 / √2, puede utilizar el método acotado con límites:

11 res = minimize_scalar(objective_function, method='bounded', bounds=(-1, 0))

En este código, se agrega método y límites como argumentos a minimize_scalar (), y establece límites a ser de -1 a 0. la salida de este método es como sigue:

fun: -0.24999999999998732
message: 'Solution found.'
nfev: 10
status: 0
success: True
x: -0.707106701474177

como se esperaba, el mínimo fue encontrado en x = -1 / √2. Nota la producción adicional de este método, que incluye un atributo de mensaje en res. Este campo se utiliza a menudo para la salida más detallado de algunos de los solucionadores de minimización.

minimizar una función con muchas variables

scipy.optimize también incluye el más general minimizar (). Esta función puede manejar entradas y salidas multivariante y tiene más complicado algoritmos de optimización para ser capaz de manejar esto. Además, minimizar () puede manejar las limitaciones en la solución a su problema. Puede especificar tres tipos de restricciones :

Al utilizar estas limitaciones, se puede limitar la elección específica del método de optimización que es capaz de utilizar, ya que no todos los métodos disponibles apoyan las limitaciones de esta manera.

vamos a probar una demostración sobre el uso de minimizar (). Imagínese que usted es un corredor de bolsa que esté interesado en maximización de los ingresos totales de la venta de un número fijo de sus acciones. Que haya identificado un conjunto particular de los compradores, y para cada comprador, saber el precio que tendrá que pagar y la cantidad de dinero que tienen a mano.

Usted frase puede este problema como un problema de optimización restringida . La función objetivo es que desea maximizar sus ingresos. Sin embargo, reducir al mínimo () Busca el valor mínimo de una función, por lo que necesita para multiplicar su función objetivo por -1 para encontrar los valores de x que producen el mayor número negativo.

Hay una limitación en el problema, que es que la suma del total de acciones adquiridas por los compradores no exceda el número de acciones que tiene a mano. También hay delimita en cada una de las variables de la solución, ya que cada comprador tiene un límite superior de efectivo disponible, y un límite inferior de cero. Solution X-valores negativos significan que usted estaría pagando los compradores!

Pruebe el siguiente código para resolver este problema. En primer lugar, la importación de los módulos que necesite y variables a continuación, establecidos para determinar el número de compradores en el mercado y el número de acciones que desea vender:

1 import numpy as np
2 from scipy.optimize import minimize, LinearConstraint
3
4 n_buyers = 10
5 n_shares = 15

En este código, se importa numpy, minimizar (), y LinearConstraint de scipy. optimizar. A continuación, se establece un mercado de 10 compradores que va a comprar 15 acciones en total de usted.

A continuación, crear matrices para almacenar el precio que cada comprador paga, la cantidad máxima que pueden permitirse el lujo de gastar, y el número máximo de acciones que cada comprador puede permitirse, dado los primeros dos matrices. Para este ejemplo, puede utilizar la generación de números aleatorios en np.random para generar las matrices:

6 np.random.seed(10)
7 prices = np.random.random(n_buyers)
8 money_available = np.random.randint(1, 4, n_buyers)

En este código, establecer la semilla para los generadores de números aleatorios de NumPy. Esta función se asegura de que cada vez que se ejecuta este código, se obtendrá el mismo conjunto de números aleatorios. Es aquí para asegurarse de que su salida es el mismo que el tutorial para la comparación.

En la línea 7, que genera el conjunto de los precios de los compradores pagarán. np.random.random () crea una matriz de números aleatorios en el intervalo semiabierto [0, 1). El número de elementos de la matriz se determina por el valor del argumento, que en este caso es el número de compradores.

En la línea 8, se genera una matriz de enteros en el intervalo semiabierto de [1, 4), de nuevo con el tamaño del número de compradores. Esta matriz representa el total de efectivo cada comprador tiene disponible. Ahora, es necesario calcular el número máximo de acciones que cada comprador puede comprar:

9 n_shares_per_buyer = money_available / prices
10 print(prices, money_available, n_shares_per_buyer, sep="\n")

En la línea 9, se toma la relación de la money_available con los precios para determinar el número máximo de acciones que cada comprador puede adquirir. Por último, se imprime cada una de estas matrices separadas por un salto de línea. La salida se muestra a continuación:

[0.77132064 0.02075195 0.63364823 0.74880388 0.49850701 0.22479665
0.19806286 0.76053071 0.16911084 0.08833981]
[1 1 1 3 1 3 3 2 1 1]
[ 1.29647768 48.18824404 1.57816269 4.00638948 2.00598984 13.34539487
15.14670609 2.62974258 5.91328161 11.3199242 ]

La primera fila es la gama de precios, que son números de punto flotante entre 0 y 1. Esta fila es seguido por el máximo de efectivo disponible en números enteros de 1 a 4. Por último, se ve la número de acciones que cada comprador puede adquirir.

Ahora, es necesario crear las limitaciones y límites para el solucionador. La restricción es que la suma total de las acciones comprada no puede exceder el número total de acciones disponibles. Esta es una limitación en lugar de un límite, ya que implica más de una de las variables de la solución.

To represent this mathematically, you could say that x[0] + x[1] + ... + x[n] = n_shares, where n is the total number of buyers. More succinctly, you could take the dot or inner product of a vector of ones with the solution values, and constrain that to be equal to n_shares. Remember that LinearConstraint takes the dot product of the input array with the solution values and compares it to the lower and upper bound. You can use this to set up the constraint on n_shares:

11 constraint = LinearConstraint(np.ones(n_buyers), lb=n_shares, ub=n_shares)

In this code, you create an array of ones with the length n_buyers and pass it as the first argument to LinearConstraint. Since LinearConstraint takes the dot product of the solution vector with this argument, it’ll result in the sum of the purchased shares.

This result is then constrained to lie between the other two arguments:

Since lb = ub = n_shares, this is an equality constraint because the sum of the values must be equal to both lb and ub. If lb were different from ub, then it would be an in equality constraint .

Next, create the bounds for the solution variable. The bounds limit the number of shares purchased to be 0 on the lower side and n_shares_per_buyer on the upper side. The format that minimize() expects for the bounds is a sequence of tuples of lower and upper bounds:

12 bounds = [(0, n) for n in n_shares_per_buyer]

In this code, you use a comprehension to generate a list of tuples for each buyer. The last step before you run the optimization is to define the objective function. Recall that you’re trying to maximize your income. Equivalently, you want to make the negative of your income as large a negative number as possible.

The income that you generate from each sale is the price that the buyer pays multiplied by the number of shares they’re buying. Mathematically, you could write this as prices[0]*x[0] + prices[1]*x[1] + ... + prices[n]*x[n], where n is again the total number of buyers.

Once again, you can represent this more succinctly with the inner product, or x.dot(prices). This means that your objective function should take the current solution values x and the array of prices as arguments:

13 def objective_function(x, prices):
14 return -x.dot(prices)

In this code, you define objective_function() to take two arguments. Then you take the dot product of x with prices and return the negative of that value. Remember that you have to return the negative because you’re trying to make that number as small as possible, or as close to negative infinity as possible. Finally, you can call minimize():

15 res = minimize(
16 objective_function,
17 x0=10 * np.random.random(n_buyers),
18 args=(prices,),
19 constraints=constraint,
20 bounds=bounds,
21 )

In this code, res is an instance of OptimizeResult, just like with minimize_scalar(). As you’ll see, there are many of the same fields, even though the problem is quite different. In the call to minimize(), you pass five arguments:

objective_function : The first positional argument must be the function that you’re optimizing.

x0 : The next argument is an initial guess for the values of the solution. In this case, you’re just providing a random array of values between 0 and 10, with the length of n_buyers. For some algorithms or some problems, choosing an appropriate initial guess may be important. However, for this example, it doesn’t seem too important.

args : The next argument is a tuple of other arguments that are necessary to be passed into the objective function. minimize() will always pass the current value of the solution x into the objective function, so this argument serves as a place to collect any other input necessary. In this example, you need to pass prices to objective_function(), so that goes here.

constraints : The next argument is a sequence of constraints on the problem. You’re passing the constraint you generated earlier on the number of available shares.

bounds : The last argument is the sequence of bounds on the solution variables that you generated earlier.

Once the solver runs, you should inspect res by printing it:

fun: -8.783020157087366
jac: array([-0.77132058, -0.02075195, -0.63364816, -0.74880385,
-0.4985069, -0.22479665, -0.19806278, -0.76053071, -0.16911077,
-0.08833981])
message: 'Optimization terminated successfully.'
nfev: 204
nit: 17
njev: 17
status: 0
success: True
x: array([1.29647768e+00, 3.94665456e-13, 1.57816269e+00, 4.00638948e+00,
2.00598984e+00, 3.48323773e+00, 5.55111512e-14, 2.62974258e+00,
5.37143977e-14, 1.34606983e-13])

In this output, you can see message and status indicating the final state of the optimization. For this optimizer, a status of 0 means the optimization terminated successfully, which you can also see in the message. Since the optimization was successful, fun shows the value of the objective function at the optimized solution values. You’ll make an income of $8.78 from this sale.

You can see the values of x that optimize the function in res.x. In this case, the result is that you should sell about 1.3 shares to the first buyer, zero to the second buyer, 1.6 to the third buyer, 4.0 to the fourth, and so on.

You should also check and make sure that the constraints and bounds that you set are satisfied. You can do this with the following code:

22 print("The total number of shares is:", sum(res.x))
23 print("Leftover money for each buyer:" money_available - res.x * prices)

In this code, you print the sum of the shares purchased by each buyer, which should be equal to n_shares. Then, you print the difference between each buyer’s cash on hand and the amount they spent. Each of these values should be positive. The output from these checks is shown below:

The total number of shares is: 15.0
The amount each buyer has leftover is: [4.78506124e-14 1.00000000e+00
4.95159469e-14 9.99200722e-14 5.06261699e-14 2.21697984e+00 3.00000000e+00
9.76996262e-14 1.00000000e+00 1.00000000e+00]

As you can see, all of the constraints and bounds on the solution were satisfied. Now you should try changing the problem so that the solver can’t find a solution. Change n_shares to a value of 1000, so that you’re trying to sell 1000 shares to these same buyers. When you run minimize(), you’ll find that the result is as shown below:

fun: nan
jac: array([nan, nan, nan, nan, nan, nan, nan, nan, nan, nan])
message: 'Iteration limit exceeded'
nfev: 2160
nit: 101
njev: 100
status: 9
success: False
x: array([nan, nan, nan, nan, nan, nan, nan, nan, nan, nan])

Notice that the status attribute now has a value of 9, and the message states that the iteration limit has been exceeded. There’s no way to sell 1000 shares given the amount of money each buyer has and the number of buyers in the market. However, rather than raising an error, minimize() still returns an OptimizeResult instance. You need to make sure to check the status code before proceeding with further calculations.

Conclusion

In this tutorial, you learned about the SciPy ecosystem and how that differs from the SciPy library . You read about some of the modules available in SciPy and learned how to install SciPy using Anaconda or pip. Then, you focused on some examples that use the clustering and optimization functionality in SciPy.

In the clustering example, you developed an algorithm to sort spam text messages from legitimate messages. Using kmeans(), you found that messages with more than about 20 digits are extremely likely to be spam!

In the optimization example, you first found the minimum value in a mathematically clear function with only one variable. Then, you solved the more complex problem of maximizing your profit from selling stocks. Using minimize(), you found the optimal number of stocks to sell to a group of buyers and made a profit of $8.79!

SciPy is a huge library, with many more modules to dive into. With the knowledge you have now, you’re well equipped to start exploring!

Categorías
Python

Automatización de Django implementaciones con Tela y Ansible

 

Tabla de Contenidos

  • mejores libros para el aprendizaje PythonPython Crash CourseHead-Primera Python, segundo editionInvent tus propios juegos de ordenador con Python, cuarto editionThink Python: Cómo Pensar como un Informático, segundo editionEffective Computación en Física: Guía de Campo de la Investigación con PythonLearn Python 3 del Curso de Python WayReal duro, Parte 1
  • Python Crash Course
  • de cabeza Python, 2ª edición
  • Inventa tus propios juegos de ordenador con Python, 4ª edición
  • Piense Python: Cómo Pensar como un Informático, 2ª edición
  • Computación eficaz en Física: Guía de campo de la Investigación con Python
  • Learn Python 3 del Curso real del pitón manera dura
  • , Parte 1
  • mejores Python Libros para KidsPython para niños: Una Juguetón Introducción a ProgrammingTeach a sus hijos con el Código : Padres-friendly Guía de Programación Python
  • Python para niños: Una Introducción a la Programación Juguetón
  • Enseñar a sus hijos a Código: Padres-Friendly Guía de Programación trucos
  • Mejor intermedios y Python BooksPython avanzada Python: un buffet de impresionante Python FeaturesFluent Python: clara, concisa y eficaz ProgrammingEffective Python: 59 maneras de escribir mejor PythonPython Cookbook
  • trucos Python: un buffet de impresionante Python Características
  • Fluido Python: clara, concisa y eficaz de programación Python
  • efectiva: 59 maneras de escribir mejor Python
  • Python Cookbook
  • Obtener Codificación!
  • Python Crash Course
  • de cabeza Python, 2ª edición
  • Inventa tus propios juegos de ordenador con Python, 4ª edición
  • Piense Python: Cómo Pensar como un Informático, 2ª edición
  • Computación eficaz en Física: Guía de campo de la Investigación con Python
  • Learn Python 3 del Curso real del pitón manera dura
  • , Parte 1
  • Python para niños: Una Juguetón Introducción a la Programación
  • Enseñe a sus hijos a Código: Padres-friendly Guía a Python programación trucos
  • Python: un buffet de impresionante Python Características
  • Fluido Python: clara, concisa y eficaz programación
  • Python efectiva: 59 maneras de escribir mejor Python
  • Python Cookbook

Python es un lenguaje de programación increíble .it se puede aplicar a casi cualquier tarea de programación, permite un rápido desarrollo y depuración, y trae el apoyo de lo que es sin duda el más acogedor comunidad de usuarios.

Introducción a Python es como aprender cualquier nueva habilidad: es importante encontrar un recurso que se conecte con para guiar su aprendizaje. Afortunadamente, no hay escasez de excelentes libros que pueden ayudarle a aprender tanto los conceptos básicos de la programación y los detalles de la programación en Python. Con la abundancia de recursos, puede ser difícil identificar qué libro sería el mejor para su situación.

En este artículo, se destacan los mejores libros para el aprendizaje de Python a través de una colección de reseñas de libros. Cada revisión le da un sabor del libro, los temas tratados, y el contexto para ilustrar estos temas. Diferentes libros resonarán con diferentes personas, dependiendo del estilo y la presentación de los libros, fondos de los lectores, así como otros factores.

Si son nuevos en Python, cualquiera de los libros de introducción le dará una base sólida en los fundamentos.

Tal vez usted quiere aprender Python con su hijo, o tal vez enseñar a Python a un grupo de kids.Check los mejores Python Libros para Niños de recursos dirigidos a un público más joven.

A medida que avance en el recorrido que Python, tendrá que profundizar más para maximizar la eficiencia de su código. Los mejores libros de nivel intermedio y avanzado Python proporcionan información para ayudarle a todo un experto de Python, lo que le permite convertirse en un experto Pythonista.

Después de leer estas críticas, si todavía no está seguro de qué libro elegir, los editores a menudo proporcionan un capítulo de muestra o sección para darle un ejemplo de lo que ofrece el libro. Lectura de una muestra del libro le debe dar la imagen más representativa del ritmo, el estilo y las expectativas del autor.

Independientemente de qué libro se destaca más, tenga en cuenta esta anécdota de uno de nuestros críticos de libros, Steven C. Howell:

“Un profesor favorito una vez me dijo,‘No importa qué libro leer primero. Siempre es el segundo que tiene más sentido.’

No puedo decir que éste ha sido siempre el caso para mí, pero definitivamente he encontrado que una segunda referencia puede hacer toda la diferencia cuando la primera me dejó perplejo o frustrado.

Cuando el aprendizaje de las clases de Python, que tenía dificultades para relacionarse con los ejemplos utilizados en los dos primeros libros Tomé up.It no fue hasta el tercer libro me he referido a que los conceptos empezaron a hacer clic.

La lección importante es que si se queda atascado o frustrado, y los recursos que ha no están ayudando, entonces no se dio por vencido. Mira otro libro, buscar en la web, pregunta en un foro, o simplemente tomar un descanso.”

Nota: Este artículo contiene enlaces de afiliados a los minoristas como Amazon, por lo que puede soportar el Real Python accediendo y haciendo una compra en algunos de los enlaces. La compra de uno de estos enlaces no añade ningún coste adicional para usted. enlaces de afiliados no influyen en nuestras decisiones editoriales de ninguna manera.

Los mejores libros para el aprendizaje de Python

Si eres nuevo en Python, es probable que en una de las dos situaciones siguientes:

Esta sección se centra en el primero de estos dos escenarios, con reseñas de los libros que consideramos que es la mejores libros de programación Python para los lectores que son nuevos en la programación y Python. En consecuencia, estos libros no requieren experiencia previa en programación. Parten de los fundamentos absolutos y enseñan ambos conceptos generales de programación, así como la forma en que se aplican a Python.

Nota: Si usted está buscando los mejores libros de Python para programadores con experiencia , considerar la siguiente selección de libros con revisiones completas en la introducción y secciones avanzadas:

  • Think Python: El más básico de esta lista , Think Python proporciona una referencia completa de Python.
  • Fluido Python: Mientras que la simplicidad de Python le permite iniciar rápidamente la codificación, este libro le enseña cómo escribir código Python idiomática, cuando abarca varios temas profundos de la lengua.
  • Python efectiva: 59 maneras de escribir mejor Python: Este relativamente corto libro es una colección de 59 artículos en los que, de manera similar a Python Fluido, se centran en la enseñanza de cómo escribir código verdaderamente Pythonic.
  • Python Cookbook: Como un libro de cocina, esta será una buena referencia sobre el uso de Python para completar las tareas que usted ha hecho en otro idioma.

Alternativamente, es posible que incluso prefieren ir directamente al tutorial oficial de Python, un recurso bien escrita y completa.

Python Crash Course

Eric Matthes (n Almidón Press, 2016)

Se hace lo que dice en la lata, y lo hace muy bien. El libro comienza con un tutorial de los básicos de Python elementos y estructuras de datos, a través de variables, cadenas, números, listas y tuplas, describiendo cómo se trabaja con cada uno de ellos.

A continuación, si se cubren las declaraciones y pruebas lógicas, seguido por una inmersión en los diccionarios.

Después de eso, la entrada de cubiertas para libros usuario, mientras que los bucles, funciones, clases, y manejo de archivos, así como las pruebas y la depuración de código.

eso es sólo la primera mitad del libro! En la segunda mitad, se trabaja en tres grandes proyectos, la creación de algunas aplicaciones, divertidas inteligentes.

El primer proyecto es un juego Alien Invasion, esencialmente, invasores del espacio, desarrollado utilizando el paquete pygame. A diseñar un barco (el uso de clases), a continuación, programa de la manera de pilotar y hacer que disparar balas. Luego, a diseñar varias clases de extranjeros, hace el movimiento flota alienígena, y que sea posible derribarlos. Por último, se añade un marcador y una lista de puntuaciones más altas para completar el juego.

Después de eso, la próxima visualización de datos de proyectos cubiertas con matplotlib, paseos aleatorios, tirar los dados, y un poco de análisis estadístico, la creación de gráficos y tablas con el paquete pygal. Se aprende cómo descargar datos en una variedad de formatos, importar en Python, y visualizar los resultados, así como la forma de interactuar con las API web, recuperar y visualizar los datos de GitHub y HackerNews.

El tercer proyecto le guía a través de la creación de una aplicación web completa utilizando Django para establecer un registro de aprendizaje para rastrear lo que los usuarios han estado estudiando. Cubre cómo instalar Django, creó un proyecto, el diseño de sus modelos, crear una interfaz de administración, configurar cuentas de usuario, gestionar los controles de acceso sobre una base por usuario, el estilo de toda su aplicación con Bootstrap, y, finalmente, implementarlo en Heroku .

Este libro está bien escrito y muy bien organizado. Presenta un gran número de ejercicios útiles, así como tres entretenido y desafiante proyectos que componen la segunda mitad del libro. (Revisado por David Schlesinger.)

  • Ver en Amazon »
  • Ver En Editor del sitio web»

de cabeza Python, 2ª edición

Paul Barry (O’Reilly, 2016)

me gusta mucho la serie de cabeza de libros, si bien es cierto que son más ligeros de peso en el contenido general que muchas de las otras recomendaciones de esta sección. La desventaja es la de que este enfoque hace que el libro más fácil de usar.

Si usted es el tipo de persona que le gusta aprender cosas un pequeño trozo, bastante autónomo a la vez, y que desea tener un montón de ejemplos concretos e ilustraciones de los conceptos involucrados, entonces el de cabeza serie es para ti. El sitio web del editor tiene que decir lo siguiente acerca de su enfoque:

“Sobre la base de las últimas investigaciones en la ciencia cognitiva y la teoría del aprendizaje, de cabeza Python utiliza un formato de gran riqueza visual para involucrar a su mente, en lugar de un enfoque mucho texto que pone a dormir. Por qué perder el tiempo luchando con nuevos conceptos? Esta experiencia de aprendizaje multisensorial está diseñado para la forma en que su cerebro funciona de verdad “. (Fuente)

lleno de ilustraciones, ejemplos, apartes, y otras cositas, de cabeza Python es consistentemente atractivo y fácil de leer. Este libro comienza su gira de Python sumergiéndose en las listas y que explica cómo utilizar y manipular ellos. A continuación, pasa en módulos, los errores y el manejo de archivos. Cada tema se organiza en torno a un proyecto unificador: la construcción de un sitio web dinámico para un entrenador de atletismo de la escuela el uso de Python a través de una interfaz de entrada común (CGI).

Después de eso, el libro pasa el tiempo y le enseña a usar una aplicación Android para interactuar con la página web que ha creado. Se aprende a manejar la entrada del usuario, los datos Wrangle, y la mirada en lo que está involucrado en el despliegue y la ampliación de una aplicación Python en la web.

Si bien este libro no es tan amplio como algunos de los otros, que cubre una amplia gama de tareas de Python de una manera que podría decirse que es más accesible, indoloro y eficaz. Esto es especialmente cierto si se encuentra el tema de la escritura de programas un poco intimidante al principio.

Este libro está diseñado para guiarlo a través de cualquier desafío. Mientras que el contenido se centra más, este libro tiene un montón de material para mantenerlo ocupado y el aprendizaje. Usted no se aburrirá. Si encuentra la mayoría de los libros de programación a ser demasiado seco, esto podría ser un excelente libro para que usted pueda empezar en Python. (Revisado por David Schlesinger y Steven C. Howell.)

  • Ver en Amazon »
  • Ver En Editor del sitio web»

Inventa tus propios juegos de ordenador con Python, 4ª edición

Al Sweigart (almidón, 2017)

Si los juegos son su cosa, o incluso tener una idea de juego de su cuenta, este sería el libro perfecto para aprender Python. En este libro, a aprender los fundamentos de la programación y Python con los ejercicios de aplicación se centraron en la creación de juegos clásicos.

Comenzando con una introducción a la terminal de Python y el bucle REPL, seguido de una base “Hola, mundo!” script, el derecho de buceo en la fabricación de un juego básico de adivinar el número, cubriendo números aleatorios, el control, la conversión de tipos, y los datos de Boole fluir. Después de eso, un pequeño script broma-decir está escrito para ilustrar el uso de declaraciones de impresión, los caracteres de escape, y las operaciones básicas de cuerda.

El próximo proyecto es un juego de exploración de cuevas basado en texto, Reino del Dragón, que es una introducción a los diagramas de flujo y funciones, guías a través de cómo definir sus propios argumentos y parámetros, y explica los operadores booleanos, el alcance global y local, y el sueño () función.

Después de un breve desvío en forma de depurar su código Python, junto poner en práctica el juego de ahorcado, mediante obras de arte ASCII, mientras aprenden acerca de las listas, el operador in, los métodos, las declaraciones elif, el módulo de azar, y un puñado de métodos de las cadenas .

A continuación, extender el juego del ahorcado con nuevas características, como las listas de palabras y niveles de dificultad, mientras aprenden acerca de los diccionarios, pares de valores clave, y la asignación a múltiples variables.

Su próximo proyecto es un juego de Tic-Tac-Toe, que introduce algunos conceptos de inteligencia artificial de alto nivel, se muestra cómo la evaluación de cortocircuito en los condicionales, y explica el valor Ninguno, así como algunas formas diferentes de acceder a las listas.

su viaje a través del resto del libro se desarrolla en un vein.You’ll similares aprender bucles anidados, mientras que la construcción de una serie de estilo Mastermind juego de adivinanzas, las coordenadas cartesianas para un juego Sonar Hunt, criptografía para escribir cifrado César, y la inteligencia artificial en la aplicación de Reversi (también conocido como Othello), en la que el equipo puede jugar contra sí mismo.

Después de todo esto, hay una inmersión en el uso de gráficos para los juegos con PyGame: usted cubrirá cómo animar los gráficos, gestionar la detección de colisiones, así como sonidos de uso, imágenes y sprites. Para llevar a todos estos conceptos, el libro le guía a través de hacer un juego de obstáculos gráfica esquivando.

Este libro está bien hecho, y el hecho de que cada proyecto es una unidad autónoma hace que sea atractivo y accesible. Si usted es alguien que le gusta aprender sobre la marcha, entonces usted disfrutará de este libro.

El hecho de que esto introduce el libro de conceptos sólo cuando sea necesario puede ser una posible disadvantage.While está organizado más como una guía de referencia, la amplia gama de contenidos que se imparten en el contexto de juegos conocidos hace de este uno de los mejores libros para el aprendizaje Pitón. (revisado por David Schlesinger.)

  • Ver en Amazon »
  • Ver El autor del sitio web»

Piense Python: Cómo Pensar como un Informático, 2ª edición

Allen B. Downey (O’Reilly , 2015)

Si el aprendizaje de Python mediante la creación de juegos de vídeo es demasiado frívolo para usted, considere el libro de Allen Downey Piense Python , que tiene un enfoque mucho más serio.

Como dice el título, el objetivo de este libro es que le enseñe cómo codificadores pensar acerca de la codificación, y hace un buen trabajo de ella. En comparación con los otros libros, es más seco y organizada de una manera más lineal. Los focos de libros sobre todo lo que necesitan saber acerca de la programación básica de Python, de una manera muy sencilla, clara y completa.

En comparación con otros libros similares, que no va tan profundamente en algunas de las áreas más avanzadas, en lugar que cubre una amplia gama de materiales, incluyendo temas de los otros libros no van a ninguna parte cerca. Ejemplos de tales temas incluyen la sobrecarga de operadores, polimorfismo, análisis de algoritmos, y la mutabilidad frente a la inmutabilidad.

versiones anteriores eran un poco de luz sobre los ejercicios, pero la última edición ha corregido en gran medida este libro shortcoming.The contiene cuatro proyectos razonablemente profundas, que se presentan como estudios de casos, pero en general, tiene un menor número de ejercicios de aplicación dirigidas en comparación con muchos otros libros.

Si desea una presentación paso a paso de sólo los hechos, y se desea obtener un poco de información adicional acerca del codificadores profesional de mirar los problemas, este libro es una gran elección. (Revisado por David Schlesinger y Steven C. Howell.)

  • Ver en Amazon »
  • Ver En Editor del sitio web»

Computación eficaz en Física: Guía de Campo de la Investigación con Python

Anthony Scopatz, Kathryn D. Huff (O’Reilly, 2015)

Este es el libro me gustaría tener cuando estaba primero aprendiendo Python.

A pesar de su nombre, este libro es una excelente opción para las personas que no tienen experiencia con la física, la investigación, o problemas computacionales.

Realmente es una guía de campo para el uso de Python. En la parte superior de la realidad, la enseñanza de Python, sino que también abarca los temas relacionados, como la línea de comandos y control de versiones, así como la prueba e implementación de software.

Además de ser un gran recurso de aprendizaje, este libro también servirá como una excelente referencia de Python, ya que los temas están bien organizados con un montón de ejemplos y ejercicios intercalados.

El libro está dividido en cuatro secciones bien llamado: Para empezar, conseguir que se haga, Cómo hacerlo bien, y conseguir que fuera allí.

La sección de introducción contiene todo lo necesario para comenzar a running.It comienza con un capítulo sobre los fundamentos de la línea de comandos bash. (Sí, incluso se puede instalar fiesta para Windows.) El libro procede a explicar los fundamentos de Python, golpeando en todos los temas esperados: operadores, cadenas, variables, contenedores, la lógica, y el flujo control.Additionally, hay un entero capítulo dedicado a todos los diferentes tipos de funciones, y otro para las clases y programación orientada a objetos.

Edificio

sobre esta base, los conseguir que se haga sección se mueve en el área de las más centrada en los datos de Python.Note que esta sección, que ocupa aproximadamente un tercio del libro, será más aplicable a los científicos, ingenieros y científicos de datos .Si es decir que, enjoy.If no es así, no dude en saltar a continuación, seleccionando cualquiera de las secciones pertinentes. Pero asegúrese de tomar el último capítulo de la sección, ya que le enseñará cómo implementar software utilizando pip, Conda, máquinas virtuales y contenedores de Docker.

Para aquellos de ustedes que están interesados ​​en trabajar con los datos, la sección comienza con una descripción rápida de las bibliotecas esenciales para el análisis de datos y visualization.You continuación tiene un capítulo especial dedicado a impartir los temas de las expresiones regulares, NumPy, los datos almacenamiento (incluyendo la ejecución fuera de núcleos operaciones), estructuras especializadas de datos (tablas hash, marcos de datos, D-árboles, y árboles kd), y la computación paralela.

El Consiguiéndolo Sección derecha le enseña cómo evitar y superar muchos de los problemas más comunes asociados con el trabajo en Python.It comienza mediante la extensión de la discusión sobre la implementación de software mediante la enseñanza de cómo construir tuberías de software utilizando make.You luego aprender cómo el uso de Git y Github para realizar un seguimiento, almacenar y organizar sus ediciones de código con el tiempo, un proceso conocido como la versión control.El sección concluye con la enseñanza de cómo depurar y probar el código, dos habilidades muy valiosas.

La sección final, conseguir que fuera allí, se centra en la comunicación efectiva con los consumidores de su código, usted mismo included.It cubre los temas de documentación, lenguajes de marcado (principalmente látex), la colaboración de código, y la sección licenses.The software y libro, concluye con una larga lista de proyectos Python científicos organizados por temas.

Este libro se destaca porque, además de la enseñanza de todos los fundamentos de Python, también enseña que muchas de las tecnologías utilizadas por Pythonistas. Este es realmente uno de los mejores libros para el aprendizaje de Python.

y también sirve como una gran referencia, se completa un glosario, bibliografía, y el libro índice.El definitivamente tiene un giro Python científica, pero no se preocupe si usted no viene de una formación científica. No hay ecuaciones matemáticas, e incluso se puede impresionar a sus compañeros de trabajo cuando ven que está en leer sobre Física Computacional! (revisado por Steven C Howell.)

  • Ver en Amazon »
  • Ver El autor del sitio web»

Learn Python 3 the Hard Way

Zed A. Shaw (Addison-Wesley, 2016)

Learn Python el Camino duro es un clásico. Soy un gran fan de enfoque del libro. Cuando se aprende “por las malas”, usted tiene que:

Lo bueno de este libro es lo bien que se presenta el contenido. se presenta claramente cada capítulo. Los ejemplos de código son todas concisa, bien construido, y al punto. Los ejercicios son instructivas, y cualquier problema que se encuentra con que no serán en absoluto insuperable. Su mayor riesgo es errores tipográficos. Hacerlo a través de este libro, y que sin duda ya no será un principiante en Python.

no deje que el título te desanime. El “camino difícil” resulta ser el camino más fácil si se toma el punto de vista de largo. amores nadie a escribir un montón de cosas en el, pero eso es lo que en realidad implica programación, por lo que es bueno para acostumbrarse a él desde el principio. Lo bueno de este libro es que se ha ido perfeccionando a través de varias ediciones ahora, para los restos de plástico se han hecho agradable y suave por ahora.

El libro está construido como una serie de más de cincuenta ejercicios, cada uno construido sobre el anterior y cada enseñanza que alguna nueva característica de la lengua. A partir de Ejercicio 0 con Python configurado en su ordenador, de comenzar a escribir programas sencillos. Se aprende acerca de las variables, tipos de datos, funciones lógicas, bucles, listas, depuración, diccionarios, programación orientada a objetos, la herencia y el embalaje. Incluso crear un juego simple que utiliza un motor de juego.

Las siguientes secciones cubren conceptos como pruebas automatizadas, la exploración léxica en la entrada del usuario a penas de análisis sintáctico, y el paquete lpthw.web, para poner su juego en la web.

Zed es un escritor atractivo, paciente que no pasa por alto los detalles. Si se trabaja a través de este libro de manera -el derecho “camino difícil”, mediante el seguimiento de las sugerencias de estudio previstos a lo largo del texto, así como los ejercicios de programación-usted será mucho más allá de la etapa de principiante programador cuando haya terminado. (Revisado por David Schlesinger.)

  • Ver en Amazon »
  • Ver El autor del sitio web»

Nota: De todos los libros incluidos en este artículo, este es el único con comentarios poco precisos. El desbordamiento de pila (SO) de la comunidad ha compilado una lista de 22 quejas prologados con la siguiente afirmación:

“Hemos notado una tendencia general que los usuarios utilizando [ Learn Python la manera dura ] publicar preguntas que no tiene mucho sentir tanto en PC como en el chat. Esto se debe a la estructura y las técnicas utilizadas en el libro “. (Fuente)

preparan su propia lista de tutoriales recomendados, que incluye lo siguiente:

  • El oficial de Python 3 tutorial
  • Inmersión en Python 3
  • El Inventar con la serie Python, que incluye Inventa tus propios juegos de ordenador con Python
  • Piense Python

pesar de la crítica negativa hacia Learn Python la manera dura , David Schlesinger y Amazonas revisores están de acuerdo en que el libro vale la pena, aunque es probable que desee complementar su biblioteca con otro libro de Python que podría servir más como una reference.Also, asegúrese de hacer su diligencia debida antes de hacer preguntas a desbordamiento de pila, como la comunidad puede ser un poco abrasivo a veces. Curso Python

real, parte 1

real del pitón equipo (Real Python, 2017)

Este libro es el primero de tres (hasta ahora) en la serie curso real del pitón. Fue escrito con el objetivo de conseguir que en funcionamiento, y lo hace un gran trabajo en la consecución de este objetivo. El libro es una mezcla de prosa explicativo, código de ejemplo y ejercicios de revisión. Los ejercicios de revisión intercalados solidifican su aprendizaje que le permite aplicar de inmediato lo que ha aprendido.

Al igual que con los libros anteriores, instrucciones claras se proporcionan por adelantado para conseguir Python instalado y en ejecución en el ordenador. Después de la sección de configuración, en lugar de dar una visión general seco de tipos de datos, real del pitón simplemente comienza con cuerdas y en realidad es bastante completo: se aprende rebanar cadena antes de llegar a la página 30.

A continuación, el libro le da una buena sensación de el sabor de Python muestra cómo jugar con algunos de los métodos de la clase que se pueden aplicar. A continuación, se aprende a funciones de escritura y bucles, utilizar la lógica condicional, trabajar con listas y diccionarios, y leer y escribir archivos.

Entonces las cosas se ponen muy divertido! Una vez que ha aprendido a instalar los paquetes con la pipa (y de la fuente), cubiertas real del pitón que interactúan con y manipular archivos PDF, utilizando SQL desde dentro Python, raspado de datos de las páginas web, utilizando numpy y matplotlib hacer la computación científica, y Por último, la creación de interfaces gráficas de usuario con easyGUI y tkinter.

Lo que me gusta de real Python es que, además de cubrir los aspectos básicos de una manera minuciosa y amable, el libro explora algunos de los usos más avanzados de Python que ninguno de los otros libros golpeado en, como una tela raspado. También hay dos volúmenes adicionales, que intervienen en el desarrollo más avanzado de Python. (Revisado por David Schlesinger.)

  • Ver En Python real »

responsabilidad: empecé a usar los libros real Python hace varios años, cuando todavía estaban en fase beta. Pensé entonces y todavía pienso ahora, que son uno de los mejores recursos disponibles para aprender el lenguaje Python y varias formas en que puede ser utilizado. Mi concierto de la redacción de artículos en el sitio web real Python es un desarrollo mucho más reciente, y mi opinión es completamente independiente. – David

mejores Python Libros para Niños

Los siguientes libros están dirigidos a los adultos interesados ​​en enseñar a los niños a código, mientras que, posiblemente aprender por sí mismos a lo largo del way.Both de estos libros se recomiendan para los niños tan jóvenes como de 9 o 10, pero que son ideales para los niños más grandes también. Es importante señalar que estos libros no están destinados a ser entregados a un solo niño, dependiendo de su edad

Se. Ellos serían ideales para un padre que quería aprender Python junto a su hijo.

Python para niños: Una Introducción a la Programación Juguetón

Jason R. Briggs (almidón, 2013)

“Juguetón” es correcto Este es un libro divertido para todas las edades, a pesar de su título!. Proporciona una forma clara, fácil de seguir, introducción a Python programming.It de profusamente ilustrado, los ejemplos son sencillos y claramente presentado, y es una guía sólida para alguien que quiera obtener una buena base en los fundamentos, además de un poco más.

El libro comienza con una excelente, guía detallada para conseguir Python instalado en su sistema, ya sea Windows, OS X, o Ubuntu Linux.It luego procede a introducir la terminal de Python y cómo puede ser utilizado como un simple calculator.This sirve para introducir algunos conceptos básicos como variables y operación aritmética.

A continuación, se abordan iterables, y el capítulo se abre camino progresivamente a través de cadenas, listas, tuplas y diccionarios.

Una vez que ha logrado, la biblioteca tortuga Python se usa para comenzar a trabajar con gráficos de tortuga, un marco popular para enseñar a los niños a code.From allí, los avances de libros a través condicionales declaraciones, bucles, funciones y módulos. Las clases y objetos

están cubiertos, seguido de un verdaderamente excelente sección sobre Python de funciones integradas, y luego una sección de una serie de librerías útiles Python y modules.Turtle gráficos se revisan con mayor detalle, después de lo cual el libro introduce tkinter de la creación de interfaces de usuario, mejores gráficos y animaciones pares.

Con esto concluye la parte 1 del libro, “aprender a programar”, mientras que el resto se centró en la construcción de dos divertida aplicación projects.The primer proyecto es construir una versión de un solo jugador de Pong, llamada Bounce! Esto integra los conceptos de programación de funciones, clases y control de flujo, junto con las tareas de la creación de una interfaz usando tkinter, que ilustra a la lona, ​​la realización de cálculos geométricos, y el uso de enlaces de sucesos para crear interactividad.

En el segundo proyecto, se construye un videojuego de desplazamiento lateral, Sr. Stickman carreras para el juego Exit.This se aplica a muchos de los mismos conceptos y tareas como Bounce! pero con más profundidad y una mayor complexity.Along el camino, también te presenten a la fuente abierta programa de manipulación de imágenes GIMP, que se utiliza para crear el libro elementos patrimoniales de su juego se hace una increíble cantidad de kilometraje de estos dos juegos, y conseguir que trabajar es a la vez instructiva y muy divertido.

Me gusta mucho este book.Whether eres joven, o simplemente jóvenes de corazón, podrá disfrutar de este libro si usted está buscando una manera divertida, accesible, introducción a Python y programación. (Revisado por David Schlesinger y Steven C. Howell.)

  • Ver en Amazon »
  • Ver En Editor del sitio web»

Enseñe a sus hijos a Código: Padres-Friendly Guía de Programación Python

Bryson Payne (almidón, 2015)

Este libro es similar a Python para niños, pero destinada más para un trabajo adulto con un niño (o niños) a aprender a código, como el título lo suggests.One que los conjuntos este libro, aparte de la mayoría de los libros de introducción es el uso de ilustraciones en color y en casi todos los libros page.The está bien escrito y presenta el aprendizaje de código como una manera de los niños se enseñan habilidades para resolver problemas.

As is commonly the case, this book begins with a Python installation guide.Compared to Python for Kids , the guide in this book is more cursory but completely adequate.

The first activity is, again, turtle graphics.A number of basic variations on drawing a rotated square are presented—without a lot of underlying explanation, initially—just to introduce the general concepts, but by the end of the section, you’ll have been provided with a pretty good understanding of the basics.

Next, calculations, variables, and mathematics in Python are explained. Once strings have been covered, the book brings all of that back into turtle graphics to enhance and explore the work that was done earlier. By this point, the code explanations are extremely clear, with explicit line-by-line details. You’d have a hard time misunderstanding any of the code presented.

Lists are explored next, as is the eval() function.Loops are introduced and then used to create increasingly complex graphics with the turtle.Conditional expressions come next, along with Boolean logic and operators.

The random library is introduced with a guessing game and randomly placed spirals made with turtle graphics. You explore randomness further by implementing rolling dice and picking cards, which leads up to you creating the games Yahtzee and War.

Functions, more advanced graphics, and user interaction are investigated next.

The book then branches off to cover using PyGame to create even more advanced graphics and animations, and then user interaction to create a very simple drawing program.

At this point, you have all the tools to create some real games. Development of both a full-featured version of Pong and a bubble-popping game are presented. Both provide enough depth to pose some challenges and maintain interest.

What I like best about this book is its large number of programming challenges, as well as the excellent summaries at the end of each chapter reminding you what was covered.If you and your child are interested in programming, this book should take both of you a good distance, and you’ll have a lot of fun.As the author, Dr. Bryson Payne, said in his recent TEDx talk, “Step out of your comfort zone, and become literate in the language of technology.” (Reviewed by David Schlesinger and Steven C. Howell.)

  • View On Amazon »
  • View On Publisher Website »

Best Intermediate and Advanced Python Books

Knowing Python is one thing.Knowing what’s Pythonic takes practice.Sometimes Python’s low barrier to entry gives people the mistaken idea that the language is less capable than other languages, that style does not matter, or that best practices are only a matter of preference.Have you ever seen Python code that looked like C or Fortran?

Learning how to use Python effectively requires some understanding of what Python is doing under the hood.Pythonic programming takes advantage of how the Python language is implemented to maximize the efficiency of your code.

Fortunately, there are some excellent books, packed with expert guidance, aimed to help you take what you’ve learned and level up your skills.Any of the books in this section will give you a deeper understanding of Python programming concepts and teach you how to write developer-style Python code.Note that these are by no means introductory books.They do not include the basics of getting started.These books will be helpful if you are already coding in Python and want to further hone your skills on your path to becoming a serious Pythonista.

Python Tricks: A Buffet of Awesome Python Features

Dan Bader (dbader.org, 2017)

This book illustrates valuable lesser-known Python features and best practices, written to help you gain a deeper understanding of Python.Each of the 43 subsections presents a different concept, referred to as a Python Trick, with discussion and easy-to-digest code examples illustrating how you can take advantage of that concept.

The book’s content is broken into the following sections:

  • Patterns for Cleaner Python
  • Effective Functions
  • Classes & OOP
  • Common Data Structures in Python
  • Looping & Iteration
  • Dictionary Tricks
  • Pythonic Productivity Techniques

As it says on the cover, the content is organized as “A Buffet,” with each subsection being a self-contained topic, with a brief introduction, examples, discussion, and list of Key Takeaways .As such, you should feel free to jump around to whichever sections are the most appealing.

In addition to the book, I particularly enjoyed the 12 Bonus Videos that are available when you purchase this as an eBook.They have an average length of 11 minutes, perfect for watching during lunch.Each video illustrates a different concept using clear and concise code examples that are simple to reproduce.While some of the videos covered familiar concepts, they still provided interesting insight without dragging on. (Reviewed by Steven C. Howell.)

  • View On Amazon »
  • View On Real Python »

Disclaimer: Though this book is officially distributed through Real Python, I recommend it independently of my connection with Real Python.I purchased this book when it was first released, before I had the opportunity to write for Real Python.For further evidence of the value of this book, check out the Amazon reviews: 148, averaging 4.8 out of 5 stars, at the time of this review. — Steve

Fluent Python: Clear, Concise, and Effective Programming

Luciano Ramalho (O’Reilly, 2014)

This book was written for experienced Python 2 programmers who want to become proficient in Python 3.Consequently, this book is perfect for someone with a solid foundation in the basics of Python, 2 or 3, who wants to take their skills to the next level.Additionally, this book also works well as a reference for an experienced programmer from another language who wants to look up “How do I do in Python?”

The book is organized by topic so that each section can be read independently.While many of the topics covered in this book are found in introductory books, Fluent Python provides much more detail, illuminating many of the more nuanced and overlooked features of the Python language.

The chapters are broken into the following six sections:

With code examples on almost every page, and numbered call-outs linking lines of code to helpful descriptions, this book is extremely approachable.Additionally, the code examples are geared toward the interactive Python console, a practical approach to exploring and learning the concepts presented.

I find myself turning to this book when I have a Python question and want an explanation that is more thorough than the one I would likely get on Stack Overflow.I also enjoy reading this book when I have a bit of down-time and just want to learn something new.On more than one occasion, I have found that a concept I recently learned from this book unexpectedly turned out to be the perfect solution to a problem I had to solve. (Reviewed by Steven C. Howell.)

  • View On Amazon »
  • View On Publisher Website »

Effective Python: 59 Ways to Write Better Python

Brett Slatkin (Addison-Wesley, 2015)

This book is a collection of 59 independent articles that build on a basic understanding of Python to teach Pythonic best practices, lesser known functionality, and built-in tools.The topics range in complexity, beginning with the simple concept of being aware of which Python version you’re using, and ending with the more complicated, and typically ignored, concept of identifying memory leaks.

Each article is a combination of example code, discussion, and a list of things to remember.

As each article is independent, this is a great book to jump around in, allowing you to focus on the topics that are most applicable or interesting.This also makes it perfect for reading one article at a time.With each article being around two to four pages in length, you could make time to read one article per day, finishing the book in two to three months (depending on whether you read on weekends).

The articles are grouped into the following 8 chapters:

If you have a solid foundation in Python and want to fill in holes, deepen you understanding, and learn some of the less obvious features of Python, this would be a great book for you. (Reviewed by Steven C. Howell.)

  • View On Amazon »
  • View On Author Website »

Python Cookbook

David Beazley & Brian K. Jones (O’Reilly, 3rd edition, 2013)

What makes this book stand out is its level of detail. Code cookbooks are typically designed as short and sweet manuals to illustrate slick ways of doing everyday tasks.In this case, each recipe in Python Cookbook has an extended code solution as well as an author’s discussion of some particular elements of the solution.

Each recipe starts out with a clear problem statement, such as, “You want to write a decorator that adds an extra argument to the calling signature of the wrapped function.” It then jumps into a solution that uses modern, idiomatic Python 3 code, patterns, and data structures, often spending four to five pages discussing the solution.

Based on its more involved and sophisticated examples, and the authors’ own recommendation in the preface, this is probably the most advanced Python book on our list.Despite that, don’t be scared away if you consider yourself an intermediate Python programmer.Who’s judging, anyway?There’s an old saying that goes something like this:

“The best way to become a better basketball player is to lose to the best players you can find, rather than beating the worst.”

You may see some code blocks you don’t fully understand—come back to them in a few months. Re-read those sections after you’ve picked up a few additional concepts, and suddenly, it will click. Most of the chapters start out fairly straightforward, and then gradually become more intense.

The latter half of the book illustrates designs like decorator patterns, closures, accessor functions, and callback functions.

It’s always nice to read from a trustworthy source, and this book’s authors certainly fit that bill. David Beazley is a frequent keynote speaker at events such as PyCon and also the author of Python Essential Reference . Similarly, Brian K. Jones is a CTO, the creator of a Python magazine, and founder of the Python User Group in Princeton (PUG-IP).

This particular edition is written and tested with Python 3.3. (Reviewed by Brad Solomon.)

  • View On Amazon »
  • View On Publisher Website »

Get Coding!

One of the awesome things about Python is it has a relatively low barrier to entry, compared to many other languages.Despite this, learning Python is a never-ending process.The language is relevant for such a wide variety of tasks, and evolves so much that there will always be something new to discover and learn.While you can pick up enough Python to do some fun things in a week or two, people who’ve been using Python for twenty years will tell you they’re still learning new things they can do with this flexible and evolving language.

To ultimately be successful as a Python programmer, you need to begin with a solid foundation, then gain a deeper understanding of how the language works, and how to best put it to use.To gain a solid foundation, you really can’t go wrong with any of the best books to learn Python.If you want to learn Python with a child, or maybe teach a group of kids, check out the list of best Python books for kids.After you’ve got your feet wet, check out some of the best intermediate and advanced Python books to dig in deeper to less obvious concepts that will improve the efficiency of your code.

All of these books will teach you what you need to know to legitimately call you rself a Python coder.The only ingredient missing is you .

Categorías
Python

Lectura y escritura de archivos en Python

 

Tabla de Contenidos

  • Por qué TDD? Configuración
  • primera prueba
  • Django
  • de control de versiones
  • funcional TestsAdmin LoginSetup los contactos Configuración de aplicaciones
  • Admin Login
  • los contactos de la unidad de aplicaciones
  • TestsViewsMain viewall Contactos ViewAdd Contacto ViewValidationCreate Contacto
  • Vistas
  • Vista principal
  • Todos contactos Ver
  • agregar contacto Ver
  • Validación
  • Crear contacto
  • pruebas funcionales Estructura Redux
  • prueba

  • Conclusión
  • admin Login
  • de configuración la aplicación contactos
  • Vistas
  • Vista principal
  • Todos Ver contactos
  • agregar contacto Ver
  • Validación
  • Crear contacto

Última actualización: – (! vic gracias)

  • 29/01/2014 código actualizado para la forma
  • 12/29/2013 – reestructurado todo entrada de blog

prueba de conducción del Developme nt (TDD) es un ciclo de desarrollo iterativo que hace hincapié en escribir pruebas automatizadas antes de escribir el código real.

El proceso es simple:

Por qué TDD?

Con TDD, aprenderá a romper el código en trozos lógicos, de fácil comprensión, lo que ayuda a garantizar la exactitud de código.

Esto es importante porque es difícil a-

TDD ayuda a solucionar estos problemas. Que no garantiza en absoluto que su código estará libre de error; Sin embargo, usted va a escribir mejor código, que se traduce en una mejor comprensión del código. Esto en sí mismo le ayudará con la eliminación de errores y, al menos, usted será capaz de errores de dirección mucho más fácil.

TDD es prácticamente un estándar de la industria también. charla

suficiente. Vamos a llegar a un código.

Para este tutorial, vamos a ser la creación de una aplicación de contactos almacén del usuario.

Nota: Este tutorial asume que está ejecutando un entorno basado en Unix – por ejemplo, Mac OS X, Linux recta, o Linux VM a través de Windows. También estaré usando Sublime 2 como mi editor de texto. También, asegúrese de que haya completado el tutorial oficial de Django y tener un conocimiento básico del lenguaje Python. Además, en este primer post, sin embargo, no vamos a entrar en algunas de las nuevas herramientas disponibles en Django 1.6. Este post establece las bases para posteriores mensajes que tienen que ver con diferentes formas de pruebas.

primera prueba

Antes de hacer nada tenemos que configura por primera vez una prueba. Para esta prueba sólo queremos hacer que Django es configurado correctamente. Vamos a estar usando una prueba de funcionamiento para esto – lo que vamos a estar explicamos más abajo.

Crear un nuevo directorio para su proyecto:

$ mkdir django-tdd
$ cd django-tdd

configuración Ahora un nuevo directorio para incluir sus pruebas funcionales:

$ mkdir ft
$ cd ft

Crear un nuevo archivo llamado “tests.py” y añadir el siguiente código:

from selenium import webdriver

browser = webdriver.Firefox()
browser.get('http://localhost:8000/')

body = browser.find_element_by_tag_name('body')
assert 'Django' in body.text

browser.quit()

Ahora ejecute el prueba:

$ python tests.py

Asegúrese de que tiene instalado el selenio – pip instalar el selenio

debería ver FireFox pop-up y tratar de navegar a http: // localhost: 8000 /. En su terminal debería ver:

Traceback (most recent call last):
File "tests.py", line 7, in
assert 'Django' in body.text
AssertionError

Felicidades! Usted escribió su primera prueba falla.

Ahora vamos a escribir código sólo lo suficiente como para hacerlo pasar, que simplemente equivale a la creación de un entorno de desarrollo de Django. Configuración

Django

Activar un virtualenv:

$ cd ..
$ virtualenv --no-site-packages env
$ source env/bin/activate

Instalar Django y la configuración de un proyecto:

$ pip install django==1.6.1
$ django-admin.py startproject contacts

Su estructura actual proyecto debe tener este aspecto:

├── contacts
│   ├── contacts
│   │   ├── __init__.py
│   │   ├── settings.py
│   │   ├── urls.py
│   │   └── wsgi.py
│   └── manage.py
└── ft
└── tests.py

Instalar Selenio:

$ pip install selenium==2.39.0

ejecutar el servidor:

$ cd contacts
$ python manage.py runserver

A continuación, abrir una nueva ventana en su terminal, navegue hasta el directorio “pies”, a continuación, ejecutar la prueba:

$ python tests.py

debería ver la ventana de Firefox navegar a http: // localhost: 8000 / nuevo. Esta vez no debe haber errores. Agradable. Que acaba de pasar su primera prueba!

Ahora, la creación de nuestro entorno de desarrollo acabado de let. Control de

Versión

En primer lugar, añadir un “.gitignore” e incluir el código siguiente en el archivo:

.Python
env
bin
lib
include
.DS_Store
.pyc

Ahora crear un repositorio Git y comprometerse:

$ git init
$ git add .
$ git commit -am "initial"

Con la configuración del proyecto, vamos a dar un paso atrás y discutir funcional pruebas.

pruebas funcionales

nos acercamos a la primera prueba a través de selenio a través de pruebas funcionales. Estas pruebas permiten a impulsar el navegador web como si fuéramos el usuario final, para ver cómo la aplicación de hecho funciones . Dado que estas pruebas siguen el comportamiento del usuario final – también llamado una historia de usuario – se trata de la prueba de una serie de características, en lugar de una sola función – que es más apropiado para pruebas unitarias. importante señalar que cuando se prueba código que no has escrito, usted debe comenzar con las pruebas funcionales de Se. Dado que estamos probando en esencia código de Django, pruebas funcionales son el camino correcto a seguir.

Otra forma de pensar funcional vs pruebas unitarias es que las pruebas funcionales se centran en las pruebas de la aplicación desde el exterior, desde la perspectiva del usuario, mientras que las pruebas unitarias se centran en la aplicación desde el interior, desde la perspectiva del desarrollador.

Esto hará mucho más sentido en la práctica.

Antes de continuar, vamos a reestructurar nuestro entorno de pruebas para hacer más fácil la prueba.

En primer lugar, vamos a volver a escribir la primera prueba en el archivo “tests.py”:

from selenium import webdriver
from selenium.webdriver.common.keys import Keys

from django.test import LiveServerTestCase

class AdminTest(LiveServerTestCase):

def setUp(self):
self.browser = webdriver.Firefox()

def tearDown(self):
self.browser.quit()

def test_admin_site(self):
# user opens web browser, navigates to admin page
self.browser.get(self.live_server_url + '/admin/')
body = self.browser.find_element_by_tag_name('body')
self.assertIn('Django administration', body.text)

continuación, se ejecuta:

$ python manage.py test ft

Se debe pasar:

----------------------------------------------------------------------
Ran 1 test in 3.304s

OK

Felicidades!

Antes de continuar, vamos a ver lo que está pasando aquí. Si todo ha ido bien debería pasar. También debe ver FireFox abierta y pasar por el proceso que se indica en el ensayo con el tearDown funciones setup () () y. La prueba en sí es simplemente probando si el “admin /” (self.browser.get (self.live_server_url + ‘/ admin /’) página se puede encontrar y que las palabras “administración Django” están presentes en el cuerpo de la etiqueta.

Confirmémoslo

ejecutar el servidor:.

$ python manage.py runserver

a continuación, vaya a http: // localhost: 8000 / admin / en su navegador y debería ver:

Nos puede confirmar que la prueba está funcionando correctamente con sólo las pruebas de lo que no debía actualizar la última línea de la prueba a:..

self.assertIn('administration Django', body.text)

ejecutarlo de nuevo debería ver el siguiente error (que se espera, por supuesto):..

AssertionError: 'administration Django' not found in u'Django administration\nUsername:\nPassword:\n '

corregir el test de nuevo Confirmar la código.

por último, ¿se fijaron que empezamos el nombre de la función para la prueba real se inició con test_. Esto es para que el corredor de prueba Django puede encontrar la prueba. En otras palabras, cualquier función que comienza con test_ serán tratados como una prueba por el corredor de prueba.

administración Iniciar sesión

A continuación, la prueba nos dejó para asegurarse de que el usuario puede iniciar sesión en el sitio de administración.

actualización test_admin_site la función en “tests.py”:

def test_admin_site(self):
# user opens web browser, navigates to admin page
self.browser.get(self.live_server_url + '/admin/')
body = self.browser.find_element_by_tag_name('body')
self.assertIn('Django administration', body.text)
# users types in username and passwords and presses enter
username_field = self.browser.find_element_by_name('username')
username_field.send_keys('admin')
password_field = self.browser.find_element_by_name('password')
password_field.send_keys('admin')
password_field.send_keys(Keys.RETURN)
# login credentials are correct, and the user is redirected to the main admin page
body = self.browser.find_element_by_tag_name('body')
self.assertIn('Site administration', body.text)

Por lo tanto –

  • find_element_by_name – se utiliza para la localización de los campos de entrada send_keys
  • – envía las pulsaciones de teclado

Ejecutar la prueba. Usted debe ver este error:

AssertionError: 'Site administration' not found in u'Django administration\nPlease enter the correct username and password for a staff account. Note that both fields may be case-sensitive.\nUsername:\nPassword:\n '

Esta fracasado porque no tenemos una configuración de usuario admin. Este es un fallo esperado, lo cual es bueno. En otras palabras, sabíamos que iba a fallar – que hace que sea mucho más fácil de solucionar.

sincronización de la base de datos: Configuración

$ python manage.py syncdb

un usuario administrador.

prueba

nuevo. Debe volver a fallar. ¿Por qué? Django crea una copia de la base de datos cuando las pruebas son corrió así que de esa manera las pruebas no afectan a la base de datos de producción.

Hay que configurar un accesorio, que es un archivo que contiene los datos que quiera cargar en la base de datos de prueba: las credenciales de inicio de sesión. Para ello, ejecute estos comandos para volcar la información de usuario administrador de la base de datos para el accesorio:

$ mkdir ft/fixtures
$ python manage.py dumpdata auth.User --indent=2 > ft/fixtures/admin.json

Ahora actualizar la clase AdminTest:

class AdminTest(LiveServerTestCase):

# load fixtures
fixtures = ['admin.json']

def setUp(self):
self.browser = webdriver.Firefox()

def tearDown(self):
self.browser.quit()

def test_admin_site(self):
# user opens web browser, navigates to admin page
self.browser.get(self.live_server_url + '/admin/')
body = self.browser.find_element_by_tag_name('body')
self.assertIn('Django administration', body.text)
# users types in username and passwords and presses enter
username_field = self.browser.find_element_by_name('username')
username_field.send_keys('admin')
password_field = self.browser.find_element_by_name('password')
password_field.send_keys('admin')
password_field.send_keys(Keys.RETURN)
# login credentials are correct, and the user is redirected to the main admin page
body = self.browser.find_element_by_tag_name('body')
self.assertIn('Site administration', body.text)

Ejecutar la prueba. Debe pasar.

Cada vez que una prueba es RAN, Django vuelca la base de datos de prueba. Entonces todos los accesorios especificados en el archivo “test.py” se cargan en la base de datos. Agregar un afirman más de

Let. Actualización de la prueba de nuevo:

def test_admin_site(self):
# user opens web browser, navigates to admin page
self.browser.get(self.live_server_url + '/admin/')
body = self.browser.find_element_by_tag_name('body')
self.assertIn('Django administration', body.text)
# users types in username and passwords and presses enter
username_field = self.browser.find_element_by_name('username')
username_field.send_keys('admin')
password_field = self.browser.find_element_by_name('password')
password_field.send_keys('admin')
password_field.send_keys(Keys.RETURN)
# login credentials are correct, and the user is redirected to the main admin page
body = self.browser.find_element_by_tag_name('body')
self.assertIn('Site administration', body.text)
# user clicks on the Users link
user_link = self.browser.find_elements_by_link_text('Users')
user_link[0].click()
# user verifies that user live@forever.com is present
body = self.browser.find_element_by_tag_name('body')
self.assertIn('live@forever.com', body.text)

ejecutarlo. Se debe fallar, porque necesitamos y otro usuario con el archivo de datos:

[
{
"pk": 1,
"model": "auth.user",
"fields": {
"username": "admin",
"first_name": "",
"last_name": "",
"is_active": true,
"is_superuser": true,
"is_staff": true,
"last_login": "2013-12-29T03:49:13.545Z",
"groups": [],
"user_permissions": [],
"password": "pbkdf2_sha256$12000$VtsgwjQ1BZ6u$zwnG+5E5cl8zOnghahArLHiMC6wGk06HXrlAijFFpSA=",
"email": "ad@min.com",
"date_joined": "2013-12-29T03:49:13.545Z"
}
},
{
"pk": 2,
"model": "auth.user",
"fields": {
"username": "live",
"first_name": "",
"last_name": "",
"is_active": true,
"is_superuser": false,
"is_staff": false,
"last_login": "2013-12-29T03:49:13.545Z",
"groups": [],
"user_permissions": [],
"password": "pbkdf2_sha256$12000$VtsgwjQ1BZ6u$zwnG+5E5cl8zOnghahArLHiMC6wGk06HXrlAijFFpSA=",
"email": "live@forever.com",
"date_joined": "2013-12-29T03:49:13.545Z"
}
}
]

Ejecutar de nuevo. Asegúrese de que su paso. Refactor la prueba si es necesario. Ahora pensar en lo demás que usted podría probar. Tal vez usted podría poner a prueba para asegurarse de que el usuario administrador puede agregar un usuario en el panel de administración. O tal vez una prueba para asegurarse de que alguien sin acceso de administrador no puede acceder al panel de administración. Escribir algunas pruebas más. Actualizar el código. Prueba de nuevo. Refactor si es necesario.

A continuación, vamos a añadir la aplicación para añadir contactos. No se olvide de cometer! Configuración

la aplicación Contactos

empezar con una prueba. Agregue la siguiente función:

def test_create_contact_admin(self):
self.browser.get(self.live_server_url + '/admin/')
username_field = self.browser.find_element_by_name('username')
username_field.send_keys('admin')
password_field = self.browser.find_element_by_name('password')
password_field.send_keys('admin')
password_field.send_keys(Keys.RETURN)
# user verifies that user_contacts is present
body = self.browser.find_element_by_tag_name('body')
self.assertIn('User_Contacts', body.text)

ejecutar el banco de prueba de nuevo. Debería ver la siguiente de errores

AssertionError: 'User_Contacts' not found in u'Django administration\nWelcome, admin. Change password / Log out\nSite administration\nAuth\nGroups\nAdd\nChange\nUsers\nAdd\nChange\nRecent Actions\nMy Actions\nNone available'

  • que se espera.

Ahora, escribir código sólo lo suficiente para que esto pase.

Crear la App:

$ python manage.py startapp user_contacts

Añadir al archivo “settings.py”:

INSTALLED_APPS = (
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'ft',
'user_contacts',
)

Dentro del archivo “admin.py” en el directorio user_contacts añadir el siguiente código:

from user_contacts.models import Person, Phone
from django.contrib import admin

admin.site.register(Person)
admin.site.register(Phone)

Su estructura del proyecto debe parecerse esto:

├── user_contacts
│   ├── __init__.py
│   ├── admin.py
│   ├── models.py
│   ├── tests.py
│   └── views.py
├── contacts
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── ft
│   ├── __init__.py
│   ├── fixtures
│   │   └── admin.json
│   └── tests.py
└── manage.py

Update “models.py”:

from django.db import models

class Person(models.Model):
first_name = models.CharField(max_length = 30)
last_name = models.CharField(max_length = 30)
email = models.EmailField(null = True, blank = True)
address = models.TextField(null = True, blank = True)
city = models.CharField(max_length = 15, null = True,blank = True)
state = models.CharField(max_length = 15, null = True, blank = True)
country = models.CharField(max_length = 15, null = True, blank = True)

def __unicode__(self):
return self.last_name +", "+ self.first_name

class Phone(models.Model):
person = models.ForeignKey('Person')
number = models.CharField(max_length=10)

def __unicode__(self):
return self.number

Ejecutar la prueba de nuevo ahora. Ahora debería ver: Ir de

Ran 2 tests in 11.730s

OK

Let adelante y añadir a la prueba para asegurarse de que el administrador puede agregar datos:

# user clicks on the Persons link
persons_links = self.browser.find_elements_by_link_text('Persons')
persons_links[0].click()
# user clicks on the Add person link
add_person_link = self.browser.find_element_by_link_text('Add person')
add_person_link.click()
# user fills out the form
self.browser.find_element_by_name('first_name').send_keys("Michael")
self.browser.find_element_by_name('last_name').send_keys("Herman")
self.browser.find_element_by_name('email').send_keys("michael@realpython.com")
self.browser.find_element_by_name('address').send_keys("2227 Lexington Ave")
self.browser.find_element_by_name('city').send_keys("San Francisco")
self.browser.find_element_by_name('state').send_keys("CA")
self.browser.find_element_by_name('country').send_keys("United States")
# user clicks the save button
self.browser.find_element_by_css_selector("input[value='Save']").click()
# the Person has been added
body = self.browser.find_element_by_tag_name('body')
self.assertIn('Herman, Michael', body.text)
# user returns to the main admin screen
home_link = self.browser.find_element_by_link_text('Home')
home_link.click()
# user clicks on the Phones link
persons_links = self.browser.find_elements_by_link_text('Phones')
persons_links[0].click()
# user clicks on the Add phone link
add_person_link = self.browser.find_element_by_link_text('Add phone')
add_person_link.click()
# user finds the person in the dropdown
el = self.browser.find_element_by_name("person")
for option in el.find_elements_by_tag_name('option'):
if option.text == 'Herman, Michael':
option.click()
# user adds the phone numbers
self.browser.find_element_by_name('number').send_keys("4158888888")
# user clicks the save button
self.browser.find_element_by_css_selector("input[value='Save']").click()
# the Phone has been added
body = self.browser.find_element_by_tag_name('body')
self.assertIn('4158888888', body.text)
# user logs out
self.browser.find_element_by_link_text('Log out').click()
body = self.browser.find_element_by_tag_name('body')
self.assertIn('Thanks for spending some quality time with the Web site today.', body.text)

que es para la funcionalidad de administración. Deje de mecanismos de conmutación y el enfoque de la aplicación, user_contacts, sí. ¿Ha olvidado para comprometerse? Si es así, hacerlo ahora.

Unidad

Pruebas de

Piense acerca de las características que hemos escrito hasta ahora. Sólo hemos definido nuestro modelo y los administradores podrán alterar el modelo. Basado en esto, y el objetivo general de nuestro proyecto, se centran en las funcionalidades de usuario restantes. Los usuarios deben

poder-

intentar formular la prueba de funcionamiento restantes (s) sobre la base de esos requisitos. Antes de escribir las pruebas funcionales, sin embargo, debemos definir el comportamiento del código a través de pruebas de unidad – lo que le ayudará a escribir bien, un código limpio, por lo que es más fácil escribir las pruebas funcionales.

Recuerde : Las pruebas funcionales son el último indicador de si el proyecto funciona o no, mientras que las pruebas de unidad son los medios para ayudar a alcanzar ese fin. Todo esto tendrá sentido pronto. pausa de

Let por un minuto y hablar de algunas convenciones.

Aunque los fundamentos de TDD (o extremos) – Test, código, Refactor – son universales, muchos desarrolladores de acercarse a los medios de manera diferente. Por ejemplo, me gusta escribir mis pruebas de unidad en primer lugar, para asegurar que mi código funciona a un nivel granular, a continuación, escribir las pruebas funcionales. Otros escriben pruebas funcionales en primer lugar, verlas fallan, entonces las pruebas de unidad de escritura, de ver fallan, a continuación, escribir el código para satisfacer primero las pruebas unitarias, que en última instancia deben satisfacer las pruebas de funcionamiento. No hay respuesta correcta o incorrecta aquí. Hacer lo que se siente más cómodo – pero siguen poniendo a prueba en primer lugar, a continuación, escribir código, y finalmente refactor.

Vistas

En primer lugar, comprobar para asegurarse de que todos los puntos de vista están configurados correctamente.

Vista principal

Como siempre, se inicia con una prueba:

from django.template.loader import render_to_string
from django.test import TestCase, Client
from user_contacts.models import Person, Phone
from user_contacts.views import *

class ViewTest(TestCase):

def setUp(self):
self.client_stub = Client()

def test_view_home_route(self):
response = self.client_stub.get('/')
self.assertEquals(response.status_code, 200)

Nombre test_views.py esta prueba y guardarlo en la user_contacts / Pruebas de directorio. También añadir un archivo __init__.py al directorio y borrar el archivo “tests.py” en el directorio principal user_contacts.

Run que:

$ python manage.py test user_contacts

Que falle – AssertionError: 404 = 200 – porque la URL, Vista, y la plantilla no existen. Si no está familiarizado con la forma en Django se encarga de la arquitectura MVC, por favor leer el breve artículo aquí.

La prueba es simple. En primer lugar, obtener la URL “/” con el cliente, que es parte de TestCase de Django. La respuesta se almacena, después comprobamos para asegurarse de que el código de estado devuelto es igual a 200.

Añadir la siguiente ruta de “contactos / urls.py”:

url(r'^', include('user_contacts.urls')),

actualización “user_contacts / urls.py”:

from django.conf.urls import patterns, url

from user_contacts.views import *

urlpatterns = patterns('',
url(r'^$', home),
)

Actualizar “views.py”:

from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render_to_response, render
from django.template import RequestContext
from user_contacts.models import Phone, Person
# from user_contacts.new_contact_form import ContactForm

def home(request):
return render_to_response('index.html')

Añadir una plantilla de “index.html” en el directorio de plantillas:



Welcome.<itle><br /> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link href="http:/<br />etdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" rel="stylesheet" media="screen"></p> <style> .container { padding: 50px; } </style> <p> </head><br /> <body></p> <div class="container"> <h1>What would you like to do?</h1> <ul> <li><a href="/all">View Contacts</a></li> <li><a href="/add">Add Contact</a></li> </ul> <div> <script src="http://code.jquery.com/jquery-1.10.2.min.js"></script><br /> <script src="http:/<br />etdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script><br /> </body><br /> </html><br /> </code> </p> <p> Ejecutar la prueba de nuevo. Se debe pasar muy bien. </p> <h3> Todos los contactos Ver </h3> <p> La prueba de este punto de vista es casi idéntica a la última prueba. Intentarlo por su cuenta antes de mirar a mi respuesta. </p> <p> Escribir la prueba por primera vez por la adición de la siguiente función a la clase ViewTest: </p> <p> <code>def test_view_contacts_route(self):<br /> response = self.client_stub.get('/all/')<br /> self.assertEquals(response.status_code, 200)<br /> </code> </p> <p> Cuando RAN, debería ver el mismo error: AssertionError: 404 = 200. </p> <p> Actualizar “user_contacts / urls.py” con la siguiente ruta : </p> <p> <code>url(r'^all/$', all_contacts),<br /> </code> </p> <p> Update “views.py”: </p> <p> <code>def all_contacts(request):<br /> contacts = Phone.objects.all()<br /> return render_to_response('all.html', {'contacts':contacts})<br /> </code> </p> <p> Añadir un “-todos.html Anuncios” plantilla para el directorio de plantillas: </p> <p> <code><!DOCTYPE html><br /> <html><br /> <head><br /> <title>All Contacts.<itle><br /> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link href="http:/<br />etdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" rel="stylesheet" media="screen"></p> <style> .container { padding: 50px; } </style> <p></head><br /> <body></p> <div class="container"> <h1>All Contacts</h1> <table border="1" cellpadding="5"> <tr> <th>First Name<h></p> <th>Last Name<h></p> <th>Address<h></p> <th>City<h></p> <th>State<h></p> <th>Country<h></p> <th>Phone Number<h></p> <th>Email<h><br /> <r><br /> {% for contact in contacts %}</p> <tr> <td>{{contact.person.first\_name}}<d></p> <td>{{contact.person.last\_name}}<d></p> <td>{{contact.person.address}}<d></p> <td>{{contact.person.city}}<d></p> <td>{{contact.person.state}}<d></p> <td>{{contact.person.country}}<d></p> <td>{{contact.number}}<d></p> <td>{{contact.person.email}}<d><br /> <r><br /> {% endfor %}<br /> <able><br /> <br /> <a href="/">Return Home</a> </div> <p> <script src="http://code.jquery.com/jquery-1.10.2.min.js"></script><br /> <script src="http:/<br />etdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script><br /> </body><br /> </html><br /> </code> </p> <p> Esto debe pasar también. </p> <h3> Añadir Contacto Ver </h3> <p> Esta prueba es ligeramente diferente de los dos anteriores, así que por favor seguir a lo largo de cerca. </p> <p> Añadir la prueba para el conjunto de pruebas: </p> <p> <code>def test_add_contact_route(self):<br /> response = self.client_stub.get('/add/')<br /> self.assertEqual(response.status_code, 200)<br /> </code> </p> <p> Debe ver este error cuando RAN: AssertionError: 404 = 200 </p> <p> Update “urls.py”: </p> <p> <code>url(r'^add/$', add),<br /> </code> </p> <p> Update “views.py”: </p> <p> <code>def add(request):<br /> person_form = ContactForm()<br /> return render(request, 'add.html', {'person_form' : person_form}, context_instance = RequestContext(request))<br /> </code> </p> <p> Hacer Asegúrese de añadir la siguiente importación: </p> <p> <code>from user_contacts.new_contact_form import ContactForm<br /> </code> </p> <p> Crear un nuevo archivo llamado new_contact_form.py y agregue el siguiente código: </p> <p> <code>import re<br /> from django import forms<br /> from django.core.exceptions import ValidationError<br /> from user_contacts.models import Person, Phone</p> <p>class ContactForm(forms.Form):<br /> first_name = forms.CharField(max_length=30)<br /> last_name = forms.CharField(max_length=30)<br /> email = forms.EmailField(required=False)<br /> address = forms.CharField(widget=forms.Textarea, required=False)<br /> city = forms.CharField(required=False)<br /> state = forms.CharField(required=False)<br /> country = forms.CharField(required=False)<br /> number = forms.CharField(max_length=10)</p> <p> def save(self):<br /> if self.is_valid():<br /> data = self.cleaned_data<br /> person = Person.objects.create(first_name=data.get('first_name'), last_name=data.get('last_name'),<br /> email=data.get('email'), address=data.get('address'), city=data.get('city'), state=data.get('state'),<br /> country=data.get('country'))<br /> phone = Phone.objects.create(person=person, number=data.get('number'))<br /> return phone<br /> </code> </p> <p> Añadir “add.html” en el directorio de plantillas: </p> <p> <code><!DOCTYPE html><br /> <html><br /> <head><br /> <title>Welcome.<itle><br /> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link href="http:/<br />etdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" rel="stylesheet" media="screen"></p> <style> .container { padding: 50px; } </style> <p></head><br /> <body></p> <div class="container"> <h1>Add Contact</h1> <p></p> <form action="/create" method ="POST" role="form"> {% csrf\_token %}<br /> {{ person_\_form.as\_p }}<br /> {{ phone\_form.as\_p }}<br /> <input type ="submit" name ="Submit" class="btn btn-default" value ="Add"><br /> </form> <p> <a href="/">Return Home</a> </div> <p> <script src="http://code.jquery.com/jquery-1.10.2.min.js"></script><br /> <script src="http:/<br />etdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script><br /> </body><br /> </html><br /> </code> </p> <p> ¿pasa? Debería. Si no es así, refactor. </p> <h3> Validación </h3> <p> Ahora que hemos terminado de probar las Vistas, vamos a añadir la validación de la forma. Pero primero tenemos que escribir una prueba. ¡Sorpresa! </p> <p> Crear un nuevo archivo llamado “test_validator.py” dentro del directorio “pruebas” y añadir el siguiente código: </p> <p> <code>from django.core.exceptions import ValidationError<br /> from django.test import TestCase<br /> from user_contacts.validators import validate_number, validate_string</p> <p> class ValidatorTest(TestCase):<br /> def test_string_is_invalid_if_contains_numbers_or_special_characters(self):<br /> with self.assertRaises(ValidationError):<br /> validate_string('@test')<br /> validate_string('tester#')<br /> def test_number_is_invalid_if_contains_any_character_except_digits(self):<br /> with self.assertRaises(ValidationError):<br /> validate_number('123ABC')<br /> validate_number('75431#')<br /> </code> </p> <p> Antes de ejecutar el conjunto de pruebas, se puede adivinar lo que podría suceder? <em> Consejo: Ponga mucha atención a las importaciones en el código de seguridad. </em> Usted debe obtener el siguiente error porque no tenemos un archivo “validators.py”: </p> <p> <code>ImportError: cannot import name validate_string<br /> </code> </p> <p> En otras palabras, estamos probando la lógica en un archivo de validación que no existe todavía. </p> <p> Añadir un nuevo archivo llamado “validators.py” al directorio user_contacts: </p> <p> <code>import re<br /> from django.core.exceptions import ValidationError</p> <p>def validate_string(string):<br /> if re.search('^[A-Za-z]+$', string) is None:<br /> raise ValidationError('Invalid')</p> <p>def validate_number(value):<br /> if re.search('^[0-9]+$', value) is None:<br /> raise ValidationError('Invalid')<br /> </code> </p> <p> ejecutar el banco de prueba de nuevo. Cinco ahora debe pasar: </p> <p> <code>Ran 5 tests in 0.019s</p> <p>OK<br /> </code> </p> <h3> Crear contacto </h3> <p> Dado que hemos añadido la validación, que queremos poner a prueba para asegurarse de que los validadores trabajan en el área de administración, por lo que la actualización “test_views.py”: pruebas </p> <p> <code>from django.template.loader import render_to_string<br /> from django.test import TestCase, Client<br /> from user_contacts.models import Person, Phone<br /> from user_contacts.views import *</p> <p>class ViewTest(TestCase):</p> <p> def setUp(self):<br /> self.client_stub = Client()<br /> self.person = Person(first_name = 'TestFirst',last_name = 'TestLast')<br /> self.person.save()<br /> self.phone = Phone(person = self.person,number = '7778889999')<br /> self.phone.save()</p> <p> def test_view_home_route(self):<br /> response = self.client_stub.get('/')<br /> self.assertEquals(response.status_code, 200)</p> <p> def test_view_contacts_route(self):<br /> response = self.client_stub.get('/all/')<br /> self.assertEquals(response.status_code, 200)</p> <p> def test_add_contact_route(self):<br /> response = self.client_stub.get('/add/')<br /> self.assertEqual(response.status_code, 200)</p> <p> def test_create_contact_successful_route(self):<br /> response = self.client_stub.post('/create',data = {'first_name' : 'testFirst', 'last_name':'tester', 'email':'test@tester.com', 'address':'1234 nowhere', 'city':'far away', 'state':'CO', 'country':'USA', 'number':'987654321'})<br /> self.assertEqual(response.status_code, 302)</p> <p> def test_create_contact_unsuccessful_route(self):<br /> response = self.client_stub.post('/create',data = {'first_name' : 'tester_first_n@me', 'last_name':'test', 'email':'tester@test.com', 'address':'5678 everywhere', 'city':'far from here', 'state':'CA', 'country':'USA', 'number':'987654321'})<br /> self.assertEqual(response.status_code, 200)</p> <p> def tearDown(self):<br /> self.phone.delete()<br /> self.person.delete()<br /> </code> </p> <p> Dos fallara. </p> <p> Lo que hay que hacer con el fin de obtener esta prueba a pasar? Bueno, en primer lugar hay que agregar una función a los puntos de vista que permiten agregar información a la base de datos. </p> <p> Agregar ruta: </p> <p> <code>url(r'^create$', create),<br /> </code> </p> <p> Update “views.py”: </p> <p> <code>def create(request):<br /> form = ContactForm(request.POST)<br /> if form.is_valid():<br /> form.save()<br /> return HttpResponseRedirect('all/')<br /> return render(<br /> request, 'add.html', {'person_form' : form},<br /> context_instance=RequestContext(request))<br /> </code> </p> <p> prueba de nuevo: </p> <p> <code>$ python manage.py test user_contacts<br /> </code> </p> <p> Esta vez sólo una prueba debe fallar – AssertionError: 302 = 200 – porque tratamos de agregar datos que no deberían haber pasado los validadores, pero lo hicieron. En otras palabras, tenemos que actualizar el archivo “models.py” así como la forma para tomar esas validadores en cuenta. </p> <p> Update “models.py”: </p> <p> <code>from django.db import models<br /> from user_contacts.validators import validate_string, validate_number</p> <p>class Person(models.Model):<br /> first_name = models.CharField(max_length = 30, validators = [validate_string])<br /> last_name = models.CharField(max_length = 30, validators = [validate_string])<br /> email = models.EmailField(null = True, blank = True)<br /> address = models.TextField(null = True, blank = True)<br /> city = models.CharField(max_length = 15, null = True,blank = True)<br /> state = models.CharField(max_length = 15, null = True, blank = True, validators = [validate_string])<br /> country = models.CharField(max_length = 15, null = True, blank = True)</p> <p> def __unicode__(self):<br /> return self.last_name +", "+ self.first_name</p> <p>class Phone(models.Model):<br /> person = models.ForeignKey('Person')<br /> number = models.CharField(max_length=10, validators = [validate_number])</p> <p> def __unicode__(self):<br /> return self.number<br /> </code> </p> <p> Eliminar la base de datos actual, “db.sqlite3”, y volver a sincronizar la base de datos: Configuración </p> <p> <code>$ python manage.py syncdb<br /> </code> </p> <p> un usuario administrador de nuevo. </p> <p> actualización new_contact_form.py mediante la adición de validación: </p> <p> <code>import re<br /> from django import forms<br /> from django.core.exceptions import ValidationError<br /> from user_contacts.models import Person, Phone<br /> from user_contacts.validators import validate_string, validate_number</p> <p>class ContactForm(forms.Form):<br /> first_name = forms.CharField(max_length=30, validators = [validate_string])<br /> last_name = forms.CharField(max_length=30, validators = [validate_string])<br /> email = forms.EmailField(required=False)<br /> address = forms.CharField(widget=forms.Textarea, required=False)<br /> city = forms.CharField(required=False)<br /> state = forms.CharField(required=False, validators = [validate_string])<br /> country = forms.CharField(required=False)<br /> number = forms.CharField(max_length=10, validators = [validate_number])</p> <p> def save(self):<br /> if self.is_valid():<br /> data = self.cleaned_data<br /> person = Person.objects.create(first_name=data.get('first_name'), last_name=data.get('last_name'),<br /> email=data.get('email'), address=data.get('address'), city=data.get('city'), state=data.get('state'),<br /> country=data.get('country'))<br /> phone = Phone.objects.create(person=person, number=data.get('number'))<br /> return phone<br /> </code> </p> <p> Ejecutar las pruebas de nuevo. 7 debe pasar. </p> <p> Ahora, desviándose de TDD por un minuto, quiero añadir una prueba adicional para la validación de prueba en el lado del cliente. Así que añadir test_contact_form.py: </p> <p> <code>from django.test import TestCase<br /> from user_contacts.models import Person<br /> from user_contacts.new_contact_form import ContactForm</p> <p>class TestContactForm(TestCase):<br /> def test_if_valid_contact_is_saved(self):<br /> form = ContactForm({'first_name':'test', 'last_name':'test','number':'9999900000'})<br /> contact = form.save()<br /> self.assertEqual(contact.person.first_name, 'test')<br /> def test_if_invalid_contact_is_not_saved(self):<br /> form = ContactForm({'first_name':'tes&t', 'last_name':'test','number':'9999900000'})<br /> contact = form.save()<br /> self.assertEqual(contact, None)<br /> </code> </p> <p> Ejecutar el paquete de pruebas. Todas las 9 pruebas deben pasar ahora. ¡Hurra! Ahora comprometerse. Pruebas funcionales </p> <h2> Redux </h2> <p> con la unidad de pruebas realizadas, que ahora puede añadir una prueba funcional para asegurar que la aplicación se ejecuta correctamente. Con suerte, con las unidades de prueba que pasa, deberíamos tener ningún problema con la prueba funcional. </p> <p> Añadir una nueva clase en el fichero “tests.py”: </p> <p> <code>class UserContactTest(LiveServerTestCase):</p> <p> def setUp(self):<br /> self.browser = webdriver.Firefox()<br /> self.browser.implicitly_wait(3)</p> <p> def tearDown(self):<br /> self.browser.quit()</p> <p> def test_create_contact(self):<br /> # user opens web browser, navigates to home page<br /> self.browser.get(self.live_server_url + '/')<br /> # user clicks on the Persons link<br /> add_link = self.browser.find_elements_by_link_text('Add Contact')<br /> add_link[0].click()<br /> # user fills out the form<br /> self.browser.find_element_by_name('first_name').send_keys("Michael")<br /> self.browser.find_element_by_name('last_name').send_keys("Herman")<br /> self.browser.find_element_by_name('email').send_keys("michael@realpython.com")<br /> self.browser.find_element_by_name('address').send_keys("2227 Lexington Ave")<br /> self.browser.find_element_by_name('city').send_keys("San Francisco")<br /> self.browser.find_element_by_name('state').send_keys("CA")<br /> self.browser.find_element_by_name('country').send_keys("United States")<br /> self.browser.find_element_by_name('number').send_keys("4158888888")<br /> # user clicks the save button<br /> self.browser.find_element_by_css_selector("input[value='Add']").click()<br /> # the Person has been added<br /> body = self.browser.find_element_by_tag_name('body')<br /> self.assertIn('michael@realpython.com', body.text)</p> <p> def test_create_contact_error(self):<br /> # user opens web browser, navigates to home page<br /> self.browser.get(self.live_server_url + '/')<br /> # user clicks on the Persons link<br /> add_link = self.browser.find_elements_by_link_text('Add Contact')<br /> add_link[0].click()<br /> # user fills out the form<br /> self.browser.find_element_by_name('first_name').send_keys("test@")<br /> self.browser.find_element_by_name('last_name').send_keys("tester")<br /> self.browser.find_element_by_name('email').send_keys("test@tester.com")<br /> self.browser.find_element_by_name('address').send_keys("2227 Tester Ave")<br /> self.browser.find_element_by_name('city').send_keys("Tester City")<br /> self.browser.find_element_by_name('state').send_keys("TC")<br /> self.browser.find_element_by_name('country').send_keys("TCA")<br /> self.browser.find_element_by_name('number').send_keys("4158888888")<br /> # user clicks the save button<br /> self.browser.find_element_by_css_selector("input[value='Add']").click()<br /> body = self.browser.find_element_by_tag_name('body')<br /> self.assertIn('Invalid', body.text)<br /> </code> </p> <p> Ejecutar las pruebas funcionales: </p> <p> <code>$ python manage.py test ft<br /> </code> </p> <p> Aquí sólo estamos probando el código que escribimos y ya probado con pruebas unitarias desde la perspectiva del usuario final. Las cuatro pruebas deben pasar. </p> <p> Por último, vamos a asegurar que la validación ponemos en su lugar se aplica al panel de administración mediante la adición de la siguiente función a la clase AdminTest: </p> <p> <code>def test_create_contact_admin_raise_error(self):<br /> # # user opens web browser, navigates to admin page, and logs in<br /> self.browser.get(self.live_server_url + '/admin/')<br /> username_field = self.browser.find_element_by_name('username')<br /> username_field.send_keys('admin')<br /> password_field = self.browser.find_element_by_name('password')<br /> password_field.send_keys('admin')<br /> password_field.send_keys(Keys.RETURN)<br /> # user clicks on the Persons link<br /> persons_links = self.browser.find_elements_by_link_text('Persons')<br /> persons_links[0].click()<br /> # user clicks on the Add person link<br /> add_person_link = self.browser.find_element_by_link_text('Add person')<br /> add_person_link.click()<br /> # user fills out the form<br /> self.browser.find_element_by_name('first_name').send_keys("test@")<br /> self.browser.find_element_by_name('last_name').send_keys("tester")<br /> self.browser.find_element_by_name('email').send_keys("test@tester.com")<br /> self.browser.find_element_by_name('address').send_keys("2227 Tester Ave")<br /> self.browser.find_element_by_name('city').send_keys("Tester City")<br /> self.browser.find_element_by_name('state').send_keys("TC")<br /> self.browser.find_element_by_name('country').send_keys("TCA")<br /> # user clicks the save button<br /> self.browser.find_element_by_css_selector("input[value='Save']").click()<br /> body = self.browser.find_element_by_tag_name('body')<br /> self.assertIn('Invalid', body.text)<br /> </code> </p> <p> ejecutarlo. Cinco pruebas deben pasar. Y se comprometen Vamos a llamar a un día. Estructura </p> <p> prueba </p> <h2> </h2> <p> TDD es una poderosa herramienta y una parte integral del ciclo de desarrollo, ayudando a los desarrolladores de programas rompen en pequeñas porciones, legibles. Dichas porciones son mucho más fáciles de escribir ahora y cambiar más tarde. Además, tener una suite completa de los ensayos, que cubre todas las características de su base de código, ayuda a asegurar que las nuevas implementaciones de funciones no rompa el código existente. </p> <p> Dentro del proceso, las pruebas funcionales <strong> </strong> son pruebas de alto nivel, se centró en la <em> características </em> que los usuarios finales interactuar con él. </p> <p> Mientras tanto, Unidad <strong> prueba Las pruebas funcionales de apoyo </strong> en que ponen a prueba cada característica del código. Tenga en cuenta que la unidad <strong> prueba </strong> son mucho más fáciles de escribir, en general, proporcionar una mejor cobertura, y son más fáciles de depurar, ya que ponen a prueba sólo una característica a la vez. También se desarrollan mucho más rápido, así que asegúrese de probar sus pruebas de unidad más a menudo que sus pruebas funcionales. La toma del </p> <p> Let un vistazo a nuestra estructura de prueba para ver cómo nuestras pruebas unitarias apoyan las pruebas funcionales: </p> </p> <p> <img src="https://eltecnofilo.es/wp-content/uploads/2020/03/django-tdd-test-structure.6d04849a84ea.png"> </p> <h2> Conclusión </h2> <p> Felicidades. Lo haces a través. ¿Que sigue? </p> <p> primer lugar, usted puede haber notado que yo no 100% de seguimiento del proceso de TDD. Esta bien. La mayoría de los desarrolladores involucrados en TDD no siempre se adhieren a ella en cada situación individual. Hay momentos en los que debe desvía de ella con el fin de simplemente hacer las cosas – que es perfectamente bien. Si desea refactorizar una parte del código / proceso para adherirse plenamente al proceso de TDD, se puede. De hecho, puede ser una buena práctica. </p> <p> En segundo lugar, pensar en las pruebas que echaba de menos. La determinación de qué y cuándo prueba es difícil. Se necesita tiempo y mucha práctica para ser bueno en las pruebas en general. He dejado muchos espacios en blanco que tengo la intención de Revel en mi próximo post. Vea si usted puede encontrar estos y añadir pruebas. </p> <p> Por último, recuerda el último paso en el proceso de TDD? Refactorización. Este paso es vital, ya que ayuda a crear legible, código mantenible que no sólo se entiende ahora – pero en el futuro también. Cuando uno mira hacia atrás en su código, piense en las pruebas se pueden combinar. También, qué pruebas debe añadir para asegurar que todo el código escrito se prueba? Se podía comprobar valores nulos y / o autenticación del lado del servidor, por ejemplo. Usted debe refactorizar el código antes de pasar a escribir ningún código nuevo – lo que no lo hice por el bien de tiempo. Tal vez en otra entrada del blog? Pensar en lo mal código puede contaminar todo el proceso? </p> <p> Gracias por leer. Coge el código final en el repositorio aquí. Por favor, comentario a continuación con cualquier pregunta. </p> </div><!-- .entry-content --> </div><!-- .post-inner --> <div class="section-inner"> </div><!-- .section-inner --> </article><!-- .post --> <hr class="post-separator styled-separator is-style-wide section-inner" aria-hidden="true" /> <article class="post-6495 post type-post status-publish format-standard has-post-thumbnail hentry category-python" id="post-6495"> <header class="entry-header has-text-align-center"> <div class="entry-header-inner section-inner medium"> <div class="entry-categories"> <span class="screen-reader-text">Categorías</span> <div class="entry-categories-inner"> <a href="https://eltecnofilo.es/category/python/" rel="category tag">Python</a> </div><!-- .entry-categories-inner --> </div><!-- .entry-categories --> <h2 class="entry-title heading-size-1"><a href="https://eltecnofilo.es/introduccion-a-los-canales-de-django/">Introducción a los canales de Django</a></h2> <div class="post-meta-wrapper post-meta-single post-meta-single-top"> <ul class="post-meta"> <li class="post-author meta-wrapper"> <span class="meta-icon"> <span class="screen-reader-text">Autor de la entrada</span> <svg class="svg-icon" aria-hidden="true" role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" width="18" height="20" viewBox="0 0 18 20"><path fill="" d="M18,19 C18,19.5522847 17.5522847,20 17,20 C16.4477153,20 16,19.5522847 16,19 L16,17 C16,15.3431458 14.6568542,14 13,14 L5,14 C3.34314575,14 2,15.3431458 2,17 L2,19 C2,19.5522847 1.55228475,20 1,20 C0.44771525,20 0,19.5522847 0,19 L0,17 C0,14.2385763 2.23857625,12 5,12 L13,12 C15.7614237,12 18,14.2385763 18,17 L18,19 Z M9,10 C6.23857625,10 4,7.76142375 4,5 C4,2.23857625 6.23857625,0 9,0 C11.7614237,0 14,2.23857625 14,5 C14,7.76142375 11.7614237,10 9,10 Z M9,8 C10.6568542,8 12,6.65685425 12,5 C12,3.34314575 10.6568542,2 9,2 C7.34314575,2 6,3.34314575 6,5 C6,6.65685425 7.34314575,8 9,8 Z" /></svg> </span> <span class="meta-text"> Por <a href="https://eltecnofilo.es/author/admin/">admin</a> </span> </li> <li class="post-date meta-wrapper"> <span class="meta-icon"> <span class="screen-reader-text">Fecha de la entrada</span> <svg class="svg-icon" aria-hidden="true" role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" width="18" height="19" viewBox="0 0 18 19"><path fill="" d="M4.60069444,4.09375 L3.25,4.09375 C2.47334957,4.09375 1.84375,4.72334957 1.84375,5.5 L1.84375,7.26736111 L16.15625,7.26736111 L16.15625,5.5 C16.15625,4.72334957 15.5266504,4.09375 14.75,4.09375 L13.3993056,4.09375 L13.3993056,4.55555556 C13.3993056,5.02154581 13.0215458,5.39930556 12.5555556,5.39930556 C12.0895653,5.39930556 11.7118056,5.02154581 11.7118056,4.55555556 L11.7118056,4.09375 L6.28819444,4.09375 L6.28819444,4.55555556 C6.28819444,5.02154581 5.9104347,5.39930556 5.44444444,5.39930556 C4.97845419,5.39930556 4.60069444,5.02154581 4.60069444,4.55555556 L4.60069444,4.09375 Z M6.28819444,2.40625 L11.7118056,2.40625 L11.7118056,1 C11.7118056,0.534009742 12.0895653,0.15625 12.5555556,0.15625 C13.0215458,0.15625 13.3993056,0.534009742 13.3993056,1 L13.3993056,2.40625 L14.75,2.40625 C16.4586309,2.40625 17.84375,3.79136906 17.84375,5.5 L17.84375,15.875 C17.84375,17.5836309 16.4586309,18.96875 14.75,18.96875 L3.25,18.96875 C1.54136906,18.96875 0.15625,17.5836309 0.15625,15.875 L0.15625,5.5 C0.15625,3.79136906 1.54136906,2.40625 3.25,2.40625 L4.60069444,2.40625 L4.60069444,1 C4.60069444,0.534009742 4.97845419,0.15625 5.44444444,0.15625 C5.9104347,0.15625 6.28819444,0.534009742 6.28819444,1 L6.28819444,2.40625 Z M1.84375,8.95486111 L1.84375,15.875 C1.84375,16.6516504 2.47334957,17.28125 3.25,17.28125 L14.75,17.28125 C15.5266504,17.28125 16.15625,16.6516504 16.15625,15.875 L16.15625,8.95486111 L1.84375,8.95486111 Z" /></svg> </span> <span class="meta-text"> <a href="https://eltecnofilo.es/introduccion-a-los-canales-de-django/">marzo 5, 2020</a> </span> </li> <li class="post-comment-link meta-wrapper"> <span class="meta-icon"> <svg class="svg-icon" aria-hidden="true" role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" width="19" height="19" viewBox="0 0 19 19"><path d="M9.43016863,13.2235931 C9.58624731,13.094699 9.7823475,13.0241935 9.98476849,13.0241935 L15.0564516,13.0241935 C15.8581553,13.0241935 16.5080645,12.3742843 16.5080645,11.5725806 L16.5080645,3.44354839 C16.5080645,2.64184472 15.8581553,1.99193548 15.0564516,1.99193548 L3.44354839,1.99193548 C2.64184472,1.99193548 1.99193548,2.64184472 1.99193548,3.44354839 L1.99193548,11.5725806 C1.99193548,12.3742843 2.64184472,13.0241935 3.44354839,13.0241935 L5.76612903,13.0241935 C6.24715123,13.0241935 6.63709677,13.4141391 6.63709677,13.8951613 L6.63709677,15.5301903 L9.43016863,13.2235931 Z M3.44354839,14.766129 C1.67980032,14.766129 0.25,13.3363287 0.25,11.5725806 L0.25,3.44354839 C0.25,1.67980032 1.67980032,0.25 3.44354839,0.25 L15.0564516,0.25 C16.8201997,0.25 18.25,1.67980032 18.25,3.44354839 L18.25,11.5725806 C18.25,13.3363287 16.8201997,14.766129 15.0564516,14.766129 L10.2979143,14.766129 L6.32072889,18.0506004 C5.75274472,18.5196577 4.89516129,18.1156602 4.89516129,17.3790323 L4.89516129,14.766129 L3.44354839,14.766129 Z" /></svg> </span> <span class="meta-text"> <a href="https://eltecnofilo.es/introduccion-a-los-canales-de-django/#respond">No hay comentarios<span class="screen-reader-text"> en Introducción a los canales de Django</span></a> </span> </li> </ul><!-- .post-meta --> </div><!-- .post-meta-wrapper --> </div><!-- .entry-header-inner --> </header><!-- .entry-header --> <figure class="featured-media"> <div class="featured-media-inner section-inner medium"> <img width="1200" height="150" src="https://eltecnofilo.es/wp-content/uploads/2020/03/fc3dcce3b30783158d89077cf5a8810e-1200x150.jpeg" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="" srcset="https://eltecnofilo.es/wp-content/uploads/2020/03/fc3dcce3b30783158d89077cf5a8810e-1200x150.jpeg 1200w, https://eltecnofilo.es/wp-content/uploads/2020/03/fc3dcce3b30783158d89077cf5a8810e-300x38.jpeg 300w, https://eltecnofilo.es/wp-content/uploads/2020/03/fc3dcce3b30783158d89077cf5a8810e-1024x128.jpeg 1024w, https://eltecnofilo.es/wp-content/uploads/2020/03/fc3dcce3b30783158d89077cf5a8810e-768x96.jpeg 768w, https://eltecnofilo.es/wp-content/uploads/2020/03/fc3dcce3b30783158d89077cf5a8810e.jpeg 1440w" sizes="(max-width: 1200px) 100vw, 1200px" /> </div><!-- .featured-media-inner --> </figure><!-- .featured-media --> <div class="post-inner thin "> <div class="entry-content"> <p> </p> <p> Tabla de Contenidos </p> <ul> <li> Por qué TDD? Configuración </li> <li> primera prueba </li> <li> Django </li> <li> de control de versiones </li> <li> funcional TestsAdmin LoginSetup los contactos Configuración de aplicaciones </li> <li> Admin Login </li> <li> los contactos de la unidad de aplicaciones </li> <li> TestsViewsMain viewall Contactos ViewAdd Contacto ViewValidationCreate Contacto </li> <li> Vistas </li> <li> Vista principal </li> <li> Todos contactos Ver </li> <li> agregar contacto Ver </li> <li> Validación </li> <li> Crear contacto </li> <li> pruebas funcionales Estructura Redux </li> <p> prueba </p> <li> </li> <li> Conclusión </li> </ul> <ul> <li> admin Login </li> <li> de configuración la aplicación contactos </li> </ul> <ul> <li> Vistas </li> <li> Vista principal </li> <li> Todos Ver contactos </li> <li> agregar contacto Ver </li> <li> Validación </li> <li> Crear contacto </li> </ul> <p> <img src="https://eltecnofilo.es/wp-content/uploads/2020/03/fc3dcce3b30783158d89077cf5a8810e.jpeg"> </p> <p> Última actualización: – (! vic gracias) </p> <ul> <li> 29/01/2014 código actualizado para la forma </li> <li> 12/29/2013 – reestructurado todo entrada de blog </li> </ul> <p> prueba de conducción del Developme nt (TDD) es un ciclo de desarrollo iterativo que hace hincapié en escribir pruebas automatizadas antes de escribir el código real. </p> <p> El proceso es simple: </p> </p> <p> <img src="https://files.realpython.com/mediadd.0904607f8ec9.png"> </p> <h2> Por qué TDD? </h2> <p> Con TDD, aprenderá a romper el código en trozos lógicos, de fácil comprensión, lo que ayuda a garantizar la exactitud de código. </p> <p> Esto es importante porque es difícil a- </p> <p> TDD ayuda a solucionar estos problemas. Que no garantiza en absoluto que su código estará libre de error; Sin embargo, usted va a escribir mejor código, que se traduce en una mejor comprensión del código. Esto en sí mismo le ayudará con la eliminación de errores y, al menos, usted será capaz de errores de dirección mucho más fácil. </p> <p> TDD es prácticamente un estándar de la industria también. charla </p> <p> suficiente. Vamos a llegar a un código. </p> <p> Para este tutorial, vamos a ser la creación de una aplicación de contactos almacén del usuario. </p> <p> Nota: Este tutorial asume que está ejecutando un entorno basado en Unix – por ejemplo, Mac OS X, Linux recta, o Linux VM a través de Windows. También estaré usando Sublime 2 como mi editor de texto. También, asegúrese de que haya completado el tutorial oficial de Django y tener un conocimiento básico del lenguaje Python. <strong> Además, en este primer post, sin embargo, no vamos a entrar en algunas de las nuevas herramientas disponibles en Django 1.6. Este post establece las bases para posteriores mensajes que tienen que ver con diferentes formas de pruebas. </strong> </p> <h2> primera prueba </h2> <p> Antes de hacer nada tenemos que configura por primera vez una prueba. Para esta prueba sólo queremos hacer que Django es configurado correctamente. Vamos a estar usando una prueba de funcionamiento para esto – lo que vamos a estar explicamos más abajo. </p> <p> Crear un nuevo directorio para su proyecto: </p> <p> <code>$ mkdir django-tdd<br /> $ cd django-tdd<br /> </code> </p> <p> configuración Ahora un nuevo directorio para incluir sus pruebas funcionales: </p> <p> <code>$ mkdir ft<br /> $ cd ft<br /> </code> </p> <p> Crear un nuevo archivo llamado “tests.py” y añadir el siguiente código: </p> <p> <code>from selenium import webdriver</p> <p>browser = webdriver.Firefox()<br /> browser.get('http://localhost:8000/')</p> <p>body = browser.find_element_by_tag_name('body')<br /> assert 'Django' in body.text</p> <p>browser.quit()<br /> </code> </p> <p> Ahora ejecute el prueba: </p> <p> <code>$ python tests.py<br /> </code> </p> <p> Asegúrese de que tiene instalado el selenio – pip instalar el selenio </p> <p> debería ver FireFox pop-up y tratar de navegar a http: // localhost: 8000 /. En su terminal debería ver: </p> <p> <code>Traceback (most recent call last):<br /> File "tests.py", line 7, in <module><br /> assert 'Django' in body.text<br /> AssertionError<br /> </code> </p> <p> Felicidades! Usted escribió su primera prueba falla. </p> <p> Ahora vamos a escribir código sólo lo suficiente como para hacerlo pasar, que simplemente equivale a la creación de un entorno de desarrollo de Django. Configuración </p> <h2> Django </h2> <p> Activar un virtualenv: </p> <p> <code>$ cd ..<br /> $ virtualenv --no-site-packages env<br /> $ source env/bin/activate<br /> </code> </p> <p> Instalar Django y la configuración de un proyecto: </p> <p> <code>$ pip install django==1.6.1<br /> $ django-admin.py startproject contacts<br /> </code> </p> <p> Su estructura actual proyecto debe tener este aspecto: </p> <p> <code>├── contacts<br /> │   ├── contacts<br /> │   │   ├── __init__.py<br /> │   │   ├── settings.py<br /> │   │   ├── urls.py<br /> │   │   └── wsgi.py<br /> │   └── manage.py<br /> └── ft<br /> └── tests.py<br /> </code> </p> <p> Instalar Selenio: </p> <p> <code>$ pip install selenium==2.39.0<br /> </code> </p> <p> ejecutar el servidor: </p> <p> <code>$ cd contacts<br /> $ python manage.py runserver<br /> </code> </p> <p> A continuación, abrir una nueva ventana en su terminal, navegue hasta el directorio “pies”, a continuación, ejecutar la prueba: </p> <p> <code>$ python tests.py<br /> </code> </p> <p> debería ver la ventana de Firefox navegar a http: // localhost: 8000 / nuevo. Esta vez no debe haber errores. Agradable. Que acaba de pasar su primera prueba! </p> <p> Ahora, la creación de nuestro entorno de desarrollo acabado de let. Control de </p> <h2> Versión </h2> <p> En primer lugar, añadir un “.gitignore” e incluir el código siguiente en el archivo: </p> <p> <code>.Python<br /> env<br /> bin<br /> lib<br /> include<br /> .DS_Store<br /> .pyc<br /> </code> </p> <p> Ahora crear un repositorio Git y comprometerse: </p> <p> <code>$ git init<br /> $ git add .<br /> $ git commit -am "initial"<br /> </code> </p> <p> Con la configuración del proyecto, vamos a dar un paso atrás y discutir funcional pruebas. </p> <h2> pruebas funcionales </h2> <p> nos acercamos a la primera prueba a través de selenio a través de pruebas funcionales. Estas pruebas permiten a impulsar el navegador web como si fuéramos el usuario final, para ver cómo la aplicación de hecho <em> funciones </em>. Dado que estas pruebas siguen el comportamiento del usuario final – también llamado una historia de usuario – se trata de la prueba de una serie de características, en lugar de una sola función – que es más apropiado para pruebas unitarias. importante señalar que cuando se prueba código que no has escrito, usted debe comenzar con las pruebas funcionales de <strong> Se. </strong> Dado que estamos probando en esencia código de Django, pruebas funcionales son el camino correcto a seguir. </p> <p> Otra forma de pensar funcional vs pruebas unitarias es que las pruebas funcionales se centran en las pruebas de la aplicación desde el exterior, desde la perspectiva del usuario, mientras que las pruebas unitarias se centran en la aplicación desde el interior, desde la perspectiva del desarrollador. </p> <p> Esto hará mucho más sentido en la práctica. </p> <p> Antes de continuar, vamos a reestructurar nuestro entorno de pruebas para hacer más fácil la prueba. </p> <p> En primer lugar, vamos a volver a escribir la primera prueba en el archivo “tests.py”: </p> <p> <code>from selenium import webdriver<br /> from selenium.webdriver.common.keys import Keys</p> <p>from django.test import LiveServerTestCase</p> <p>class AdminTest(LiveServerTestCase):</p> <p> def setUp(self):<br /> self.browser = webdriver.Firefox()</p> <p> def tearDown(self):<br /> self.browser.quit()</p> <p> def test_admin_site(self):<br /> # user opens web browser, navigates to admin page<br /> self.browser.get(self.live_server_url + '/admin/')<br /> body = self.browser.find_element_by_tag_name('body')<br /> self.assertIn('Django administration', body.text)<br /> </code> </p> <p> continuación, se ejecuta: </p> <p> <code>$ python manage.py test ft<br /> </code> </p> <p> Se debe pasar: </p> <p> <code>----------------------------------------------------------------------<br /> Ran 1 test in 3.304s</p> <p>OK<br /> </code> </p> <p> Felicidades! </p> <p> Antes de continuar, vamos a ver lo que está pasando aquí. Si todo ha ido bien debería pasar. También debe ver FireFox abierta y pasar por el proceso que se indica en el ensayo con el tearDown funciones setup () () y. La prueba en sí es simplemente probando si el “admin /” (self.browser.get (self.live_server_url + ‘/ admin /’) página se puede encontrar y que las palabras “administración Django” están presentes en el cuerpo de la etiqueta. </p> <p> Confirmémoslo </p> <p> ejecutar el servidor:. </p> <p> <code>$ python manage.py runserver<br /> </code> </p> <p> a continuación, vaya a http: // localhost: 8000 / admin / en su navegador y debería ver: </p> </p> <p> <img src="https://eltecnofilo.es/wp-content/uploads/2020/03/django-tdd-admin.20f4656c76f9.png"> </p> <p> Nos puede confirmar que la prueba está funcionando correctamente con sólo las pruebas de lo que no debía actualizar la última línea de la prueba a:.. </p> <p> <code>self.assertIn('administration Django', body.text)<br /> </code> </p> <p> ejecutarlo de nuevo debería ver el siguiente error (que se espera, por supuesto):.. </p> <p> <code>AssertionError: 'administration Django' not found in u'Django administration\nUsername:\nPassword:\n '<br /> </code> </p> <p> corregir el test de nuevo Confirmar la código. </p> <p> por último, ¿se fijaron que empezamos el nombre de la función para la prueba real se inició con test_. Esto es para que el corredor de prueba Django puede encontrar la prueba. En otras palabras, cualquier función que comienza con test_ serán tratados como una prueba por el corredor de prueba. </p> <h3> administración Iniciar sesión </h3> <p> A continuación, la prueba nos dejó para asegurarse de que el usuario puede iniciar sesión en el sitio de administración. </p> <p> actualización test_admin_site la función en “tests.py”: </p> <p> <code>def test_admin_site(self):<br /> # user opens web browser, navigates to admin page<br /> self.browser.get(self.live_server_url + '/admin/')<br /> body = self.browser.find_element_by_tag_name('body')<br /> self.assertIn('Django administration', body.text)<br /> # users types in username and passwords and presses enter<br /> username_field = self.browser.find_element_by_name('username')<br /> username_field.send_keys('admin')<br /> password_field = self.browser.find_element_by_name('password')<br /> password_field.send_keys('admin')<br /> password_field.send_keys(Keys.RETURN)<br /> # login credentials are correct, and the user is redirected to the main admin page<br /> body = self.browser.find_element_by_tag_name('body')<br /> self.assertIn('Site administration', body.text)<br /> </code> </p> <p> Por lo tanto – </p> <ul> <li> find_element_by_name – se utiliza para la localización de los campos de entrada send_keys </li> <li> – envía las pulsaciones de teclado </li> </ul> <p> Ejecutar la prueba. Usted debe ver este error: </p> <p> <code>AssertionError: 'Site administration' not found in u'Django administration\nPlease enter the correct username and password for a staff account. Note that both fields may be case-sensitive.\nUsername:\nPassword:\n '<br /> </code> </p> <p> Esta fracasado porque no tenemos una configuración de usuario admin. Este es un fallo esperado, lo cual es bueno. En otras palabras, sabíamos que iba a fallar – que hace que sea mucho más fácil de solucionar. </p> <p> sincronización de la base de datos: Configuración </p> <p> <code>$ python manage.py syncdb<br /> </code> </p> <p> un usuario administrador. </p> <p> prueba </p> <p> nuevo. Debe volver a fallar. ¿Por qué? Django crea una copia de la base de datos cuando las pruebas son corrió así que de esa manera las pruebas no afectan a la base de datos de producción. </p> <p> Hay que configurar un accesorio, que es un archivo que contiene los datos que quiera cargar en la base de datos de prueba: las credenciales de inicio de sesión. Para ello, ejecute estos comandos para volcar la información de usuario administrador de la base de datos para el accesorio: </p> <p> <code>$ mkdir ft/fixtures<br /> $ python manage.py dumpdata auth.User --indent=2 > ft/fixtures/admin.json<br /> </code> </p> <p> Ahora actualizar la clase AdminTest: </p> <p> <code>class AdminTest(LiveServerTestCase):</p> <p> # load fixtures<br /> fixtures = ['admin.json']</p> <p> def setUp(self):<br /> self.browser = webdriver.Firefox()</p> <p> def tearDown(self):<br /> self.browser.quit()</p> <p> def test_admin_site(self):<br /> # user opens web browser, navigates to admin page<br /> self.browser.get(self.live_server_url + '/admin/')<br /> body = self.browser.find_element_by_tag_name('body')<br /> self.assertIn('Django administration', body.text)<br /> # users types in username and passwords and presses enter<br /> username_field = self.browser.find_element_by_name('username')<br /> username_field.send_keys('admin')<br /> password_field = self.browser.find_element_by_name('password')<br /> password_field.send_keys('admin')<br /> password_field.send_keys(Keys.RETURN)<br /> # login credentials are correct, and the user is redirected to the main admin page<br /> body = self.browser.find_element_by_tag_name('body')<br /> self.assertIn('Site administration', body.text)<br /> </code> </p> <p> Ejecutar la prueba. Debe pasar. </p> <p> Cada vez que una prueba es RAN, Django vuelca la base de datos de prueba. Entonces todos los accesorios especificados en el archivo “test.py” se cargan en la base de datos. Agregar un afirman más de </p> <p> Let. Actualización de la prueba de nuevo: </p> <p> <code>def test_admin_site(self):<br /> # user opens web browser, navigates to admin page<br /> self.browser.get(self.live_server_url + '/admin/')<br /> body = self.browser.find_element_by_tag_name('body')<br /> self.assertIn('Django administration', body.text)<br /> # users types in username and passwords and presses enter<br /> username_field = self.browser.find_element_by_name('username')<br /> username_field.send_keys('admin')<br /> password_field = self.browser.find_element_by_name('password')<br /> password_field.send_keys('admin')<br /> password_field.send_keys(Keys.RETURN)<br /> # login credentials are correct, and the user is redirected to the main admin page<br /> body = self.browser.find_element_by_tag_name('body')<br /> self.assertIn('Site administration', body.text)<br /> # user clicks on the Users link<br /> user_link = self.browser.find_elements_by_link_text('Users')<br /> user_link[0].click()<br /> # user verifies that user live@forever.com is present<br /> body = self.browser.find_element_by_tag_name('body')<br /> self.assertIn('live@forever.com', body.text)<br /> </code> </p> <p> ejecutarlo. Se debe fallar, porque necesitamos y otro usuario con el archivo de datos: </p> <p> <code>[<br /> {<br /> "pk": 1,<br /> "model": "auth.user",<br /> "fields": {<br /> "username": "admin",<br /> "first_name": "",<br /> "last_name": "",<br /> "is_active": true,<br /> "is_superuser": true,<br /> "is_staff": true,<br /> "last_login": "2013-12-29T03:49:13.545Z",<br /> "groups": [],<br /> "user_permissions": [],<br /> "password": "pbkdf2_sha256$12000$VtsgwjQ1BZ6u$zwnG+5E5cl8zOnghahArLHiMC6wGk06HXrlAijFFpSA=",<br /> "email": "ad@min.com",<br /> "date_joined": "2013-12-29T03:49:13.545Z"<br /> }<br /> },<br /> {<br /> "pk": 2,<br /> "model": "auth.user",<br /> "fields": {<br /> "username": "live",<br /> "first_name": "",<br /> "last_name": "",<br /> "is_active": true,<br /> "is_superuser": false,<br /> "is_staff": false,<br /> "last_login": "2013-12-29T03:49:13.545Z",<br /> "groups": [],<br /> "user_permissions": [],<br /> "password": "pbkdf2_sha256$12000$VtsgwjQ1BZ6u$zwnG+5E5cl8zOnghahArLHiMC6wGk06HXrlAijFFpSA=",<br /> "email": "live@forever.com",<br /> "date_joined": "2013-12-29T03:49:13.545Z"<br /> }<br /> }<br /> ]<br /> </code> </p> <p> Ejecutar de nuevo. Asegúrese de que su paso. Refactor la prueba si es necesario. Ahora pensar en lo demás que usted podría probar. Tal vez usted podría poner a prueba para asegurarse de que el usuario administrador puede agregar un usuario en el panel de administración. O tal vez una prueba para asegurarse de que alguien sin acceso de administrador no puede acceder al panel de administración. Escribir algunas pruebas más. Actualizar el código. Prueba de nuevo. Refactor si es necesario. </p> <p> A continuación, vamos a añadir la aplicación para añadir contactos. No se olvide de cometer! Configuración </p> <h3> la aplicación Contactos </h3> <p> empezar con una prueba. Agregue la siguiente función: </p> <p> <code>def test_create_contact_admin(self):<br /> self.browser.get(self.live_server_url + '/admin/')<br /> username_field = self.browser.find_element_by_name('username')<br /> username_field.send_keys('admin')<br /> password_field = self.browser.find_element_by_name('password')<br /> password_field.send_keys('admin')<br /> password_field.send_keys(Keys.RETURN)<br /> # user verifies that user_contacts is present<br /> body = self.browser.find_element_by_tag_name('body')<br /> self.assertIn('User_Contacts', body.text)<br /> </code> </p> <p> ejecutar el banco de prueba de nuevo. Debería ver la siguiente de errores </p> <p> <code>AssertionError: 'User_Contacts' not found in u'Django administration\nWelcome, admin. Change password / Log out\nSite administration\nAuth\nGroups\nAdd\nChange\nUsers\nAdd\nChange\nRecent Actions\nMy Actions\nNone available'<br /> </code> </p> <ul> <li> que se espera. </li> </ul> <p> Ahora, escribir código sólo lo suficiente para que esto pase. </p> <p> Crear la App: </p> <p> <code>$ python manage.py startapp user_contacts<br /> </code> </p> <p> Añadir al archivo “settings.py”: </p> <p> <code>INSTALLED_APPS = (<br /> 'django.contrib.admin',<br /> 'django.contrib.auth',<br /> 'django.contrib.contenttypes',<br /> 'django.contrib.sessions',<br /> 'django.contrib.messages',<br /> 'django.contrib.staticfiles',<br /> 'ft',<br /> 'user_contacts',<br /> )<br /> </code> </p> <p> Dentro del archivo “admin.py” en el directorio user_contacts añadir el siguiente código: </p> <p> <code>from user_contacts.models import Person, Phone<br /> from django.contrib import admin</p> <p>admin.site.register(Person)<br /> admin.site.register(Phone)<br /> </code> </p> <p> Su estructura del proyecto debe parecerse esto: </p> <p> <code>├── user_contacts<br /> │   ├── __init__.py<br /> │   ├── admin.py<br /> │   ├── models.py<br /> │   ├── tests.py<br /> │   └── views.py<br /> ├── contacts<br /> │   ├── __init__.py<br /> │   ├── settings.py<br /> │   ├── urls.py<br /> │   └── wsgi.py<br /> ├── ft<br /> │   ├── __init__.py<br /> │   ├── fixtures<br /> │   │   └── admin.json<br /> │   └── tests.py<br /> └── manage.py<br /> </code> </p> <p> Update “models.py”: </p> <p> <code>from django.db import models</p> <p>class Person(models.Model):<br /> first_name = models.CharField(max_length = 30)<br /> last_name = models.CharField(max_length = 30)<br /> email = models.EmailField(null = True, blank = True)<br /> address = models.TextField(null = True, blank = True)<br /> city = models.CharField(max_length = 15, null = True,blank = True)<br /> state = models.CharField(max_length = 15, null = True, blank = True)<br /> country = models.CharField(max_length = 15, null = True, blank = True)</p> <p> def __unicode__(self):<br /> return self.last_name +", "+ self.first_name</p> <p>class Phone(models.Model):<br /> person = models.ForeignKey('Person')<br /> number = models.CharField(max_length=10)</p> <p> def __unicode__(self):<br /> return self.number<br /> </code> </p> <p> Ejecutar la prueba de nuevo ahora. Ahora debería ver: Ir de </p> <p> <code>Ran 2 tests in 11.730s</p> <p>OK<br /> </code> </p> <p> Let adelante y añadir a la prueba para asegurarse de que el administrador puede agregar datos: </p> <p> <code># user clicks on the Persons link<br /> persons_links = self.browser.find_elements_by_link_text('Persons')<br /> persons_links[0].click()<br /> # user clicks on the Add person link<br /> add_person_link = self.browser.find_element_by_link_text('Add person')<br /> add_person_link.click()<br /> # user fills out the form<br /> self.browser.find_element_by_name('first_name').send_keys("Michael")<br /> self.browser.find_element_by_name('last_name').send_keys("Herman")<br /> self.browser.find_element_by_name('email').send_keys("michael@realpython.com")<br /> self.browser.find_element_by_name('address').send_keys("2227 Lexington Ave")<br /> self.browser.find_element_by_name('city').send_keys("San Francisco")<br /> self.browser.find_element_by_name('state').send_keys("CA")<br /> self.browser.find_element_by_name('country').send_keys("United States")<br /> # user clicks the save button<br /> self.browser.find_element_by_css_selector("input[value='Save']").click()<br /> # the Person has been added<br /> body = self.browser.find_element_by_tag_name('body')<br /> self.assertIn('Herman, Michael', body.text)<br /> # user returns to the main admin screen<br /> home_link = self.browser.find_element_by_link_text('Home')<br /> home_link.click()<br /> # user clicks on the Phones link<br /> persons_links = self.browser.find_elements_by_link_text('Phones')<br /> persons_links[0].click()<br /> # user clicks on the Add phone link<br /> add_person_link = self.browser.find_element_by_link_text('Add phone')<br /> add_person_link.click()<br /> # user finds the person in the dropdown<br /> el = self.browser.find_element_by_name("person")<br /> for option in el.find_elements_by_tag_name('option'):<br /> if option.text == 'Herman, Michael':<br /> option.click()<br /> # user adds the phone numbers<br /> self.browser.find_element_by_name('number').send_keys("4158888888")<br /> # user clicks the save button<br /> self.browser.find_element_by_css_selector("input[value='Save']").click()<br /> # the Phone has been added<br /> body = self.browser.find_element_by_tag_name('body')<br /> self.assertIn('4158888888', body.text)<br /> # user logs out<br /> self.browser.find_element_by_link_text('Log out').click()<br /> body = self.browser.find_element_by_tag_name('body')<br /> self.assertIn('Thanks for spending some quality time with the Web site today.', body.text)<br /> </code> </p> <p> que es para la funcionalidad de administración. Deje de mecanismos de conmutación y el enfoque de la aplicación, user_contacts, sí. ¿Ha olvidado para comprometerse? Si es así, hacerlo ahora. </p> <p> Unidad </p> <h2> Pruebas de </h2> <p> Piense acerca de las características que hemos escrito hasta ahora. Sólo hemos definido nuestro modelo y los administradores podrán alterar el modelo. Basado en esto, y el objetivo general de nuestro proyecto, se centran en las funcionalidades de usuario restantes. Los usuarios deben </p> <p> poder- </p> <p> intentar formular la prueba de funcionamiento restantes (s) sobre la base de esos requisitos. Antes de escribir las pruebas funcionales, sin embargo, debemos definir el comportamiento del código a través de pruebas de unidad – lo que le ayudará a escribir bien, un código limpio, por lo que es más fácil escribir las pruebas funcionales. </p> <p> <strong> Recuerde </strong>: Las pruebas funcionales son el último indicador de si el proyecto funciona o no, mientras que las pruebas de unidad son los medios para ayudar a alcanzar ese fin. Todo esto tendrá sentido pronto. pausa de </p> <p> Let por un minuto y hablar de algunas convenciones. </p> <p> Aunque los fundamentos de TDD (o extremos) – Test, código, Refactor – son universales, muchos desarrolladores de acercarse a los medios de manera diferente. Por ejemplo, me gusta escribir mis pruebas de unidad en primer lugar, para asegurar que mi código funciona a un nivel granular, a continuación, escribir las pruebas funcionales. Otros escriben pruebas funcionales en primer lugar, verlas fallan, entonces las pruebas de unidad de escritura, de ver fallan, a continuación, escribir el código para satisfacer primero las pruebas unitarias, que en última instancia deben satisfacer las pruebas de funcionamiento. No hay respuesta correcta o incorrecta aquí. Hacer lo que se siente más cómodo – pero siguen poniendo a prueba en primer lugar, a continuación, escribir código, y finalmente refactor. </p> <h3> Vistas </h3> <p> En primer lugar, comprobar para asegurarse de que todos los puntos de vista están configurados correctamente. </p> <h3> Vista principal </h3> <p> Como siempre, se inicia con una prueba: </p> <p> <code>from django.template.loader import render_to_string<br /> from django.test import TestCase, Client<br /> from user_contacts.models import Person, Phone<br /> from user_contacts.views import *</p> <p>class ViewTest(TestCase):</p> <p> def setUp(self):<br /> self.client_stub = Client()</p> <p> def test_view_home_route(self):<br /> response = self.client_stub.get('/')<br /> self.assertEquals(response.status_code, 200)<br /> </code> </p> <p> Nombre test_views.py esta prueba y guardarlo en la user_contacts / Pruebas de directorio. También añadir un archivo __init__.py al directorio y borrar el archivo “tests.py” en el directorio principal user_contacts. </p> <p> Run que: </p> <p> <code>$ python manage.py test user_contacts<br /> </code> </p> <p> Que falle – AssertionError: 404 = 200 – porque la URL, Vista, y la plantilla no existen. Si no está familiarizado con la forma en Django se encarga de la arquitectura MVC, por favor leer el breve artículo aquí. </p> <p> La prueba es simple. En primer lugar, obtener la URL “/” con el cliente, que es parte de TestCase de Django. La respuesta se almacena, después comprobamos para asegurarse de que el código de estado devuelto es igual a 200. </p> <p> Añadir la siguiente ruta de “contactos / urls.py”: </p> <p> <code>url(r'^', include('user_contacts.urls')),<br /> </code> </p> <p> actualización “user_contacts / urls.py”: </p> <p> <code>from django.conf.urls import patterns, url</p> <p>from user_contacts.views import *</p> <p>urlpatterns = patterns('',<br /> url(r'^$', home),<br /> )<br /> </code> </p> <p> Actualizar “views.py”: </p> <p> <code>from django.http import HttpResponse, HttpResponseRedirect<br /> from django.shortcuts import render_to_response, render<br /> from django.template import RequestContext<br /> from user_contacts.models import Phone, Person<br /> # from user_contacts.new_contact_form import ContactForm</p> <p>def home(request):<br /> return render_to_response('index.html')<br /> </code> </p> <p> Añadir una plantilla de “index.html” en el directorio de plantillas: </p> <p> <code><!DOCTYPE html><br /> <head><br /> <title>Welcome.<itle><br /> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link href="http:/<br />etdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" rel="stylesheet" media="screen"></p> <style> .container { padding: 50px; } </style> <p> </head><br /> <body></p> <div class="container"> <h1>What would you like to do?</h1> <ul> <li><a href="/all">View Contacts</a></li> <li><a href="/add">Add Contact</a></li> </ul> <div> <script src="http://code.jquery.com/jquery-1.10.2.min.js"></script><br /> <script src="http:/<br />etdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script><br /> </body><br /> </html><br /> </code> </p> <p> Ejecutar la prueba de nuevo. Se debe pasar muy bien. </p> <h3> Todos los contactos Ver </h3> <p> La prueba de este punto de vista es casi idéntica a la última prueba. Intentarlo por su cuenta antes de mirar a mi respuesta. </p> <p> Escribir la prueba por primera vez por la adición de la siguiente función a la clase ViewTest: </p> <p> <code>def test_view_contacts_route(self):<br /> response = self.client_stub.get('/all/')<br /> self.assertEquals(response.status_code, 200)<br /> </code> </p> <p> Cuando RAN, debería ver el mismo error: AssertionError: 404 = 200. </p> <p> Actualizar “user_contacts / urls.py” con la siguiente ruta : </p> <p> <code>url(r'^all/$', all_contacts),<br /> </code> </p> <p> Update “views.py”: </p> <p> <code>def all_contacts(request):<br /> contacts = Phone.objects.all()<br /> return render_to_response('all.html', {'contacts':contacts})<br /> </code> </p> <p> Añadir un “-todos.html Anuncios” plantilla para el directorio de plantillas: </p> <p> <code><!DOCTYPE html><br /> <html><br /> <head><br /> <title>All Contacts.<itle><br /> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link href="http:/<br />etdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" rel="stylesheet" media="screen"></p> <style> .container { padding: 50px; } </style> <p></head><br /> <body></p> <div class="container"> <h1>All Contacts</h1> <table border="1" cellpadding="5"> <tr> <th>First Name<h></p> <th>Last Name<h></p> <th>Address<h></p> <th>City<h></p> <th>State<h></p> <th>Country<h></p> <th>Phone Number<h></p> <th>Email<h><br /> <r><br /> {% for contact in contacts %}</p> <tr> <td>{{contact.person.first\_name}}<d></p> <td>{{contact.person.last\_name}}<d></p> <td>{{contact.person.address}}<d></p> <td>{{contact.person.city}}<d></p> <td>{{contact.person.state}}<d></p> <td>{{contact.person.country}}<d></p> <td>{{contact.number}}<d></p> <td>{{contact.person.email}}<d><br /> <r><br /> {% endfor %}<br /> <able><br /> <br /> <a href="/">Return Home</a> </div> <p> <script src="http://code.jquery.com/jquery-1.10.2.min.js"></script><br /> <script src="http:/<br />etdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script><br /> </body><br /> </html><br /> </code> </p> <p> Esto debe pasar también. </p> <h3> Añadir Contacto Ver </h3> <p> Esta prueba es ligeramente diferente de los dos anteriores, así que por favor seguir a lo largo de cerca. </p> <p> Añadir la prueba para el conjunto de pruebas: </p> <p> <code>def test_add_contact_route(self):<br /> response = self.client_stub.get('/add/')<br /> self.assertEqual(response.status_code, 200)<br /> </code> </p> <p> Debe ver este error cuando RAN: AssertionError: 404 = 200 </p> <p> Update “urls.py”: </p> <p> <code>url(r'^add/$', add),<br /> </code> </p> <p> Update “views.py”: </p> <p> <code>def add(request):<br /> person_form = ContactForm()<br /> return render(request, 'add.html', {'person_form' : person_form}, context_instance = RequestContext(request))<br /> </code> </p> <p> Hacer Asegúrese de añadir la siguiente importación: </p> <p> <code>from user_contacts.new_contact_form import ContactForm<br /> </code> </p> <p> Crear un nuevo archivo llamado new_contact_form.py y agregue el siguiente código: </p> <p> <code>import re<br /> from django import forms<br /> from django.core.exceptions import ValidationError<br /> from user_contacts.models import Person, Phone</p> <p>class ContactForm(forms.Form):<br /> first_name = forms.CharField(max_length=30)<br /> last_name = forms.CharField(max_length=30)<br /> email = forms.EmailField(required=False)<br /> address = forms.CharField(widget=forms.Textarea, required=False)<br /> city = forms.CharField(required=False)<br /> state = forms.CharField(required=False)<br /> country = forms.CharField(required=False)<br /> number = forms.CharField(max_length=10)</p> <p> def save(self):<br /> if self.is_valid():<br /> data = self.cleaned_data<br /> person = Person.objects.create(first_name=data.get('first_name'), last_name=data.get('last_name'),<br /> email=data.get('email'), address=data.get('address'), city=data.get('city'), state=data.get('state'),<br /> country=data.get('country'))<br /> phone = Phone.objects.create(person=person, number=data.get('number'))<br /> return phone<br /> </code> </p> <p> Añadir “add.html” en el directorio de plantillas: </p> <p> <code><!DOCTYPE html><br /> <html><br /> <head><br /> <title>Welcome.<itle><br /> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link href="http:/<br />etdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" rel="stylesheet" media="screen"></p> <style> .container { padding: 50px; } </style> <p></head><br /> <body></p> <div class="container"> <h1>Add Contact</h1> <p></p> <form action="/create" method ="POST" role="form"> {% csrf\_token %}<br /> {{ person_\_form.as\_p }}<br /> {{ phone\_form.as\_p }}<br /> <input type ="submit" name ="Submit" class="btn btn-default" value ="Add"><br /> </form> <p> <a href="/">Return Home</a> </div> <p> <script src="http://code.jquery.com/jquery-1.10.2.min.js"></script><br /> <script src="http:/<br />etdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script><br /> </body><br /> </html><br /> </code> </p> <p> ¿pasa? Debería. Si no es así, refactor. </p> <h3> Validación </h3> <p> Ahora que hemos terminado de probar las Vistas, vamos a añadir la validación de la forma. Pero primero tenemos que escribir una prueba. ¡Sorpresa! </p> <p> Crear un nuevo archivo llamado “test_validator.py” dentro del directorio “pruebas” y añadir el siguiente código: </p> <p> <code>from django.core.exceptions import ValidationError<br /> from django.test import TestCase<br /> from user_contacts.validators import validate_number, validate_string</p> <p> class ValidatorTest(TestCase):<br /> def test_string_is_invalid_if_contains_numbers_or_special_characters(self):<br /> with self.assertRaises(ValidationError):<br /> validate_string('@test')<br /> validate_string('tester#')<br /> def test_number_is_invalid_if_contains_any_character_except_digits(self):<br /> with self.assertRaises(ValidationError):<br /> validate_number('123ABC')<br /> validate_number('75431#')<br /> </code> </p> <p> Antes de ejecutar el conjunto de pruebas, se puede adivinar lo que podría suceder? <em> Consejo: Ponga mucha atención a las importaciones en el código de seguridad. </em> Usted debe obtener el siguiente error porque no tenemos un archivo “validators.py”: </p> <p> <code>ImportError: cannot import name validate_string<br /> </code> </p> <p> En otras palabras, estamos probando la lógica en un archivo de validación que no existe todavía. </p> <p> Añadir un nuevo archivo llamado “validators.py” al directorio user_contacts: </p> <p> <code>import re<br /> from django.core.exceptions import ValidationError</p> <p>def validate_string(string):<br /> if re.search('^[A-Za-z]+$', string) is None:<br /> raise ValidationError('Invalid')</p> <p>def validate_number(value):<br /> if re.search('^[0-9]+$', value) is None:<br /> raise ValidationError('Invalid')<br /> </code> </p> <p> ejecutar el banco de prueba de nuevo. Cinco ahora debe pasar: </p> <p> <code>Ran 5 tests in 0.019s</p> <p>OK<br /> </code> </p> <h3> Crear contacto </h3> <p> Dado que hemos añadido la validación, que queremos poner a prueba para asegurarse de que los validadores trabajan en el área de administración, por lo que la actualización “test_views.py”: pruebas </p> <p> <code>from django.template.loader import render_to_string<br /> from django.test import TestCase, Client<br /> from user_contacts.models import Person, Phone<br /> from user_contacts.views import *</p> <p>class ViewTest(TestCase):</p> <p> def setUp(self):<br /> self.client_stub = Client()<br /> self.person = Person(first_name = 'TestFirst',last_name = 'TestLast')<br /> self.person.save()<br /> self.phone = Phone(person = self.person,number = '7778889999')<br /> self.phone.save()</p> <p> def test_view_home_route(self):<br /> response = self.client_stub.get('/')<br /> self.assertEquals(response.status_code, 200)</p> <p> def test_view_contacts_route(self):<br /> response = self.client_stub.get('/all/')<br /> self.assertEquals(response.status_code, 200)</p> <p> def test_add_contact_route(self):<br /> response = self.client_stub.get('/add/')<br /> self.assertEqual(response.status_code, 200)</p> <p> def test_create_contact_successful_route(self):<br /> response = self.client_stub.post('/create',data = {'first_name' : 'testFirst', 'last_name':'tester', 'email':'test@tester.com', 'address':'1234 nowhere', 'city':'far away', 'state':'CO', 'country':'USA', 'number':'987654321'})<br /> self.assertEqual(response.status_code, 302)</p> <p> def test_create_contact_unsuccessful_route(self):<br /> response = self.client_stub.post('/create',data = {'first_name' : 'tester_first_n@me', 'last_name':'test', 'email':'tester@test.com', 'address':'5678 everywhere', 'city':'far from here', 'state':'CA', 'country':'USA', 'number':'987654321'})<br /> self.assertEqual(response.status_code, 200)</p> <p> def tearDown(self):<br /> self.phone.delete()<br /> self.person.delete()<br /> </code> </p> <p> Dos fallara. </p> <p> Lo que hay que hacer con el fin de obtener esta prueba a pasar? Bueno, en primer lugar hay que agregar una función a los puntos de vista que permiten agregar información a la base de datos. </p> <p> Agregar ruta: </p> <p> <code>url(r'^create$', create),<br /> </code> </p> <p> Update “views.py”: </p> <p> <code>def create(request):<br /> form = ContactForm(request.POST)<br /> if form.is_valid():<br /> form.save()<br /> return HttpResponseRedirect('all/')<br /> return render(<br /> request, 'add.html', {'person_form' : form},<br /> context_instance=RequestContext(request))<br /> </code> </p> <p> prueba de nuevo: </p> <p> <code>$ python manage.py test user_contacts<br /> </code> </p> <p> Esta vez sólo una prueba debe fallar – AssertionError: 302 = 200 – porque tratamos de agregar datos que no deberían haber pasado los validadores, pero lo hicieron. En otras palabras, tenemos que actualizar el archivo “models.py” así como la forma para tomar esas validadores en cuenta. </p> <p> Update “models.py”: </p> <p> <code>from django.db import models<br /> from user_contacts.validators import validate_string, validate_number</p> <p>class Person(models.Model):<br /> first_name = models.CharField(max_length = 30, validators = [validate_string])<br /> last_name = models.CharField(max_length = 30, validators = [validate_string])<br /> email = models.EmailField(null = True, blank = True)<br /> address = models.TextField(null = True, blank = True)<br /> city = models.CharField(max_length = 15, null = True,blank = True)<br /> state = models.CharField(max_length = 15, null = True, blank = True, validators = [validate_string])<br /> country = models.CharField(max_length = 15, null = True, blank = True)</p> <p> def __unicode__(self):<br /> return self.last_name +", "+ self.first_name</p> <p>class Phone(models.Model):<br /> person = models.ForeignKey('Person')<br /> number = models.CharField(max_length=10, validators = [validate_number])</p> <p> def __unicode__(self):<br /> return self.number<br /> </code> </p> <p> Eliminar la base de datos actual, “db.sqlite3”, y volver a sincronizar la base de datos: Configuración </p> <p> <code>$ python manage.py syncdb<br /> </code> </p> <p> un usuario administrador de nuevo. </p> <p> actualización new_contact_form.py mediante la adición de validación: </p> <p> <code>import re<br /> from django import forms<br /> from django.core.exceptions import ValidationError<br /> from user_contacts.models import Person, Phone<br /> from user_contacts.validators import validate_string, validate_number</p> <p>class ContactForm(forms.Form):<br /> first_name = forms.CharField(max_length=30, validators = [validate_string])<br /> last_name = forms.CharField(max_length=30, validators = [validate_string])<br /> email = forms.EmailField(required=False)<br /> address = forms.CharField(widget=forms.Textarea, required=False)<br /> city = forms.CharField(required=False)<br /> state = forms.CharField(required=False, validators = [validate_string])<br /> country = forms.CharField(required=False)<br /> number = forms.CharField(max_length=10, validators = [validate_number])</p> <p> def save(self):<br /> if self.is_valid():<br /> data = self.cleaned_data<br /> person = Person.objects.create(first_name=data.get('first_name'), last_name=data.get('last_name'),<br /> email=data.get('email'), address=data.get('address'), city=data.get('city'), state=data.get('state'),<br /> country=data.get('country'))<br /> phone = Phone.objects.create(person=person, number=data.get('number'))<br /> return phone<br /> </code> </p> <p> Ejecutar las pruebas de nuevo. 7 debe pasar. </p> <p> Ahora, desviándose de TDD por un minuto, quiero añadir una prueba adicional para la validación de prueba en el lado del cliente. Así que añadir test_contact_form.py: </p> <p> <code>from django.test import TestCase<br /> from user_contacts.models import Person<br /> from user_contacts.new_contact_form import ContactForm</p> <p>class TestContactForm(TestCase):<br /> def test_if_valid_contact_is_saved(self):<br /> form = ContactForm({'first_name':'test', 'last_name':'test','number':'9999900000'})<br /> contact = form.save()<br /> self.assertEqual(contact.person.first_name, 'test')<br /> def test_if_invalid_contact_is_not_saved(self):<br /> form = ContactForm({'first_name':'tes&t', 'last_name':'test','number':'9999900000'})<br /> contact = form.save()<br /> self.assertEqual(contact, None)<br /> </code> </p> <p> Ejecutar el paquete de pruebas. Todas las 9 pruebas deben pasar ahora. ¡Hurra! Ahora comprometerse. Pruebas funcionales </p> <h2> Redux </h2> <p> con la unidad de pruebas realizadas, que ahora puede añadir una prueba funcional para asegurar que la aplicación se ejecuta correctamente. Con suerte, con las unidades de prueba que pasa, deberíamos tener ningún problema con la prueba funcional. </p> <p> Añadir una nueva clase en el fichero “tests.py”: </p> <p> <code>class UserContactTest(LiveServerTestCase):</p> <p> def setUp(self):<br /> self.browser = webdriver.Firefox()<br /> self.browser.implicitly_wait(3)</p> <p> def tearDown(self):<br /> self.browser.quit()</p> <p> def test_create_contact(self):<br /> # user opens web browser, navigates to home page<br /> self.browser.get(self.live_server_url + '/')<br /> # user clicks on the Persons link<br /> add_link = self.browser.find_elements_by_link_text('Add Contact')<br /> add_link[0].click()<br /> # user fills out the form<br /> self.browser.find_element_by_name('first_name').send_keys("Michael")<br /> self.browser.find_element_by_name('last_name').send_keys("Herman")<br /> self.browser.find_element_by_name('email').send_keys("michael@realpython.com")<br /> self.browser.find_element_by_name('address').send_keys("2227 Lexington Ave")<br /> self.browser.find_element_by_name('city').send_keys("San Francisco")<br /> self.browser.find_element_by_name('state').send_keys("CA")<br /> self.browser.find_element_by_name('country').send_keys("United States")<br /> self.browser.find_element_by_name('number').send_keys("4158888888")<br /> # user clicks the save button<br /> self.browser.find_element_by_css_selector("input[value='Add']").click()<br /> # the Person has been added<br /> body = self.browser.find_element_by_tag_name('body')<br /> self.assertIn('michael@realpython.com', body.text)</p> <p> def test_create_contact_error(self):<br /> # user opens web browser, navigates to home page<br /> self.browser.get(self.live_server_url + '/')<br /> # user clicks on the Persons link<br /> add_link = self.browser.find_elements_by_link_text('Add Contact')<br /> add_link[0].click()<br /> # user fills out the form<br /> self.browser.find_element_by_name('first_name').send_keys("test@")<br /> self.browser.find_element_by_name('last_name').send_keys("tester")<br /> self.browser.find_element_by_name('email').send_keys("test@tester.com")<br /> self.browser.find_element_by_name('address').send_keys("2227 Tester Ave")<br /> self.browser.find_element_by_name('city').send_keys("Tester City")<br /> self.browser.find_element_by_name('state').send_keys("TC")<br /> self.browser.find_element_by_name('country').send_keys("TCA")<br /> self.browser.find_element_by_name('number').send_keys("4158888888")<br /> # user clicks the save button<br /> self.browser.find_element_by_css_selector("input[value='Add']").click()<br /> body = self.browser.find_element_by_tag_name('body')<br /> self.assertIn('Invalid', body.text)<br /> </code> </p> <p> Ejecutar las pruebas funcionales: </p> <p> <code>$ python manage.py test ft<br /> </code> </p> <p> Aquí sólo estamos probando el código que escribimos y ya probado con pruebas unitarias desde la perspectiva del usuario final. Las cuatro pruebas deben pasar. </p> <p> Por último, vamos a asegurar que la validación ponemos en su lugar se aplica al panel de administración mediante la adición de la siguiente función a la clase AdminTest: </p> <p> <code>def test_create_contact_admin_raise_error(self):<br /> # # user opens web browser, navigates to admin page, and logs in<br /> self.browser.get(self.live_server_url + '/admin/')<br /> username_field = self.browser.find_element_by_name('username')<br /> username_field.send_keys('admin')<br /> password_field = self.browser.find_element_by_name('password')<br /> password_field.send_keys('admin')<br /> password_field.send_keys(Keys.RETURN)<br /> # user clicks on the Persons link<br /> persons_links = self.browser.find_elements_by_link_text('Persons')<br /> persons_links[0].click()<br /> # user clicks on the Add person link<br /> add_person_link = self.browser.find_element_by_link_text('Add person')<br /> add_person_link.click()<br /> # user fills out the form<br /> self.browser.find_element_by_name('first_name').send_keys("test@")<br /> self.browser.find_element_by_name('last_name').send_keys("tester")<br /> self.browser.find_element_by_name('email').send_keys("test@tester.com")<br /> self.browser.find_element_by_name('address').send_keys("2227 Tester Ave")<br /> self.browser.find_element_by_name('city').send_keys("Tester City")<br /> self.browser.find_element_by_name('state').send_keys("TC")<br /> self.browser.find_element_by_name('country').send_keys("TCA")<br /> # user clicks the save button<br /> self.browser.find_element_by_css_selector("input[value='Save']").click()<br /> body = self.browser.find_element_by_tag_name('body')<br /> self.assertIn('Invalid', body.text)<br /> </code> </p> <p> ejecutarlo. Cinco pruebas deben pasar. Y se comprometen Vamos a llamar a un día. Estructura </p> <p> prueba </p> <h2> </h2> <p> TDD es una poderosa herramienta y una parte integral del ciclo de desarrollo, ayudando a los desarrolladores de programas rompen en pequeñas porciones, legibles. Dichas porciones son mucho más fáciles de escribir ahora y cambiar más tarde. Además, tener una suite completa de los ensayos, que cubre todas las características de su base de código, ayuda a asegurar que las nuevas implementaciones de funciones no rompa el código existente. </p> <p> Dentro del proceso, las pruebas funcionales <strong> </strong> son pruebas de alto nivel, se centró en la <em> características </em> que los usuarios finales interactuar con él. </p> <p> Mientras tanto, Unidad <strong> prueba Las pruebas funcionales de apoyo </strong> en que ponen a prueba cada característica del código. Tenga en cuenta que la unidad <strong> prueba </strong> son mucho más fáciles de escribir, en general, proporcionar una mejor cobertura, y son más fáciles de depurar, ya que ponen a prueba sólo una característica a la vez. También se desarrollan mucho más rápido, así que asegúrese de probar sus pruebas de unidad más a menudo que sus pruebas funcionales. La toma del </p> <p> Let un vistazo a nuestra estructura de prueba para ver cómo nuestras pruebas unitarias apoyan las pruebas funcionales: </p> </p> <p> <img src="https://eltecnofilo.es/wp-content/uploads/2020/03/django-tdd-test-structure.6d04849a84ea.png"> </p> <h2> Conclusión </h2> <p> Felicidades. Lo haces a través. ¿Que sigue? </p> <p> primer lugar, usted puede haber notado que yo no 100% de seguimiento del proceso de TDD. Esta bien. La mayoría de los desarrolladores involucrados en TDD no siempre se adhieren a ella en cada situación individual. Hay momentos en los que debe desvía de ella con el fin de simplemente hacer las cosas – que es perfectamente bien. Si desea refactorizar una parte del código / proceso para adherirse plenamente al proceso de TDD, se puede. De hecho, puede ser una buena práctica. </p> <p> En segundo lugar, pensar en las pruebas que echaba de menos. La determinación de qué y cuándo prueba es difícil. Se necesita tiempo y mucha práctica para ser bueno en las pruebas en general. He dejado muchos espacios en blanco que tengo la intención de Revel en mi próximo post. Vea si usted puede encontrar estos y añadir pruebas. </p> <p> Por último, recuerda el último paso en el proceso de TDD? Refactorización. Este paso es vital, ya que ayuda a crear legible, código mantenible que no sólo se entiende ahora – pero en el futuro también. Cuando uno mira hacia atrás en su código, piense en las pruebas se pueden combinar. También, qué pruebas debe añadir para asegurar que todo el código escrito se prueba? Se podía comprobar valores nulos y / o autenticación del lado del servidor, por ejemplo. Usted debe refactorizar el código antes de pasar a escribir ningún código nuevo – lo que no lo hice por el bien de tiempo. Tal vez en otra entrada del blog? Pensar en lo mal código puede contaminar todo el proceso? </p> <p> Gracias por leer. Coge el código final en el repositorio aquí. Por favor, comentario a continuación con cualquier pregunta. </p> </div><!-- .entry-content --> </div><!-- .post-inner --> <div class="section-inner"> </div><!-- .section-inner --> </article><!-- .post --> <hr class="post-separator styled-separator is-style-wide section-inner" aria-hidden="true" /> <article class="post-1 post type-post status-publish format-standard hentry category-uncategorized" id="post-1"> <header class="entry-header has-text-align-center"> <div class="entry-header-inner section-inner medium"> <div class="entry-categories"> <span class="screen-reader-text">Categorías</span> <div class="entry-categories-inner"> <a href="https://eltecnofilo.es/category/uncategorized/" rel="category tag">Uncategorized</a> </div><!-- .entry-categories-inner --> </div><!-- .entry-categories --> <h2 class="entry-title heading-size-1"><a href="https://eltecnofilo.es/hello-world/">Hello world!</a></h2> <div class="post-meta-wrapper post-meta-single post-meta-single-top"> <ul class="post-meta"> <li class="post-author meta-wrapper"> <span class="meta-icon"> <span class="screen-reader-text">Autor de la entrada</span> <svg class="svg-icon" aria-hidden="true" role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" width="18" height="20" viewBox="0 0 18 20"><path fill="" d="M18,19 C18,19.5522847 17.5522847,20 17,20 C16.4477153,20 16,19.5522847 16,19 L16,17 C16,15.3431458 14.6568542,14 13,14 L5,14 C3.34314575,14 2,15.3431458 2,17 L2,19 C2,19.5522847 1.55228475,20 1,20 C0.44771525,20 0,19.5522847 0,19 L0,17 C0,14.2385763 2.23857625,12 5,12 L13,12 C15.7614237,12 18,14.2385763 18,17 L18,19 Z M9,10 C6.23857625,10 4,7.76142375 4,5 C4,2.23857625 6.23857625,0 9,0 C11.7614237,0 14,2.23857625 14,5 C14,7.76142375 11.7614237,10 9,10 Z M9,8 C10.6568542,8 12,6.65685425 12,5 C12,3.34314575 10.6568542,2 9,2 C7.34314575,2 6,3.34314575 6,5 C6,6.65685425 7.34314575,8 9,8 Z" /></svg> </span> <span class="meta-text"> Por <a href="https://eltecnofilo.es/author/admin/">admin</a> </span> </li> <li class="post-date meta-wrapper"> <span class="meta-icon"> <span class="screen-reader-text">Fecha de la entrada</span> <svg class="svg-icon" aria-hidden="true" role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" width="18" height="19" viewBox="0 0 18 19"><path fill="" d="M4.60069444,4.09375 L3.25,4.09375 C2.47334957,4.09375 1.84375,4.72334957 1.84375,5.5 L1.84375,7.26736111 L16.15625,7.26736111 L16.15625,5.5 C16.15625,4.72334957 15.5266504,4.09375 14.75,4.09375 L13.3993056,4.09375 L13.3993056,4.55555556 C13.3993056,5.02154581 13.0215458,5.39930556 12.5555556,5.39930556 C12.0895653,5.39930556 11.7118056,5.02154581 11.7118056,4.55555556 L11.7118056,4.09375 L6.28819444,4.09375 L6.28819444,4.55555556 C6.28819444,5.02154581 5.9104347,5.39930556 5.44444444,5.39930556 C4.97845419,5.39930556 4.60069444,5.02154581 4.60069444,4.55555556 L4.60069444,4.09375 Z M6.28819444,2.40625 L11.7118056,2.40625 L11.7118056,1 C11.7118056,0.534009742 12.0895653,0.15625 12.5555556,0.15625 C13.0215458,0.15625 13.3993056,0.534009742 13.3993056,1 L13.3993056,2.40625 L14.75,2.40625 C16.4586309,2.40625 17.84375,3.79136906 17.84375,5.5 L17.84375,15.875 C17.84375,17.5836309 16.4586309,18.96875 14.75,18.96875 L3.25,18.96875 C1.54136906,18.96875 0.15625,17.5836309 0.15625,15.875 L0.15625,5.5 C0.15625,3.79136906 1.54136906,2.40625 3.25,2.40625 L4.60069444,2.40625 L4.60069444,1 C4.60069444,0.534009742 4.97845419,0.15625 5.44444444,0.15625 C5.9104347,0.15625 6.28819444,0.534009742 6.28819444,1 L6.28819444,2.40625 Z M1.84375,8.95486111 L1.84375,15.875 C1.84375,16.6516504 2.47334957,17.28125 3.25,17.28125 L14.75,17.28125 C15.5266504,17.28125 16.15625,16.6516504 16.15625,15.875 L16.15625,8.95486111 L1.84375,8.95486111 Z" /></svg> </span> <span class="meta-text"> <a href="https://eltecnofilo.es/hello-world/">diciembre 25, 2019</a> </span> </li> <li class="post-comment-link meta-wrapper"> <span class="meta-icon"> <svg class="svg-icon" aria-hidden="true" role="img" focusable="false" xmlns="http://www.w3.org/2000/svg" width="19" height="19" viewBox="0 0 19 19"><path d="M9.43016863,13.2235931 C9.58624731,13.094699 9.7823475,13.0241935 9.98476849,13.0241935 L15.0564516,13.0241935 C15.8581553,13.0241935 16.5080645,12.3742843 16.5080645,11.5725806 L16.5080645,3.44354839 C16.5080645,2.64184472 15.8581553,1.99193548 15.0564516,1.99193548 L3.44354839,1.99193548 C2.64184472,1.99193548 1.99193548,2.64184472 1.99193548,3.44354839 L1.99193548,11.5725806 C1.99193548,12.3742843 2.64184472,13.0241935 3.44354839,13.0241935 L5.76612903,13.0241935 C6.24715123,13.0241935 6.63709677,13.4141391 6.63709677,13.8951613 L6.63709677,15.5301903 L9.43016863,13.2235931 Z M3.44354839,14.766129 C1.67980032,14.766129 0.25,13.3363287 0.25,11.5725806 L0.25,3.44354839 C0.25,1.67980032 1.67980032,0.25 3.44354839,0.25 L15.0564516,0.25 C16.8201997,0.25 18.25,1.67980032 18.25,3.44354839 L18.25,11.5725806 C18.25,13.3363287 16.8201997,14.766129 15.0564516,14.766129 L10.2979143,14.766129 L6.32072889,18.0506004 C5.75274472,18.5196577 4.89516129,18.1156602 4.89516129,17.3790323 L4.89516129,14.766129 L3.44354839,14.766129 Z" /></svg> </span> <span class="meta-text"> <a href="https://eltecnofilo.es/hello-world/#comments">1 comentario<span class="screen-reader-text"> en Hello world!</span></a> </span> </li> </ul><!-- .post-meta --> </div><!-- .post-meta-wrapper --> </div><!-- .entry-header-inner --> </header><!-- .entry-header --> <div class="post-inner thin "> <div class="entry-content"> <p>Welcome to WordPress. This is your first post. Edit or delete it, then start writing!</p> </div><!-- .entry-content --> </div><!-- .post-inner --> <div class="section-inner"> </div><!-- .section-inner --> </article><!-- .post --> <div class="pagination-wrapper section-inner"> <hr class="styled-separator pagination-separator is-style-wide" aria-hidden="true" /> <nav class="navigation pagination" role="navigation" aria-label="Entradas"> <h2 class="screen-reader-text">Navegación de entradas</h2> <div class="nav-links"><a class="prev page-numbers" href="https://eltecnofilo.es/page/20/"><span aria-hidden="true">←</span> <span class="nav-prev-text">Entradas <span class="nav-short">siguientes</span></span></a> <a class="page-numbers" href="https://eltecnofilo.es/">1</a> <span class="page-numbers dots">…</span> <a class="page-numbers" href="https://eltecnofilo.es/page/20/">20</a> <span aria-current="page" class="page-numbers current">21</span><span class="next page-numbers placeholder" aria-hidden="true"><span class="nav-next-text">Entradas <span class="nav-short">anteriores</span></span> <span aria-hidden="true">→</span></span></div> </nav> </div><!-- .pagination-wrapper --> </main><!-- #site-content --> <div class="footer-nav-widgets-wrapper header-footer-group"> <div class="footer-inner section-inner"> <aside class="footer-widgets-outer-wrapper" role="complementary"> <div class="footer-widgets-wrapper"> <div class="footer-widgets column-one grid-item"> <div class="widget widget_search"><div class="widget-content"><form role="search" method="get" class="search-form" action="https://eltecnofilo.es/"> <label for="search-form-2"> <span class="screen-reader-text">Buscar:</span> <input type="search" id="search-form-2" class="search-field" placeholder="Buscar …" value="" name="s" /> </label> <input type="submit" class="search-submit" value="Buscar" /> </form> </div></div> <div class="widget widget_recent_entries"><div class="widget-content"> <h2 class="widget-title subheading heading-size-3">Entradas recientes</h2> <ul> <li> <a href="https://eltecnofilo.es/vps-cloud-hosting/">VPS cloud hosting</a> </li> <li> <a href="https://eltecnofilo.es/versiones-de-ejecucion-de-python-en-acoplable-como-probar-la-ultima-release-python/">Versiones de ejecución de Python en acoplable: Cómo probar la última Release Python</a> </li> <li> <a href="https://eltecnofilo.es/leer-y-escribir-archivos-csv/">Leer y escribir archivos CSV</a> </li> <li> <a href="https://eltecnofilo.es/python-puro-vs-vs-numpy-tensorflow-comparacion-de-rendimiento/">Python puro vs vs NumPy TensorFlow Comparación de Rendimiento</a> </li> <li> <a href="https://eltecnofilo.es/estructura-python-programa-lexico/">Estructura Python Programa léxico</a> </li> </ul> </div></div><div class="widget widget_recent_comments"><div class="widget-content"><h2 class="widget-title subheading heading-size-3">Comentarios recientes</h2><ul id="recentcomments"><li class="recentcomments"><span class="comment-author-link"><a href="https://wordpress.org/" rel="external nofollow ugc" class="url">A WordPress Commenter</a></span> en <a href="https://eltecnofilo.es/hello-world/#comment-1">Hello world!</a></li></ul></div></div> </div> <div class="footer-widgets column-two grid-item"> <div class="widget widget_archive"><div class="widget-content"><h2 class="widget-title subheading heading-size-3">Archivos</h2> <ul> <li><a href='https://eltecnofilo.es/2020/04/'>abril 2020</a></li> <li><a href='https://eltecnofilo.es/2020/03/'>marzo 2020</a></li> <li><a href='https://eltecnofilo.es/2019/12/'>diciembre 2019</a></li> </ul> </div></div><div class="widget widget_categories"><div class="widget-content"><h2 class="widget-title subheading heading-size-3">Categorías</h2> <ul> <li class="cat-item cat-item-22"><a href="https://eltecnofilo.es/category/python/">Python</a> </li> <li class="cat-item cat-item-1"><a href="https://eltecnofilo.es/category/uncategorized/">Uncategorized</a> </li> </ul> </div></div><div class="widget widget_meta"><div class="widget-content"><h2 class="widget-title subheading heading-size-3">Meta</h2> <ul> <li><a rel="nofollow" href="https://eltecnofilo.es/wp-login.php">Acceder</a></li> <li><a href="https://eltecnofilo.es/feed/">Feed de entradas</a></li> <li><a href="https://eltecnofilo.es/comments/feed/">Feed de comentarios</a></li> <li><a href="https://es.wordpress.org/">WordPress.org</a></li> </ul> </div></div> </div> </div><!-- .footer-widgets-wrapper --> </aside><!-- .footer-widgets-outer-wrapper --> </div><!-- .footer-inner --> </div><!-- .footer-nav-widgets-wrapper --> <footer id="site-footer" role="contentinfo" class="header-footer-group"> <div class="section-inner"> <div class="footer-credits"> <p class="footer-copyright">© 2020 <a href="https://eltecnofilo.es/">My Blog</a> </p><!-- .footer-copyright --> <p class="powered-by-wordpress"> <a href="https://es.wordpress.org/"> Funciona gracias a WordPress </a> </p><!-- .powered-by-wordpress --> </div><!-- .footer-credits --> <a class="to-the-top" href="#site-header"> <span class="to-the-top-long"> Ir arriba <span class="arrow" aria-hidden="true">↑</span> </span><!-- .to-the-top-long --> <span class="to-the-top-short"> Subir <span class="arrow" aria-hidden="true">↑</span> </span><!-- .to-the-top-short --> </a><!-- .to-the-top --> </div><!-- .section-inner --> </footer><!-- #site-footer --> <script src='https://eltecnofilo.es/wp-includes/js/wp-embed.min.js?ver=5.3.4'></script> <script> /(trident|msie)/i.test(navigator.userAgent)&&document.getElementById&&window.addEventListener&&window.addEventListener("hashchange",function(){var t,e=location.hash.substring(1);/^[A-z0-9_-]+$/.test(e)&&(t=document.getElementById(e))&&(/^(?:a|select|input|button|textarea)$/i.test(t.tagName)||(t.tabIndex=-1),t.focus())},!1); </script> </body> </html>