Simplificado en exceso: necesita algo que ejecute Python, pero Python no es el mejor para manejar todo tipo de solicitudes.
[descargo de responsabilidad: soy un desarrollador de Gunicorn]
Menos simplificado: Independientemente del servidor de aplicaciones que utilice (Gunicorn, mod_wsgi, mod_uwsgi, cherrypy), cualquier tipo de implementación no trivial tendrá algo en sentido ascendente que manejará las solicitudes que su aplicación Django no debería manejar. Ejemplos triviales de tales solicitudes están sirviendo activos estáticos (images / css / js).
Esto da como resultado dos primeros niveles de la clásica "arquitectura de tres niveles". Es decir, el servidor web (Nginx en su caso) manejará muchas solicitudes de imágenes y recursos estáticos. Las solicitudes que deben generarse dinámicamente se pasarán al servidor de aplicaciones (Gunicorn en su ejemplo). (Como comentario aparte, el tercero de los tres niveles es la base de datos)
Históricamente hablando, cada uno de estos niveles se alojaría en máquinas separadas (y probablemente habría varias máquinas en los primeros dos niveles, es decir: 5 servidores web envían solicitudes a dos servidores de aplicaciones que a su vez consultan una sola base de datos).
En la era moderna ahora tenemos aplicaciones de todas las formas y tamaños. No todos los proyectos de fin de semana o sitios de pequeñas empresas realmente necesitan la potencia de varias máquinas y funcionarán muy bien en una sola caja. Esto ha generado nuevas entradas en la gama de soluciones de alojamiento. Algunas soluciones unirán el servidor de aplicaciones con el servidor web (Apache httpd + mod_wsgi, Nginx + mod_uwsgi, etc.). Y no es nada raro alojar la base de datos en la misma máquina que una de estas combinaciones de servidor web / aplicación.
Ahora, en el caso de Gunicorn, tomamos una decisión específica (copiando de Ruby's Unicorn) para mantener las cosas separadas de Nginx mientras confiamos en el comportamiento de representación de Nginx. Específicamente, si podemos suponer que Gunicorn nunca leerá conexiones directamente desde Internet, entonces no tenemos que preocuparnos por los clientes que son lentos. Esto significa que el modelo de procesamiento para Gunicorn es vergonzosamente simple.
La separación también permite que Gunicorn se escriba en Python puro, lo que minimiza el costo de desarrollo sin afectar significativamente el rendimiento. También permite a los usuarios la capacidad de usar otros servidores proxy (suponiendo que se almacenan correctamente).
En cuanto a su segunda pregunta sobre qué maneja realmente la solicitud HTTP, la respuesta simple es Gunicorn. La respuesta completa es que tanto Nginx como Gunicorn manejan la solicitud. Básicamente, Nginx recibirá la solicitud y, si se trata de una solicitud dinámica (generalmente basada en patrones de URL), le dará esa solicitud a Gunicorn, que la procesará, y luego devolverá una respuesta a Nginx que luego reenviará la respuesta al original cliente.
Así que para terminar, sí. Necesita tanto Nginx como Gunicorn (o algo similar) para una implementación adecuada de Django. Si está buscando específicamente alojar Django con Nginx, entonces investigaría a Gunicorn, mod_uwsgi y tal vez CherryPy como candidatos para el lado de Django.