Noticias - Visitar sitio
Tres trece - juego de cartas en línea Juega tres trece con un amigo haciendo clic en el siguiente enlace para generar un código de invitación o unirse a un juego.Invitar con el código lotteh.com/games/"title =" Únete a un juego "> Únete al juego
comprar

por Daisy / Vista | Comprar | Comprar con criptomoneda



Juega Color Sudoku en línea - Juego de Colordoku gratis Este es un juego Free Free to Play Color Sudoku (Colordoku).

por Daisy / Vista | Comprar | Comprar con criptomoneda


Práctico aprendizaje profundo basado en la web y seguridad con el ejemplo Tercera edición Charlotte Harper 3 de julio de 2024 Prefacio: Las consideraciones de seguridad en la creación de software para la web son una parte importante del plan y la ejecución del desarrollador web, mientras que ingeniería un prototipo que es confiable, estable y útil para fines prácticos. El DOM (marcado de objeto de documento), con su implementación de HTML, JavaScript y CSS, así como software de backend implementando Python, C/C ++, Java y Bash, brindan a los desarrolladores web la libertad y el poder de crear una amplia variedad de proyectos que expresan creatividad, proporcionar facilidad de uso y funcionalidad, retratar humildad y carácter, y proporcionar facilidad de uso, así como conveniencia y servicios importantes que son atractivos para el Joe promedio, el usuario final que busca Mata el tiempo o haga algo en Internet, generalmente en un dispositivo de teléfono inteligente con pantalla táctil. La mayoría de las personas ni siquiera sabrían por dónde comenzar cuando quieren construir un sitio web desde cero,Tenderán a comenzar en el sitio web de otra persona y construir algo limitado en funcionalidad, confiabilidad, facilidad de uso y especialmente creatividad cuando podrían haber tenido todas las últimas herramientas poderosas a su disposición para construir algo útil sin perder el tiempo presionando botones y Especialmente desperdiciando dinero pagando suscripciones costosas al software que pocas personas querían usar de todos modos dadas sus limitaciones en facilidad de uso y flexibilidad. Si tiene unos minutos para leer este libro y aprender lo que quiero enseñarle, o incluso hablar conmigo personalmente sobre sus objetivos y obtener alguna orientación en la dirección correcta, y está motivado para aprender a codificar y escribir su propio software. , Lleve este libro a casa y deje de lado un tiempo para aprender a construir la próxima aplicación web influyente, poderosa, aerodinámica e importante, un sitio web que se trata de usted y hace exactamente lo que desea y satisface las necesidades de su audiencia. Acerca de mí: Soy un desarrollador de software con un amplioAnge of Experience in C/C ++, Java, Python, HTML, CSS y JavaScript. Construyo sitios web que las personas quieren usar, quieren visitar e incluso me pongo adicto al uso solo para aprender, recrear y matar el tiempo, y lo más importante, vendo software. Si tuvo una idea de cómo quería que se viera y funcionara un sitio web, estaba dispuesto a apoyarme para que pueda satisfacer mis propias necesidades mientras me encuentro con las suyas, y está dispuesto a cubrir los costos de ejecutar un sitio web usted mismo, Te construiría el próximo YouTube, Tiktok, Twitter, Google o incluso una aplicación de seguridad de alta tecnología que solo usted pueda acceder. En lugar de tratar de venderte mi tiempo, estoy tratando de comprar el tuyo: quiero convencerte de que construir una aplicación (sitio web) tú mismo con la información que ya existe y enseñarte lo que necesitas para ser un desarrollador de software independiente, Emprendedor, liderando una carrera exitosa en cualquier campo que desee. Y déjame ser claro, la educación que te doy será informal. Podrías ir a la escuela y aprender todo esto con unLa educación RMAL, o incluso lee este libro en la escuela, complete sus tareas y elimine mucho de su educación, pero no lo pondré formalmente en el asiento caliente y le pediré que complete las tareas. No soy tu profesor, puedes pensar en mí como un amigo que quiere guiarte hacia una carrera impulsada por tu propio éxito personal. Y tampoco vendo su éxito, tendrá que comprarlo con su tiempo. Aprender a codificar tiene una curva de aprendizaje empinada y nunca fue fácil, o se suponía que fuera. Debe trabajar tan duro como sea posible y continuar intentando y no fallando e intentando nuevamente cuando esté frustrado para aprender y construir aplicaciones usted mismo. Eso está en la naturaleza del código en sí. El código está ejecutado por un compilador diseñado para darle al programador mensajes de error, y esto le enseñará cómo codificar, incluso si simplemente está copiando el error en su motor de búsqueda y leyendo los ejemplos de otras personas. Y debo decir que no necesitas ser extremadamente rico, inteligente, exitoso,En detalles orientados u organizados para construir una aplicación. La computadora se encarga de esa organización por usted. Solo necesita perseverar a través de la prueba y el error, mantener el enfoque y trabajar duro en lo que hace, y tendrá una carrera muy exitosa en la totalidad de lo que hace. Quien soy: Me doy cuenta de que la última sección fue más sobre el aprendizaje y que se llevan de manera de este libro. ¿Quién soy exactamente? Esa es una pregunta complicada. No estoy claro que yo mismo, ya que sufro de condiciones médicas que pueden dificultarme la codificación o escribir este libro a veces, al tiempo que presento desafíos con los problemas de socialización e identidad que me hacen la vida más difícil cuando se trata de presentarme a mí mismo. . En resumen, si está leyendo este libro, lo trajiste a casa porque lo hundiste y pensaste que era útil, o incluso si solo lees tan lejos, soy una persona de mentalidad similar que quiere verte tener éxito todo lo que haces. Yo mismo soy ingeniero, un softwaredesarrollador y estudiante, y estoy escribiendo este libro para otros estudiantes que desean facilitar la vida al tener un manual del software que necesitan facilitar la vida dando ejemplos para copiar que encajen como un gran rompecabezas en un trabajo que trabaja. , Aplicación útil, grande, funcional, cohesiva y atractiva que puede impulsar el éxito sin importar la línea de negocios. En gran medida, esto es lo que hago: construyo aplicaciones para ayudarme a mí y a otras personas a tener éxito. También soy autor, aunque esta es mi primera publicación que tengo la intención de completar para armar mi cartera en un documento útil, y también soy un artista. Te admitiré esto, soy una especie de persona extraña. No soy perfecto, he corrido con la ley incluso que me llevó a dejar colegios y universidades y dejar estados para tratar de hacerse un nombre con más éxito. Soy mujer de nacimiento, uso maquillaje, tomo fotos de mí mismo, uso vestidos y otras ropa para mujeres, y me mantengo consciente de mí mismo comohombre por naturaleza. He tenido problemas con otras personas en el pasado que conducen a las luchas con la escritura y la construcción de las aplicaciones web, y me disculpo por no haber podido poner este libro en sus manos antes: lo necesitabas. Querrá leer y escribir un código que se parezca al mío y funcione como el mío y haga lo mismo, pero aún mejor, porque si puede permitirse comprar este libro en lugar de mezclar su teclado como lo hago para crear un libro usted mismo para preguntar dinero. Para ello, tiene los recursos que necesita para tener éxito en su vida. Tuve todo tipo de problemas con el crecimiento familiar, las condiciones de salud, los médicos, los medios de comunicación y la ley, y mi código refleja profundamente la lucha que es el feminismo y la naturaleza femenina en un mundo dividido y frustrado. Sin embargo, este libro es algo que me importa profundamente, mi bebé, mi cartera y mi sustento, por lo que agradezco su consideración cuando lleva el texto a casa y cuidadosamente por encima de él para aprender de mí. Tenga en cuenta que no soy perfecto,El libro tendrá errores, revisiones y nuevas ediciones, y deberá pensar con su cerebro lógico lo mejor que pueda para tener una experiencia exitosa con mi escritura. Además, comprenda que quiero decir bien para usted incluso cuando enfrenta desafíos al escribir. Piénselo así: cuando puede alquilar un sistema informático para hacer cualquier cosa que pueda imaginar en el espacio digital, almacenar toda la información que encuentre, #$%! Yze y organizarlo, y llegar a comprenderlo, lo hará. Inevitablemente, encuentre dificultades con la información que está ingeriendo e incluso publicando. Te digo esto porque encuentro las mismas dificultades. Use este libro bajo su propio riesgo, trabaje con su comunidad y comunidades disponibles para construir un software dentro de un entorno seguro, y no lleve las cosas personalmente cuando fallas o incluso tengas éxito de la manera incorrecta: así es como llegué hasta aquí , y por qué puedo traerte este texto y ayudarte a tener éxito sin divergir en un camino de locura que dejaMe arruiné, desgarro y deshací mientras me encuentro con los problemas ordinarios que todos tienen a escala global gracias a la escala global paralelista de la red en la que trabajaremos, Internet. Es posible que no esté muy familiarizado con quién soy con solo unas pocas palabras, pero le animo a que siga leyendo, podrá conocerme mientras continúa leyendo y entendiéndome mientras construye sus propios proyectos para completar su trabajo. No habrá tarea con este libro, siempre que sus profesores o maestros no le asignen ninguna, pero le recomiendo que construya una cartera de proyectos usted mismo mientras lee, así como un proyecto de Capstone que muestra cómo puede Aplique lo que ha aprendido. Mi proyecto Capstone es la base de la mayoría de lo que leerá en este libro, ya que incorpora código de mis proyectos anteriores, código que he creado y aprendí a escribir metódicamente a mano, y una amplia gama de ideas y consejos que me han ayudado. tener éxito hasta el punto en que pueda girar una aplicación simple que esUly presentó, se ve y se comporta como una aplicación popular que puede ver a su amigo o familia que usa, en Internet, anunciado para usted o en las noticias. Que es este libro: Este libro es un tutorial con el ejemplo. Puede encontrar código aquí, instrucciones sobre cómo aprender a codificar, información sobre el código de depuración y solucionar errores, solucionar pasos, instrucciones sobre cómo hacer una copia de seguridad y guarda...
Aprendizaje profundo y seguridad prácticos basados ​​en la web con el ejemplo

Práctico aprendizaje profundo basado en la web y seguridad con el ejemplo Tercera edición Charlotte Harper 3 de julio de 2024 Prefacio: Las consideraciones de seguridad en la creación de software para la web son una parte importante del plan y la ejecución del desarrollador web, mientras que ingeniería un prototipo que es confiable, estable y útil para fines prácticos. El DOM (marcado de objeto de documento), con su implementación de HTML, JavaScript y CSS, así como software de backend implementando Python, C/C ++, Java y Bash, brindan a los desarrolladores web la libertad y el poder de crear una amplia variedad de proyectos que expresan creatividad, proporcionar facilidad de uso y funcionalidad, retratar humildad y carácter, y proporcionar facilidad de uso, así como conveniencia y servicios importantes que son atractivos para el Joe promedio, el usuario final que busca Mata el tiempo o haga algo en Internet, generalmente en un dispositivo de teléfono inteligente con pantalla táctil. La mayoría de las personas ni siquiera sabrían por dónde comenzar cuando quieren construir un sitio web desdeScratch, tenderán a comenzar en el sitio web de otra persona y construir algo limitado en funcionalidad, confiabilidad, facilidad de uso y especialmente creatividad cuando podrían haber tenido todas las últimas herramientas poderosas a su disposición para construir algo útil sin perder el tiempo de los botones y especialmente desperdiciar dinero pagando suscripciones costosas al software que pocas personas querían usar de todos modos dadas sus limitaciones en facilidad de uso y flexibilidad. Si tiene unos minutos para leer este libro y aprender lo que quiero enseñarle, o incluso hablar conmigo personalmente sobre sus objetivos y obtener alguna orientación en la dirección correcta, y está motivado para aprender a codificar y escribir su propio software. , Lleve este libro a casa y deje de lado un tiempo para aprender a construir la próxima aplicación web influyente, poderosa, aerodinámica e importante, un sitio web que se trata de usted y hace exactamente lo que desea y satisface las necesidades de su audiencia. Acerca de mí: Soy un desarrollador de software conRango de experiencia en C/C ++, Java, Python, HTML, CSS y JavaScript. Construyo sitios web que las personas quieren usar, quieren visitar e incluso me pongo adicto al uso solo para aprender, recrear y matar el tiempo, y lo más importante, vendo software. Si tuvo una idea de cómo quería que se viera y funcionara un sitio web, estaba dispuesto a apoyarme para que pueda satisfacer mis propias necesidades mientras me encuentro con las suyas, y está dispuesto a cubrir los costos de ejecutar un sitio web usted mismo, Te construiría el próximo YouTube, Tiktok, Twitter, Google o incluso una aplicación de seguridad de alta tecnología que solo usted pueda acceder. En lugar de tratar de venderte mi tiempo, estoy tratando de comprar el tuyo: quiero convencerte de que construir una aplicación (sitio web) tú mismo con la información que ya existe y enseñarte lo que necesitas para ser un desarrollador de software independiente, Emprendedor, liderando una carrera exitosa en cualquier campo que desee. Y déjame ser claro, la educación que te doy será informal. Podrías ir a la escuela y aprender todo esto con unLa educación formal, o incluso lee este libro en la escuela, complete sus tareas y elimine mucho de su educación, pero no lo pondré formalmente en el asiento caliente y le pediré que complete las tareas. No soy tu profesor, puedes pensar en mí como un amigo que quiere guiarte hacia una carrera impulsada por tu propio éxito personal. Y tampoco vendo su éxito, tendrá que comprarlo con su tiempo. Aprender a codificar tiene una curva de aprendizaje empinada y nunca fue fácil, o se suponía que fuera. Debe trabajar tan duro como sea posible y continuar intentando y no fallando e intentando nuevamente cuando esté frustrado para aprender y construir aplicaciones usted mismo. Eso está en la naturaleza del código en sí. El código está ejecutado por un compilador diseñado para darle al programador mensajes de error, y esto le enseñará cómo codificar, incluso si simplemente está copiando el error en su motor de búsqueda y leyendo los ejemplos de otras personas. Y debo decir que no necesitas ser extremadamente rico, inteligente,Essful, o incluso detalles orientados u organizados para construir una aplicación. La computadora se encarga de esa organización por usted. Solo necesita perseverar a través de la prueba y el error, mantener el enfoque y trabajar duro en lo que hace, y tendrá una carrera muy exitosa en la totalidad de lo que hace. Quien soy: Me doy cuenta de que la última sección fue más sobre el aprendizaje y que se llevan de manera de este libro. ¿Quién soy exactamente? Esa es una pregunta complicada. No estoy claro que yo mismo, ya que sufro de condiciones médicas que pueden dificultarme la codificación o escribir este libro a veces, al tiempo que presento desafíos con los problemas de socialización e identidad que me hacen la vida más difícil cuando se trata de presentarme a mí mismo. . En resumen, si está leyendo este libro, lo trajiste a casa porque lo hundiste y pensaste que era útil, o incluso si solo lees tan lejos, soy una persona de mentalidad similar que quiere verte tener éxito todo lo que haces. Yo mismo soy ingenierodesarrollador y estudiante, y estoy escribiendo este libro para otros estudiantes que desean facilitar la vida al tener un manual del software que necesitan facilitar la vida dando ejemplos para copiar que encajen como un gran rompecabezas en un trabajo que trabaja. , Aplicación útil, grande, funcional, cohesiva y atractiva que puede impulsar el éxito sin importar la línea de negocios. En gran medida, esto es lo que hago: construyo aplicaciones para ayudarme a mí y a otras personas a tener éxito. También soy autor, aunque esta es mi primera publicación que tengo la intención de completar para armar mi cartera en un documento útil, y también soy un artista. Te admitiré esto, soy una especie de persona extraña. No soy perfecto, he corrido con la ley incluso que me llevó a dejar colegios y universidades y dejar estados para tratar de hacerse un nombre con más éxito. Soy mujer de nacimiento, uso maquillaje, tomo fotos de mí mismo, uso vestidos y otras ropa para mujeres, y me mantengo consciente de mí mismo comomujer por naturaleza. He tenido problemas con otras personas en el pasado que conducen a las luchas con la escritura y la construcción de las aplicaciones web, y me disculpo por no haber podido poner este libro en sus manos antes: lo necesitabas. Querrá leer y escribir un código que se parezca al mío y funcione como el mío y haga lo mismo, pero aún mejor, porque si puede permitirse comprar este libro en lugar de mezclar su teclado como lo hago para crear un libro usted mismo para preguntar dinero. Para ello, tiene los recursos que necesita para tener éxito en su vida. Tuve todo tipo de problemas con el crecimiento familiar, las condiciones de salud, los médicos, los medios de comunicación y la ley, y mi código refleja profundamente la lucha que es el feminismo y la naturaleza femenina en un mundo dividido y frustrado. Sin embargo, este libro es algo que me importa profundamente, mi bebé, mi cartera y mi sustento, por lo que agradezco su consideración cuando lleva el texto a casa y cuidadosamente por encima de él para aprender de mí. Tenga en cuenta que no soyECT, este libro tendrá errores, revisiones y nuevas ediciones, y deberá pensar con su cerebro lógico lo mejor que pueda para tener una experiencia exitosa con mi escritura. Además, comprenda que quiero decir bien para usted incluso cuando enfrenta desafíos al escribir. Piénselo así: cuando puede alquilar un sistema informático para hacer cualquier cosa que pueda imaginar en el espacio digital, almacenar toda la información que encuentre, #$%! Yze y organizarlo, y llegar a comprenderlo, lo hará. Inevitablemente, encuentre dificultades con la información que está ingeriendo e incluso publicando. Te digo esto porque encuentro las mismas dificultades. Use este libro bajo su propio riesgo, trabaje con su comunidad y comunidades disponibles para construir un software dentro de un entorno seguro, y no lleve las cosas personalmente cuando fallas o incluso tengas éxito de la manera incorrecta: así es como llegué hasta aquí , y por qué puedo traerte este texto y ayudarte a tener éxito sin divergir en un camino de locuraAves me arruinó, desgarro y deshilaché mientras me encuentro con los problemas ordinarios que todos tienen a escala global gracias a la escala global paralelista de la red en la que trabajaremos, Internet. Es posible que no esté muy familiarizado con quién soy con solo unas pocas palabras, pero le animo a que siga leyendo, podrá conocerme mientras continúa leyendo y entendiéndome mientras construye sus propios proyectos para completar su trabajo. No habrá tarea con este libro, siempre que sus profesores o maestros no le asignen ninguna, pero le recomiendo que construya una cartera de proyectos usted mismo mientras lee, así como un proyecto de Capstone que muestra cómo puede Aplique lo que ha aprendido. Mi proyecto Capstone es la base de la mayoría de lo que leerá en este libro, ya que incorpora código de mis proyectos anteriores, código que he creado y aprendí a escribir metódicamente a mano, y una amplia gama de ideas y consejos que me han ayudado. tener éxito hasta el punto en que pueda girar una aplicación simple queTotalmente destacado, se ve y se comporta como una aplicación popular, puede ver a su amigo o familia usar, en Internet, anunciarse para usted o en las noticias. Que es este libro: Este libro es un tutorial con el ejemplo. Puede encontrar código aquí, instrucciones sobre cómo aprender a codificar, información sobre el código de depuración y solucionar errores, solucionar pasos, instrucciones sobre cómo hacer una copia de seguridad y guardar su código, volver a implementar si alguien rompe su código, asegura su código, implementa Su código, crea sitios web interactivos que sean entretenidos, atractivos y adictivos, y tendrá una idea de quién soy, por qué esto es importante y cómo retratarse a sí mismo, a su aplicación e imagen de la empresa, así como a El software que construye en la mejor luz absoluta para ser lo más atractivo posible para sus usuarios finales, los visitantes de su sitio web. En este libro, demostraré una serie de ejemplos de diseño de software con un enfoque en la web como una plataforma y seguridad. Iniciaremos la experiencia de aprendizaje construyendo unOject usando la carcasa Unix, con características de copia de seguridad y secuencias de comandos. Luego, examinaremos un sitio web básico de blog, actualizaremos nuestro blog con características de fotos y video, así como usaremos estas características para emplear soluciones de seguridad utilizando software gratuito y asegurar nuestro servidor utilizando un módulo de autenticación conectable (PAM). Luego revisaremos el manejo y el procesamiento de archivos, explorando la edición de video, la donación de voz, el escaneo de códigos de barras y el reconocimiento de caracteres ópticos, entre otros conceptos. En el camino, examinaremos las API que nos ayudarán a hacer que nuestro software sea más útil y seguro, con opciones gratuitas y pagas. En el camino, exploraremos la seguridad física y las herramientas militantes, como las armas de fuego y el diseño y la fabricación de municiones, incluido el diseño del barril y el repetidor, el diseño de torretas y drones, y otros directores que integraremos con nuestro software en la red existente para proteger nuestro software y demostrar la autodefensa y la reillabilidad. Tomaremos descansos en el camino para construir juegos, 2d y 3dEntrones que respaldan y trabajan con hardware integrado en estudio de caso de ejemplos de software de representación dimensional básica y un masajeador vibratorio electrónico fundido en caucho de silicona respectivamente. En el camino, también emplearemos soluciones de aprendizaje automático ya disponibles para asegurar mejor nuestro software. También emplearemos herramientas de stock disponibles para la Web para optimizar y asegurar el proceso. Este libro es una guía para su éxito en la creación de una aplicación web e integrarla con una red profesional de computadora y sistemas mecánicos integrados, y en general una guía para construir software y hardware integrado sin conocimiento de fondo o experiencia previa. Lo que este libro no es: Si realmente desea tener un sitio web, puede configurar una tienda simple y vender lo que necesita, publicar un blog, publicar fotos o videos o de otra manera sin escribir una sola línea de código. Este libro no es ese. Este libro le enseñará cómo crear un software que sea más útil, completamentedestacado, funcional y seguro que cualquier software que ya pueda encontrar, porque implementa el último software que todavía es prototipos, puede ser costoso de ejecutar a una escala en la que operan las compañías más antiguas y no atrae a las compañías en contra y en retraso de Gane dinero para personas que realmente no están haciendo nada. Si sigue este libro de cerca, querrá escribir código, código de investigación, crear sus propias aplicaciones y ganará dinero con lo que hace. Ganaré dinero con este libro, incluso en las primeras etapas, porque contiene información que las personas necesitan y quieren leer, y ya están comprando cuando compran o usan mis aplicaciones. Este libro no creará una aplicación para usted, pero le declarará en la dirección correcta y le armará las herramientas que necesita y las habilidades y consejos que facilitarán su propio éxito en la creación de software para la web, con cada línea de Código que deberá escribir como ejemplo, listo para ser reconstruido en el software que usted y sus seguidores, invitados, clientela,Los amigos, la familia, los visitantes, los contratistas y las personas de Internet quieren usar y apoyar. Lo que aprenderás: Este libro le enseñará cómo construir y vender software, realmente funcional, software útil, grabación de medios, características de seguridad como reconocimiento facial, escaneo de código de barras de zona legible de máquina, API web para autenticar, grabar y realizar videos e fotos, e intercambiar mensajes como Bluetooth y comunicación cercana al campo (NFC). Este libro le enseñará cómo usar una computadora en red, centrándose en Debian Linux, cómo construir el código BASH para que la instalación y el respaldo de su software sean una brisa perfecta y automatizada, cómo construir el código de Python como un backend para servir mensajes dinámicos, estilo Las cosas utilizan bien los estilos CSS con Bootstrap, habilitan los inicios de sesión de usuario e interactividad a través de dispositivos en red, creen medios interactivos y redes con otros sitios web para ofrecer características de seguridad como mensajes de texto para verificación o verificación o Otros propósitos, escaneo de identificación, moderación de imagen y video, datosRansacciones para mantener su software seguro, procesamiento de pagos, comercio de criptomonedas, tareas asincrónicas y más. Aprenderá a construir sus propios dispositivos Bluetooth, con baterías, cargadores, microcontroladores, circuitos, motores y sensores, usando soldadura, cable y 3D impresos, así como materiales fundidos. Demostraré a los principios de diseño 3D aplicados a la fabricación de herramientas y la fabricación de herramientas y matrices, por lo que puede fabricar sus propios dispositivos de hardware integrados con baterías integradas, cargadores, circuitos electrónicos y salidas funcionales. y contabilizarlos con Bluetooth y la web. Específicamente, examinaremos dos estudios de casos, un masajeador vibrante y un arma de fuego casera, ambos programados en OpenSCAD, que está disponible como una interfaz gráfica o utilidad de línea de comandos y puede integrarse en una web para obtener resultados más rápidos. Aprenderá cómo construir e implementar un sitio web desde cero sin experiencia previa, hacerlo funcional, seguro, hermoso, útil y másmortantemente práctico. Aprenderá cómo usar el aprendizaje automático y la visión por computadora para hacer que un sitio sea seguro y más práctico, grabar video y audio desde su sitio web, donar su voz, hacer música y modular audio para crear muestras útiles y cómo romper el ruido. Aprovechar otros sitios web para crear la mejor red posible de sitios web que pueda vincular directamente a los suyos para compartir toda la información útil que tiene para ofrecer y, lo que es más importante, traer a las personas a su software y negocio. Este libro se centrará más en los medios, la seguridad y el aprendizaje automático, que son los tres principales componentes que lo ayudarán a desarrollar un software útil para la Web al involucrar a los usuarios adecuados y desconectar a los incorrectos de una manera realista, práctica, práctica, práctica, práctica, práctica, práctica. Manos puestos y atractivos mientras también es automático y resistente. Este libro enseña Unix, específicamente Debian (Ubuntu), Bash Shell, Python, HTML, CSS, JavaScript y una serie de paquetes de software útiles paran Solicitudes, así como un software BASH útil como Git y FFMPEG. También le enseñaré cómo intercambiar criptomonedas automáticamente, y tomar pagos en criptomonedas o de tarjetas de débito regulares mientras incluso pagará a sus visitantes una parte de sus ingresos si elige hacerlo. También le enseñaré cómo ganar dinero con su sitio web a través de la publicidad, cómo preparar su aplicación para los motores de búsqueda y hacerlo rápido, clasificado en la primera clasificación para lo que sus clientes buscarán para encontrarlo y clasificando tantos comunes. Búsquedas como sea posible. Le enseñaré cómo vender su software, anunciarlo, atraer a los clientes que buscan sus servicios y hacer un nombre en Internet a través de avenidas que ya existen, son económicos y funcionan bien. Le enseñaré cómo guardar sus datos en computadoras en la nube que funcionan para usted y guardar sus datos a bajo precio, cómo planificar y crear un sitio web que haga lo que sus usuarios quieran y lo que desean, y cómo mantener a sus usuarios comprometidos conSu sitio se aleja en sus teléfonos con notificaciones, correo electrónico, mensajes de texto, llamadas telefónicas y más vías para llevar a sus usuarios a su sitio web a su disposición detrás del clic de un botón asegurado solo para usted. Este libro se centrará en la practicidad de publicar y distribuir medios en grandes cantidades, desde texto hasta fotos, videos y audio, causar una buena impresión en los usuarios finales (su clientela) y vender de cualquier manera que haga para crear Un sitio web, una aplicación que es representativa de usted y solo, y hace que usted, su software y su empresa se vean bien de la mejor manera posible. También aprenderá algunos consejos y trucos de mí, desde consejos de codificación, tocador práctico como maquillaje y fotografía, modelado y actuación, y más, lo que será importante para retratarse a sí mismo y a su empresa de la mejor manera posible utilizando todas las herramientas disponibles. para usted mientras distribuye tanto contenido como necesita en un equilibrio saludable de plataformas para traer sue para fructificar sin más esfuerzo, trabajo o dinero de lo necesario. Este libro se llama "aprendizaje profundo y seguridad basados ​​en la web prácticos con el ejemplo" por una razón: se trata de aprender a codificar, específicamente para la web, específicamente con un enfoque en la seguridad, desde un punto de vista práctico, con ejemplos de código de trabajo que sirve Los propósitos prácticos se describen en el texto. El componente de aprendizaje de este texto también abarca el aprendizaje automático, el código que le mostraré cómo ejecutar para la web que manejará la visión por computadora, el reconocimiento facial, la moderación de imágenes y videos, la mejora de la imagen, la mejora de la resolución, el subtítulos de imágenes y otras tareas como Las métricas de predicción provienen de imágenes, como la naturaleza de la imagen como una imagen auténtica, transferida por computadora o una copia óptica (una foto de una imagen o una foto impresa). El aprendizaje automático es muy importante cuando se trata de seguridad web y seguridad del software, ya que puede preformar tareas que de otro modo eran imposibles. Tu computadoraInicie sesión con un código de acceso, pero puede ser más seguro usarlo si lo inicia con su cara. Puede hacer que una computadora de servidor sea tan segura, una computadora que normalmente le pediría un nombre de usuario y un código de contraseña y lo inicia, tal vez con un token de confirmación para cada nuevo inicio de sesión o nueva dirección IP, pero si está construyendo a gran escala, fácil de Use, un software fundamentalmente seguro y potente, esto puede ser suficiente. Atar su software demasiado estrechamente con el software de otra persona, como un servicio de correo electrónico o servicio de mensajes de texto, no es suficiente para que su software sea seguro o el de cualquiera (cualquier sitio que use). Cualquiera que construya un software que sea impecablemente seguro tiene algún sentido de lo que esto implica. El software es inherentemente inseguro porque los dispositivos y las cuentas que usamos para acceder no siempre están a nuestra disposición, podrían estar en manos de cualquier persona con mala intención para el software y, por lo tanto, pueden representar un riesgo para el software en sí. Esto es algo del enfoque de este libro. Una computadora en red es de forma predeterminadaasegurado con un token de llave largo, llamado y clave SSH o shell segura, y de otra manera está mejor asegurado con un servidor web, porque el servidor web proporciona el acceso abierto y las herramientas de seguridad de última generación que se ejecutan en el servidor en sí. El servidor web tiene acceso al navegador web del usuario, que posiblemente es la parte más poderosa del dispositivo del usuario, porque es el lugar donde el usuario puede acceder al software en red. Este kit de herramientas puede representar el texto, las páginas web que ve, y también puede grabar imágenes, audio y video (como una foto de una cara o una identificación de estado), puede leer y escribir en dispositivos de radio Bluetooth, y puede leer y escribir en campo cercano Etiquetas de transponerador, tarjetas clave de bajo costo, FOBS, pegatinas, anillos e incluso implantes de chips con números de serie únicos que pueden leerse y escribir con datos generados y validados por un servidor web vinculado al sitio web. Usando todas las herramientas a su disposición, con este libro se equipará con el conocimiento para construir un sitio web seguro y, en general, unUre Sistema informático en red que funciona para usted, hace su oferta y se ve y se siente bien. Por dónde empezar: Puede saltar más allá de la sección que comience este libro con, o cualquier sección, al código exacto que necesita, especialmente si tiene experiencia con la codificación antes o cualquiera de las herramientas mencionadas que describiré en detalle en este libro como así como documentar casos de uso y ejemplos prácticos de los mismos. Si no tiene experiencia en el código de escritura, le recomiendo que lea todo este libro, y especialmente le recomiendo que lea las secciones anteriores, para asegurarse de que este libro sea adecuado para usted. Si este libro no es adecuado para usted, considere regalarlo a un amigo o pariente que podría estar interesado en aprender sobre el desarrollo web, e incluso considere tomar prestado y aprender de ellos para llenar los vacíos donde le fallé como El maestro u otros maestros hicieron delante de mí. Comience donde sea, cada parte de este libro será útil si tiene la intención de construir unPP, y considere que las mejores aplicaciones están construidas teniendo en cuenta el usuario final: conozca a su cliente. Ahora me conoces, conoces este libro y estás listo para comenzar. Para comenzar, tome una computadora (incluso la computadora portátil más barata de una tienda de cajas, Amazon, o un viejo escritorio funciona, y configúrela de una manera que funcione para usted. Cómo leer este libro: El texto resaltado, denota que el texto pertenece en un símbolo del sistema, donde escribirá el código que ejecuta. El símbolo del sistema está muy enfocado en el teclado y requiere poco o ningún clic, acelerar su flujo de trabajo y facilitarle las cosas. Empezando: Vamos a sumergirnos. Comenzaremos construyendo código en una máquina local y comenzaremos sin construir un sitio web conectado a Internet. Es más seguro comenzar, no cuesta nada y es fácil para usted. Dependiendo de su sistema operativo, entrar en un shell bash será un poco diferente. Para Mac OS, recomiendo instalar una máquina virtual en este momento, ya que obtendrá la mayor compatibilidad conmáquina virtual. Varios proveedores, como VirtualBox y Paralells, pueden ejecutar una máquina virtual para usted, aunque también es posible instalar Ubuntu directamente en la máquina, si prefiere usar un entorno nativo que se recomienda para crear una experiencia rápida y optimizada. Si está utilizando Linux o Windows, lo que recomiendo, debería ser bastante fácil crear un proyecto. Abra su terminal, ajuste el tamaño como mejore y comience a seguir el paso 2. Si está utilizando Windows, siga el paso 1. Paso 1: - Usuarios de Windows solamente En Windows, abra el símbolo del sistema como administrador y escriba WSL -Install Paso 2: - Continúe aquí o omita el paso 1 a aquí si no está usando Windows En un terminal abierto (dependiendo de su sistema operativo, llamado Ubuntu en Windows, terminal en Mac o Linux, o un nombre similar), comience creando un proyecto. Hacemos esto con el comando mkdir, que crea un directorio. Si necesita crear un directorio para almacenar su proyecto, que se recomienda, use elcomando de CD para cambiar al directorio y y CD/PATH/TO/Directory: la ruta es las carpetas (archivos) que preceden a su directorio de destino, su ruta predeterminada es ~ o/home/username (donde el nombre de usuario es su nombre de usuario). Para cambiar al directorio predeterminado, escriba CD o CD ~ Ejemplo de mkdir: reemplace el "ejemplo" con el nombre del directorio Ahora tiene un directorio de trabajo para su proyecto. Ser tan importante como es tan importante guardar este directorio en caso de que necesite cambiar a una máquina diferente o implementar el código que escriba para que esté listo para la web, construiremos un script para hacer una copia de seguridad de su directorio en los próximos pasos. Pero construir un script toma un poco de código, y el código debe ser automatizado para ser lo más útil posible. Así que construyamos primero un script para crear scripts. Comencemos creando el script y haciéndolo ejecutable. Usaremos sudo, chmod y touch para esto, y llamaremos al script


sudo touch /usr/bin/ascript
sudo chmod a+x /usr/bin/ascript
sudo nano /usr/bin/ascript
Ahora hemos creado el script, lo hicimos ejecutable y estamos listos para editarlo. Nano es un editor de texto que le permitirá editar texto sin hacer clic, lo que es mucho más fácil que usar una interfaz de usuario gráfica. Para editar un archivo con Nano, use Nano y luego la ruta al archivo. Para hacer un guión que haga un guión, es bastante similar a hacer nuestro guión en primer lugar. Usaremos el mismo código que el anterior, reemplazando el nombre del script, "Ascript" con un parámetro de argumento, $ 1. Esto nos permite llamar al script escribiendo Simply Sudo Ascript Newscript, momento en el que podemos crear cualquier nuevo script reemplazando el "periódico" con el nombre de su script. El código en Nano debería verse como:

sudo touch /usr/bin/$1
sudo chmod a+x /usr/bin/$1
sudo nano /usr/bin/$1
Y para cerrar Nano, podemos mantener presionada la tecla de control y presionar X, luego y para denotar estamos guardando el archivo y presione la devolución. Ahora, en lugar de escribir estos tres comandos para editar un script, podremos escribir sudo Ascript Ascript para editar el script nuevamente. ¡Esto funciona! Y cualquier nuevo script se puede ejecutar fácilmente llamándolo en el shell. Guardemos nuestro trabajo ahora: escribamos un script de copia de seguridad para guardar nuestro nuevo script y luego respaldarlo en nuestro directorio de proyectos, al tiempo que respalda el script de copia de seguridad.

sudo ascript backup
Ahora, en Nano:

sudo cp /usr/bin/backup /path/to/directory/
sudo cp /usr/bin/ascript /path/to/directory/
Donde/rath/to/directorio es la ruta al proyecto que creó con MKDIR. Más adelante aprenderemos a copiar rutas repetidas como esta con un bucle y una lista, que es menos código, pero por ahora mantengamos que sea simple y tengamos algunas líneas. Para ejecutar este script y hacer una copia de seguridad de su código, guarde el archivo en nano con control+x, y y regrese, y escriba el siguiente en su shell

backup
Si se le solicita una contraseña mientras lee este libro y sigue en el shell, ingrese su contraseña de usuario correctamente, tendrá tres intentos antes de que necesite volver a ejecutar el comando. Puede usar las flechas hacia arriba y hacia abajo para volver a ejecutar los comandos y editarlas, si necesita ejecutar algo dos veces. Presione simple hacia arriba y hacia abajo intermitentemente para seleccionar un comando, antes de editar el comando con las flechas derecha, izquierda y eliminar la tecla, así como el teclado, y ejecutarlo con return. ¡Felicidades! Se las arregló para crear un script de copia de seguridad increíble que respalde dos scripts de shell importantes en su directorio de trabajo. Podríamos mover las cosas más tarde a medida que el proyecto se hace más grande, pero esto funciona por ahora. Pasemos a hacer una copia de seguridad en la nube, usaremos GitHub para esto (aunque hay muchas otras soluciones GIT para la copia de seguridad, son todo lo mismo). software mientras los hace a un servidor, mientrasTambién le permite descargar copias completas de su software detrás de una contraseña o clave. Es fundamental para guardar su software, especialmente a medida que migramos a instancias de Linux aseguradas que a veces se rompen cuando falla una sola línea de código, dejándolo bloqueado mientras que su código podría no estar respaldado si no tiene la oportunidad de respaldarlo. arriba automáticamente, que cubriremos. Si aún no está utilizando una máquina virtual de Ubuntu en este momento, recomiendo usar una máquina virtual de Ubuntu en este punto porque le facilitará la vida al instalar todos los paquetes necesarios para crear un sitio web que funcione y preformar el aprendizaje profundo operaciones en su computadora. Moveremos el código a un servidor web en el futuro cercano, pero queremos asegurarnos de que haya al menos unas pocas capas de seguridad detrás de nuestro servidor web que sean resistentes al phishing y empleen una serie de paquetes de Linux para hacerlo. este. Si aún desea usar Mac OS, puede buscar e instalarE paquetes necesarios en línea, pero puede que no haya alternativas para cada paquete que este libro o serie cubrirá. Agreguemos algunos comandos para cometer nuestro trabajo con el script de copia de seguridad ejecutando el comando sudo ascript

# …
git add –all
git commit -m “backup”
git push -u origin master
Una vez más, controle X para guardar. Ahora necesitamos hacer una configuración única para este proyecto. Debido a que pronto será un proyecto GIT, no necesitamos escribir todos los comandos cada vez que implementemos desde un repositorio de Git, pero nos acostumbraremos a esto cuando escribamos nuestros scripts de implementación. Para comenzar, asegurémonos de estar en el directorio correcto e inicializar el repositorio de git y generar claves SSH.

cd /path/to/directory
git init
git branch -m master
ssh-keygen
Después de escribir ssh-keygen, la nueva clave debe guardar en la carpeta de inicio en una carpeta llamada .ssh. Se llama id_rsa.pub. Vamos a encontrar esta clave y copiarla. Para verlo,

cd ~
cat .ssh/id_rsa.pub
Copie el texto devuelto por el último comando y cree una cuenta con su proveedor Git (idealmente GitHub), antes de agregar la clave SSH a su cuenta. Una vez que tenga una cuenta, haga clic en el menú superior derecho e ingrese la configuración, antes de agregar su tecla SSH en las teclas SSH y GPG en el acceso en el menú. Seleccione Agregar una tecla SSH y agregue la suya pegándola y dándole un título, antes de guardar y regresar a GitHub para crear un nuevo repositorio. Esto es similar para otros proveedores de GIT, deberá leer su documentación. En la nueva configuración del repositorio, brinde a su repositorio un nombre descriptivo y decida si desea publicarlo y asegúrese de configurar aún no los archivos para su inclusión. Una vez que se crea el repositorio, copie el clon con URL SSH y péguelo en el siguiente comando.

git remote add git://… (your remote URL)
Ahora puede regresar a su repositorio con CD, estará familiarizado con esto. Prueba tu script de copia de seguridad ahora con copia de seguridad ¡Excelente! Ahora realmente podemos obtener la codificación. Instalemos Django ahora que tenemos una buena comprensión de Bash y Git. Django nos permitirá hacer una copia de seguridad automáticamente de nuestro software, Bash también puede hacerlo, pero Django debería tener una implementación más simple más segura (se puede deshabilitar y configurar más fácilmente). Para instalar software en Ubuntu, utilizaremos el comando sudo apt-get. Primero, actualicemos y actualicemos el software que ya teníamos. Esto se puede hacer con la actualización de sudo apt-get y la actualización de sudo apt-get -y. A continuación, instalemos Python y nuestro entorno virtual, el hogar de nuestro código, con el siguiente comando: sudo apt-get install python-is-python3 python3-henv Esto es todo lo que necesita para obtener con Django en términos de instalaciones de software en la instancia de Ubuntu. Para Windows y Linux, esto debería ser bastante sencillo, pero para Mac es posible que desee instalar una máquina virtual yLinux en él utilizando un entorno virtual gratuito o pagado como VirtualBox o Paralells Desktop y recree los pasos anteriores para configurar un entorno Ubuntu. Ubuntu es crítico en este caso porque es el software que ejecutan los sitios web y les permite alojar sitios web con todo el software antes mencionado. Cavemos en el Django. En nuestro directorio nuevamente, con

python -m venv venv # Crea el entorno virtual donde se almacena el código
source venv/bin/activate # Activa el entorno virtual
pip install Django
django-admin startproject mysite . # Donde MySite es el proyecto que estoy comenzando en mi directorio actual.
Django recién nos inicia, porque Django está alojando el servidor web y está haciendo todo lo que necesitamos para que un sitio web local básico esté en funcionamiento. Ahora que tenemos a Django instalado, editemos un poco la configuración para que funcione como necesitamos. Primero, creemos una nueva aplicación

python manage.py startapp feed
Notarás que la primera aplicación se llama Feed. La aplicación debe llamarse lo que desee, y crearemos nuevas aplicaciones, pero el nombre de cada aplicación debe ser consistente cada vez que se hace referencia a la aplicación en el código. Para agregar una nueva aplicación, siempre editaremos el settings.py en el otro directorio que se creó la aplicación, nombrada en StartProject, en adelante, la aplicación. Usando nano,

nano app/settings.py
En la configuración, encuentre instalado_apps y separe los [] en 3 líneas. Usando cuatro espacios en la línea central vacía, agregue 'feed' o el nombre de su aplicación. Esta sección de settings.py debería verse como:

INSTALLED_APPS = [
    'feed',
]
Antes de olvidar, probemos que Django está funcionando. Usando el comando python managem.py runServer 0.0.0.0:8000, podemos ejecutar el servidor y luego navegar en un navegador web en la computadora que ejecuta el código a http: // localhost: 8000 y ver una página web de ejemplo (¡funciona!) Renuncie al servidor con Control C, lo mismo que cualquier otro comando. Ahora, cavemos en la escritura de código Python. Django tiene tres componentes principales, todos ejecutados por código por completo. Los componentes se denominan modelo, vista y plantilla, y cada uno está en un nivel superior y más bajo respectivamente antes de que la página web se entregue al usuario. El modelo es el código que almacena información en la base de datos para recuperación, clasificación y representación. La vista decide cómo se representa, manipula y modifica el modelo, casi todas las vistas usarán un modelo directamente. La plantilla es el código HTML con algunas campanas y silbatos adicionales llamados lenguaje de plantilla. La plantilla se convierte en la vista donde está llena de código Python ycontexto como modelos e información (cadenas e enteros de USUALL) desde la vista. Django también tiene otros componentes, incluidos, entre otros:: Configuración, que configura la aplicación como discutimos. URLS, que son patrones que el usuario sigue para obtener acceso a partes específicas de la aplicación web. Formularios, que definen cómo la información que se envía al servidor se maneja y se representa a la base de datos, así como al usuario. Estas son la base del procesamiento de la información en el lado del servidor, y pueden aceptar cualquier tipo de información que las almacenes de la computadora, sobre todo, las cadenas de texto, los números y los booleanos verdaderos/falsos (generalmente casillas de verificación). Plantillas, que son código HTML y lenguaje de plantilla y cierran la brecha entre Python y HTML, lo que significa que la información de Python puede servirse como código HTML al que cualquiera puede acceder y puede asegurar un sitio web con acceso restringido, al tiempo que hace que el código de Python sea accesible para la Web y útil. para una variedad de propósitos en un dispositivo remoto que noeed para estar cerca del servidor. Archivos estáticos, que generalmente son JavaScript y sus bibliotecas a las que el servidor sirve y están vinculados con la plantilla. Archivos multimedia, a los que el servidor sirve o está alojado externamente, o simplemente se escriben al servidor antes de ser procesado y publicado en otro servidor (un cubo) para alojamiento. Middleware, que es piezas de código que se ejecutan al mismo tiempo que cada vista y se consideran "incluidos" en la vista. Procesadores de contexto, que procesan el contexto de cada vista y se utilizan para agregar un contexto adicional. Pruebas, que validan que el usuario o la solicitud pasa ciertos requisitos antes de que se represente la vista. Los consumidores, que dictan cómo las redes web se manejan y responden a la comunicación. Admin, que se utiliza para registrar modelos para que puedan manipularse en detalle dentro de la página de administración de Django, donde la base de datos se puede administrar a través de una interfaz gráfica. Celery, que define tareas asincrónicas, las partes del código Django pueden comenzarnning antes de proceder inmediatamente a la siguiente tarea o línea de código. Django puede tener muchos otros componentes, que discutiremos en detalle aquí. Hay muchas maneras de hacer que Django sea más funcional, agregando WebSockets, que son canales de comunicación rápidos y simplificados, apio, que ejecuta tareas asincrónicas y una multitud de otras piezas de software para extender el django, especialmente en las funciones de vista, donde la mayor parte de el código se ejecuta. Las funciones de vista son clave porque generalmente declaran cada pieza de código específico para un patrón de URL específico o una sección del servidor. Primero, exploremos las funciones de vista. Las funciones de la vista comienzan con las importaciones que denotan código que se utilizará en la vista, y se definirán utilizando definiciones o clases regulares de funciones. Las vistas más simples están definidas por la definición de función DEF, y devuelven un httpResponse con una plantilla básica. Comencemos definiendo una visión básica para devolver el texto "Hola mundo". Recuerda que cada vez que agregasPara una declaración como DEF, si, mientras, para, etc., necesitará agregar 4 espacios para cada una de las definiciones previas que desea aplicar a su función. Entraremos en lo que cada uno de estos significa pronto. Desde el directorio de nuestro sitio, edite el archivo Feed/Views.py con Nano y agregue las siguientes líneas al final del

from django.http import HttpResponse

def hello(request):
    return HttpResponse('hello world')
HTTPRESPONS de Django responde con una cadena de texto, denotada con la apertura y el cierre '. Cada vez que pasa información a una función o clase, como solicitud o una cadena, deberá usar paréntesis (, apertura y cierre). Esto no es todo lo que necesitamos para ver nuestra opinión todavía. Por supuesto, no le hemos dicho al servidor dónde está la vista exactamente, todavía necesitamos definir una ruta por la cual la vista debe ser representada. Comencemos definiendo una ruta básica en APP/URLS.py, y entraremos en grupos de ruta más tarde. En APP/URLS.py, agregue una línea después de las declaraciones de importación después del principio importando la vista que acabamos de crear.

from feed import views as feed_views
Ahora, definamos el patrón de vista. Los patrones de vista tienen tres componentes, el componente de ruta, que le indica al servidor dónde existe la vista dentro del servidor (la ruta de URL que el usuario escribe en la barra de navegación para ingresar a la página web), el componente de vista donde se especifica la vista y un Nombre amigable para la vista, por lo que es fácil recuperar su patrón cuando se trabaja con una plantilla, especialmente por lo que su nombre se puede cambiar y actualizarse si es necesario para hacer espacio para otra vista o adquirir un nombre más lógico. Tiene sentido hacer las cosas de esta manera y ser flexible, porque su base de código será un entorno siempre cambiante que necesita flexibilidad e improvisación para ser valioso y fácil de trabajar. Así es como se verá su punto de vista, puede agregar esto a UrlPatterns = [Sección de APP/URLS.py. El patrón de vista se define con los tres componentes descritos anteriormente, y una función llamada ruta. Sus patrones de URL son una lista, así que asegúrese de terminar siempre cada elemento en elloscon una coma, porque esto separa cada una. Cada elemento también debe ir a una nueva línea, una vez más con cuatro espacios antes, al igual que la aplicación en Settings.py. Definiremos el primer componente de la vista con una función de cadena vacía, para crear una vista que se ejecute en el directorio raíz del servidor web. Tus urls.py ahora deberían verse como

from feed import views as feed_views

urlpatterns = [
    path('', feed_views.hello, name='hello'),
]
Esta es la base para crear un sitio web con Django que es completamente estático. Para hacer un sitio web más dinámico donde podamos comenzar a almacenar en caché la información, como imágenes, videos, audio y más, necesitaremos usar modelos, que exploraremos a continuación. Por ahora, revisemos nuestro código y ejecutemos el servidor. Para verificar el código en busca de errores, ejecute:

python manage.py check
Si hay algún mensaje de error, debe revisar cuidadosamente los cambios que realizó en su aplicación y ver si hay algo que sea necesario, como un espacio extraño o que falta, un carácter adicional, una cadena no cerrada, cualquier error tipográfico, cualquier accidente accidentalmente personaje eliminado o cualquier otra cosa. Leer el mensaje de error (si tiene uno), debería poder ver la ruta a un archivo que creó o editó junto con un número de línea, así que busque ese archivo y línea y ver si puede solucionar cualquier cosa que esté allí. . Si ha solucionado el problema, ejecute nuevamente el comando anterior. Cuando su software está listo para ejecutarse y está funcionando, verá la salida "Comprobación del sistema no identificó problemas". Ahora estás listo para ir. Ejecute el servidor con:

python manage.py runserver 0.0.0.0:8000
Ahora abra un navegador web y navegue a http: // localhost: 8000. Debería ver el texto devuelto entre paréntesis y citas de la función httpresponse en su opinión. Este es solo un ejemplo básico, pero si llegó tan lejos, comprende los conceptos básicos de cómo funcionan Linux, Bash, Python y Django. Profundicemos en algún modelado de bases de datos y exploremos el poder de una clase de Python para almacenar información. Luego, comenzaremos a controlar HTML y CSS antes de hacer que nuestro sitio sea completamente destacado, flexible y seguro con JavaScript y Machine Learning. Las clases se almacenan en los modelos.py de su aplicación. Usando nano, edite aplicaciones/modelos.py y agregue una nueva clase. Una clase se define con la definición de clase y se pasa una superclase de la que hereda, en este caso Models.Model. El nombre de la clase viene después de la definición de clase, y después de la definición de clase A: (colon) se usa, antes de que los atributos y las definiciones de funciones vinculadas a la clase se denoten a continuación. Nuestra claseNecesita una identificación que podamos usar para recuperarlo y mantenerlo único, y también necesita un campo de texto para almacenar información. Más adelante podemos agregar una marca de tiempo, archivos, booleanos (definiciones verdaderas o falsas que pueden ayudar a nuestro código a tomar decisiones sobre qué hacer con el modelo, y puede usarse para ordenarlo), una instancia para vincular el modelo a un usuario registrado en el servidor, y más. Vamos a desempaquetar el código

from django.db import models # La importación que se utiliza para definir nuestra clase y sus atributos

class Post(models.Model): # La definición de nuestra clase misma
    id = models.AutoField(primary_key=True) # La ID de nuestro modelo, una clave generada automáticamente que nos permitirá consultar el modelo, mantenerlo único y es útil cuando necesitamos interactuar con el modelo una vez que se haya creado.
    text = models.TextField(default='') # El atributo de nuestras tiendas de clase, en este caso, algún texto, por defecto en una cadena vacía.
Cierre y guarde el archivo como lo hicimos antes para terminar. Hay muchos otros campos y opciones que exploraremos cuando actualicemos esta clase a medida que nuestra aplicación evoluciona, pero estas son las necesidades básicas de crear una aplicación para publicar algún texto. Sin embargo, este modelo no funcionará solo. Como se describió anteriormente, necesitaremos una vista personalizada y un patrón de URL personalizado para que este modelo funcione, y también necesitaremos un formulario junto con una plantilla. Exploremos primero el formulario. Para definir un formulario, edite App/Forms.py con Nano y agregue las siguientes líneas. Necesitaremos dos importaciones, nuestra clase de formularios, así como el modelo que creamos (feed.models.post), una definición de clase similar al modelo y un campo junto con una subclase llamada meta que definirá el modelo que interactúa el formulario con. El formulario también puede tener una función de inicialización que la establece en función de la información en la solicitud, modelo o de otra manera, exploraremos esto más adelante. Los formularios de modelo son muy útiles porque pueden crear un modelo o también editar un modelo,Entonces los usaremos para ambos. Definamos uno en Forms.py

from django import forms
from feed.models import Post

class PostForm(forms.ModelForm):
    text = forms.CharField(widget=forms.Textarea)
    class Meta:
        model = Post
        fields = ('text',)
Esto es lo básico de cómo se ve una forma y modelo. Este formulario de modelo se puede usar para instanciar o editar una publicación, cambiando el texto que contiene. Vamos a ver la integración de este formulario en una vista a continuación. Primero, hagamos las migraciones y migremos la base de datos para que nuestro código pueda interactuar con el modelo cuando se ejecuta. Para hacer esto, ejecute los siguientes comandos:

python manage.py makemigrations
python manage.py migrate
Esto tomará un minuto para ejecutarse, pero una vez que lo haga, le permitirá acceder al modelo en las vistas, el middleware o en cualquier otro lugar del software. Continuemos haciendo una vista donde podamos ver nuestro modelo. Edite Feed/Views.py y agregue el siguiente código, como se indica. No necesitará agregar nada después del signo #, ese código son comentarios que se utilizan para denotar información sobre el código. Comenzaremos importando nuestro modelo en las vistas y agregarlo a un contexto en el que podamos representarlo en una plantilla como lista para la visualización. A continuación, agregaremos una plantilla donde podamos representar el formulario y el modelo con un botón para crear un nuevo objeto basado en el modelo y publicarlo en el servidor. Esto suena complicado, así que vamos a darlo paso a paso. Antes de terminar la vista, creemos una plantilla que simplemente represente el modelo y asegúrese de que podamos verlo creando una nueva publicación en el shell. Así es como debería verse esa vista:

from feed.models import Post
from django.shortcuts import render, redirect
from django.urls import reverse

def feed(request):
    posts = Post.objects.all() # Consulte todas las publicaciones en la base de datos hasta ahora
    return render(request, 'feed/feed.html', {
        'posts': posts,
    })
Todo esto se ve bastante simple hasta que llegamos al fondo. Render, el valor devuelto por la función en lugar de en una respuesta HTTP como el ejemplo anterior, siempre toma una solicitud como su primera entrada, acepta un contexto (en este caso las publicaciones en la base de datos), que ahora se puede representar en la plantilla y devuelve la plantilla definida en la función. La plantilla será un documento HTML con un poco de lenguaje llamado Jinja2, que convierte la información de Python en el HTML. Para comenzar a crear plantillas, haga dos directorios en Feed.

mkdir feed/templates
mkdir feed/templates/feed
A continuación, edite una plantilla en el directorio anterior, alimentando/plantillas/alimentación, y agregue el código para este ejemplo. Veamos la plantilla para este ejemplo.
 
<!doctype HTML>
<html>
<body>
<legend>Feed</legend>
<hr>
{% for post in posts %}
<p>{{ post.text }}</p>
{% endfor %}
</body>
</html>
 
Esta es una plantilla muy simple. Define las etiquetas HTML de apertura y cierre, una etiqueta de tipo de documento, una etiqueta de cuerpo con un título de leyenda, una etiqueta de ruptura que agrega una pequeña línea en la pantalla y un bucle for que representa cada publicación en la lista de publicaciones como un párrafo en la plantilla. Esto es todo lo que se necesita para representar publicaciones, pero todavía no hay ninguna en la base de datos. Creemos algunos con el caparazón. Podemos ejecutar el shell con managem.py

python manage.py shell
Ahora, importemos nuestro modelo de publicación

from feed.models import Post
A continuación, crearemos una publicación simple con una cadena y saldremos de la carcasa. La cadena puede ser cualquier cosa, siempre que sea un texto válido.

Post.objects.create(text='hello world')
exit()
Por último, necesitaremos agregar un patrón de URL a nuestra alimentación. Debido a que nuestra aplicación Feed usará múltiples URL y queremos mantener pequeños los tamaños de archivos, creemos una URL local.

from django.urls import path
from . import views

urlpatterns = [
    path('', views.feed, name='feed'),
]
También necesitaremos editar las URLs.py en la aplicación base, como decidimos llamarlo, este fue el primer directorio que creamos. Editar App/App.py y agregar lo siguiente a los patrones de URL

from django.urls import include # en la parte superior

urlpatterns = [
    # ... Código anterior aquí
    path('feed/', include(('feed.urls'), namespace='feed')),
]
Ahora, cuando ejecutamos el servidor con Python Manage.py RunServer, veremos la página que creamos porque tenemos el modelo, la vista y la plantilla, así como el patrón de URL, junto con los elementos de la base de datos. A continuación, implementemos el formulario que creamos y comencemos a crear nuestras propias publicaciones. Pero antes de escribir demasiado código, hagamos una copia de seguridad usando el script que escribimos anteriormente, copia de seguridad. Ejecute este script en el shell, espere unos momentos, y todo el código estará respaldado a nuestro repositorio Git.

backup
Implementar el formulario es relativamente simple. Importaremos nuestro formulario, agregaremos un controlador de solicitud de publicación a la vista y guardaremos la publicación en la base de datos antes de redirigir a la misma vista. Podemos usar la función de redirección que ya importamos, y otra función llamada inversa para obtener la URL para el patrón de vista. Consultaremos esto con la cadena 'Feed: Feed' porque el espacio de nombres del patrón incluido es Feed, y la vista también se llama Feed.

from feed.forms import PostForm

def feed(request):
    posts = Post.objects.all() # Consulte todas las publicaciones en la base de datos hasta ahora
    if request.method == 'POST': # Manejar la solicitud de publicación
        form = PostForm(request.POST) # Cree una instancia del formulario y guárdelas los datos
        if form.is_valid(): # Validar la forma
            form.save() # Guardar el nuevo objeto
        return redirect(reverse('feed:feed')) # Redirigir a la misma URL con una solicitud GET
    return render(request, 'feed/feed.html', {
        'form': PostForm(), # Asegúrese de pasar el formulario al contexto para que podamos representarlo.
        'posts': posts,
    })
Ahora, tendremos que actualizar la plantilla para tener en cuenta el nuevo formulario. Podemos hacer esto usando el
Etiquete html y renderizado el formulario en la plantilla HTML con un botón de envío. También necesitaremos un token CSRF, un token que evite que los sitios externos se publiquen al formulario sin cargar primero una página.
 
<!doctype HTML>
<html>
<body>
<legend>Feed</legend>
<form method=”POST”>
{% csrf_token %}
{{ form }}
<button type=”submit”>New Post</button>
</form>
<hr>
{% for post in posts %}
<p>{{ post.text }}</p>
{% endfor %}
</body>
</html>
 
Desglosemos esto. Hay una nueva clase de formulario, un token, el formulario en sí y un botón de envío. Bastante simple, pero cuando lo echamos un vistazo, es posible que queramos que se vea mejor. Funciona, podemos publicar nuevas publicaciones con el formulario y ahora se guardan en la base de datos. Hay algunas cosas que están sucediendo aquí. Usamos etiquetas HTML para declarar que el documento es un documento HTML, usamos una etiqueta de plantilla ({ % ... %}) para representar el token para el formulario, y otra, {{...}} para representar el formulario. También tenemos un bucle para representar el texto usando etiquetas de bloque y una etiqueta de plantilla. Las etiquetas de bloque son realmente importantes porque podemos definir cómo se representan las secciones de la plantilla con ellas, y las etiquetas de plantilla son la base de cómo colocamos variables en nuestro código. Ahora necesitamos hacer que nuestra aplicación se vea mejor, porque por ahora se ve realmente básico. Podemos hacer esto usando CSS, ya sea en línea o en clases vinculadas a cada objeto en el documento. CSS es realmente agradable porque dice todo en la página cómo debería verse,y puede hacer que se vea realmente bien. Hay algunas bibliotecas que pueden hacer esto, pero mi personal personal es Bootstrap. Bootstrap se puede descargar desde su sitio web,GetBootstrap.com/. Una vez allí, presione el botón para leer los documentos de instalación y copie el código de la sección incluir a través de CDN. Necesitará este código en la parte superior de su documento HTML, en una etiqueta llamada Head. Además, sigamos adelante y creemos una plantilla base para que no necesitemos recrear estos enlaces en cada plantilla. Haga un nuevo directorio llamado plantillas con plantillas MKDIR y luego edite plantillas/base.html. Debería verse así:
 
<!doctype HTML>
<html>
<head>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js" crossorigin="anonymous"></script>
</head>
<body>
{% block body %}
{% endblock %}
</body>
</html>
 
Asegúrese de copiar los archivos CSS y JavaScript, los archivos .css y .js, porque necesitaremos el JavaScript para que nuestro sitio sea más funcional en el futuro. Ahora, volvamos al shell bash y ejecutemos un comando rápido. Recuerde, si alguna vez necesita acceder al entorno virtual, escriba la fuente Venv/bin/active. Esto le permitirá instalar paquetes de Python localmente de una manera que le permita acceder a Django. Para dar nuestras formularios generados por las clases de Bootstrap de Django, usaremos un paquete Python llamado Formas crujientes. Podemos descargar esto con el siguiente comando

pip install django-crispy-forms
Una vez que esto esté instalado, agrégalo a settings.py

INSTALLED_APPS = [
    # … Código anterior aquí
    'crispy_forms',
]
Ahora, de vuelta en nuestra plantilla de alimentación, podemos eliminar algunas cosas. Eliminemos el comienzo y el final del documento y lo reemplacemos con herencia de nuestra plantilla base, utilizando extensiones y la definición del bloque. Además, agregaremos una importación de filtro de plantilla con carga y un filtro de plantilla al formulario. Por último, agregemos una clase de arranque al botón en el formulario para que se vea más como un botón. Eso debería verse así:
 
{% extends 'base.html' %}
{% block body %}
{% load crispy_forms_tags %}
<form method=”POST”>
{% csrf_token %}
{{ form|crispy }}
<button type=”submit” class=”btn btn-outline-primary”>New Post</button>
</form>
<hr>
{% for post in posts %}
<p>{{ post.text }}</p>
{% endfor %}
{% endblock %}
 
¡Hermoso! Eso ya es bastante de código. A continuación, debemos probarlo y asegurarnos de que podamos ver que todo se ve bien, y también asegurarnos de que todo funcione correctamente. Ejecute el servidor según las instrucciones anteriores y asegúrese de que el sitio se vea y funcione bien. ¡Buen trabajo! Está listo para pasar al siguiente paso, en el que agregaremos la funcionalidad de inicio de sesión de usuario utilizando URL, formularios, vistas y plantillas similares. La plantilla base es importante, y continuaremos modificándola y haciendo cambios según sea necesario, pero por ahora centrémonos en hacer que nuestro sitio sea más seguro, permitiendo a los usuarios iniciar sesión con un nombre de usuario y un código de contraseña, y eventualmente información aún más importante que ayudará a mantener su aplicación segura y su propia cuenta accesible solo por usted. Para hacer esto, necesitaremos usar el modelo de usuario integrado en Django. El modelo de usuario es un modelo de base de datos, como nuestra publicación, que se puede representar para registrar un usuario en el sitio web. En el futuro, antes de implementar el sitio en Internet,Extienda este modelo con otros modelos atribuidos a él y cree medidas de seguridad adicionales para el inicio de sesión que son resistentes al phishing. Comenzaremos utilizando algunos formularios de inicio de sesión integrados que proporciona Django. Primero, creemos una nueva aplicación que usaremos para representar las plantillas y vistas para la página de inicio de sesión básica. También crearemos otras aplicaciones para representar los desafíos continuos de inicio de sesión para asegurar la aplicación, incluido un pintor, reconocimiento facial, comunicación de campo cercano, dispositivos externos, autenticación de factores múltiples y reconocimiento de huellas digitales. Ya hablamos sobre comenzar una aplicación. Desde nuestro directorio, dentro del entorno virtual, pase gestionar.py estos

python manage.py startapp users
Ahora, deberíamos tener un directorio para la nueva aplicación. Comencemos creando una vista en ese directorio que corresponde al inicio de sesión del usuario. Django ha incorporado vistas para inicios de sesión del usuario, pero estos no serán adecuados para nosotros porque necesitamos una vista personalizada, que preferiblemente se realiza con una definición. Desde esta opinión, comenzaremos por verificar una solicitud posterior, pasar la solicitud.post a una forma de inicio de sesión importada de Django, autenticaremos la cuenta de usuario e iniciar sesión en el usuario antes de redirigirlos a nuestra aplicación de feed. En ussers/Views.py, agregue el siguiente código

from django.shortcuts import render, redirect
from django.urls import reverse
from django.contrib.auth.forms import AuthenticationForm, SetPasswordForm
from django.contrib.auth import authenticate, logout
from django.contrib.auth import login as auth_login
from django.contrib import messages

def login(request):
    if request.method == “POST”:
        username = request.POST['username'] # Obtenga el nombre de usuario y la contraseña de la solicitud de publicación
        password = request.POST['password'] # Autenticar al usuario
        user = authenticate(username=username, password=password)
        if user:
            auth_login(request, user, backend='django.contrib.auth.backends.ModelBackend')
            messages.success(request, 'Your password was accepted. Please continue')
            return redirect(reverse('feed:feed'))
        else: messages.warning(request, 'Username or password incorrect. Please try again')
    return render(request, 'users/login.html', {'form': AuthenticationForm()})
Esto es todo lo que necesita para una vista básica de inicio de sesión. Ahora, creemos un formulario para la vista extendiendo la plantilla base. Comenzaremos creando un nuevo directorio para plantillas en la carpeta de usuarios.

mkdir users/templates
mkdir users/templates/users
Ahora, deberíamos poder editar usuarios/plantillas/usuarios/login.html. Mientras lo hacemos, crearemos una plantilla para permitir que el usuario también se registre.

nano users/templates/users/login.html
Ahora, en la plantilla,
 
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<form method="POST">
    {% csrf_token %}
    <fieldset class="form-group">
        <legend class="border-bottom mb-4 break">Log In</legend>
        {{ form|crispy }}
    </fieldset>
    <div class="form-group">
        <button class="btn btn-outline-info" type="submit">Login</button>
    </div>
</form>
{% endblock %}
 
Esto es lo básico de una plantilla de inicio de sesión. Realmente es como la otra plantilla de estructura, pero se ve un poco diferente cuando se representa. Podemos copiar este código para construir otra plantilla muy similar llamada Register.html, donde cambiaremos la redacción y usaremos un nuevo formulario que construimos. Hagamos primero la plantilla. Editar usuarios/plantillas/usuarios/registro.html y agregar el siguiente código:
 
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<form method="POST">
    {% csrf_token %}
    <fieldset class="form-group">
        <legend class="border-bottom mb-4 break">Create an account</legend>
        {{ form|crispy }}
    </fieldset>
    <div class="form-group">
        <button class="btn btn-outline-info" type="submit">Register</button>
    </div>
</form>
{% endblock %}
 
Ahora, creemos un formulario para el registro de nuestro usuario y vuelva a las vistas antes de actualizar los inicios de sesión de nuestros usuarios con un modelo. Haremos este formulario básico para comenzar, pero incorporaremos más detalles y características de seguridad, como acuerdos y captcha en el futuro. Edite los formularios con nano usuarios/forms.py, y agregue el siguiente código.

from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm

class UserRegisterForm(UserCreationForm):
    email = forms.EmailField()

    class Meta:
        model = User
        fields = ['username', 'email', 'password1', 'password2']
Así que tenemos otra forma aquí, que funciona de manera bastante simple. Es un formulario de registro de usuario con un nombre de usuario, correo electrónico y contraseña, así como un campo de contraseña de confirmación. Tenga en cuenta que este formulario no extiende las formas regulares. Class, es un formulario de modelo que significa que tiene un meta. Un campo se define de la misma manera, y el meta de clase define el modelo que el formulario corresponde al resto de la información que se escribirá en el formulario. La mayor parte de esto ya existe en la forma de creación de usuarios incorporada de Django, por lo que lo usaremos como base para la clase (aprobada entre paréntesis). A continuación, examinaremos la vista para registrar a un usuario, ahora que tenemos un formulario y una plantilla. Este es un ModeflaM, como el de la nueva vista posterior. Editar usuarios/vistas.py y agregar el siguiente código:

# ... cantidades
from .forms import UserRegisterForm

def register(request):
    if request.method == “POST”:
        form = UserRegisterForm(request.POST)
        if form.is_valid():
            user = form.save()
            messages.success(request, 'Welcome to the app, {}.'.format(user.username))
    return render(request, 'users/register.html', {'form': UserRegisterForm})
Esto es todo lo que necesitamos para registrar un usuario, pero deberíamos tener más información. Queremos saber la vez que el usuario se registró, a qué hora fue la última vez que estuvieron en el sitio, cierta información sobre ellos, como una biografía, zona horaria, etc. Además, necesitaremos actualizar nuestro modelo de feed, publicar, para dar cuenta del usuario Modelo y publicaciones de atributos a cada usuario. Para hacer eso, actualizaremos los modelos.py en ambas aplicaciones. Comencemos editando el modelo de alimentación. Debería verse así ahora:

from django.db import models # ... cantidades
from django.contrib.auth.models import User

class Post(models.Model):
    id = models.AutoField(primary_key=True)
    author = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True, related_name='posts') # Agregar en esta línea
    text = models.TextField(default='')
Preste atención a la segunda línea que se agregó al archivo. Esta es una clave externa, que atribuirá cada publicación a un solo usuario por publicación, por lo que podemos asegurarnos de guardar las publicaciones en base al usuario por usuario y no se puede hacer ninguna publicación sin atribuirla a un usuario. Definimos esta clave extranjera con la clase que representa, un argumento eliminado para garantizar que las publicaciones se eliminen con los usuarios, argumentos nulos y en blanco para asegurarnos de que podamos eliminar al usuario si es necesario, y para acomodar la falta de un usuario en las publicaciones que ya creado, y un nombre relacionado, que podemos usar para referirnos a los objetos de publicación que crea el usuario. Este nombre relacionado, a diferencia de Post.Author, el autor de la publicación, nos brinda un usuario que publicó la publicación en sí. Ahora podemos obtener las publicaciones de un usuario realizado ejecutando user.posts.alt (), o autor.posts.all (). Ahora, hagamos que nuestros inicios de sesión sean más resistentes. Ya podemos hacer que nuestro sitio sea mucho menos vulnerable al phishing simplemente calificando la limitación de la cantidad de veces que permitiremos iniciar sesión en elSitio, esto es bastante fácil. También comencemos a almacenar información sobre cada usuario antes a medida que continuamos desarrollando nuestra aplicación. Edición de usuarios/modelos.py, agregue lo siguiente

from django.db import models
from django.contrib.auth.models import User
from django.utils import timezone

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, null=True, blank=True, related_name='profile')
    account_created = models.DateTimeField(default=timezone.now)
    last_seen = models.DateTimeField(default=timezone.now)
    can_login = models.DateTimeField(default=timezone.now)
    preferred_name = models.CharField(max_length=20,default='', null=True, blank=True)
    bio = models.TextField(blank=True, default='')
Tenga en cuenta que este modelo es bastante similar al modelo de publicación. Tenemos una importación adicional, TimeZone, que nos permitirá establecer los valores predeterminados en los campos de fecha y hora, y también tenemos un CartardFeild y Textfield como la publicación. El uso de todas estas marcas de tiempo nos ayuda a asegurar el sitio y comprender su uso, y los campos de texto nos permiten rendir información sobre cada usuario o autor en el sitio web. El Onetoonefield debería ser la única consideración menor, se comporta exactamente igual que un preestablecio pero con solo uno por modelo posterior. De esta manera, el usuario solo tiene un perfil, mientras que puede tener muchas publicaciones. Ahora, mejoremos nuestras vistas de inicio de sesión y registremos para tener en cuenta el perfil. Primero, edite usuarios/vistas.py y concéntrese en la vista de registro:

# ... cantidades
from .forms import UserRegisterForm

def register(request):
    if request.method == “POST”:
        form = UserRegisterForm(request.POST)
        if form.is_valid():
            user = form.save()
            Profile.objects.create(user=user) # Asegúrese de agregar esta línea para crear un perfil para el usuario
            messages.success(request, 'Welcome to the app, {}.'.format(user.username))
    return render(request, 'users/register.html', {'form': UserRegisterForm})
Esto simplemente crea un perfil para el usuario, sin completar ninguna información. Ahora, queremos asegurarnos de que la cuenta de usuario no pueda registrarse con demasiada frecuencia, o al menos las contraseñas no se pueden probar con demasiada frecuencia, así que actualicemos la vista de inicio de sesión.

# ... cantidades
from .models import Profile
from django.utils import timezone
import datetime

def login(request):
    if request.method == “POST”:
        username = request.POST['username']
        password = request.POST['password']
        user = authenticate(username=username, password=password)
        if user and user.profile.can_login < timezone.now(): # Tenga en cuenta que ahora verificamos si el usuario puede iniciar sesión
            auth_login(request, user, backend='django.contrib.auth.backends.ModelBackend')
            messages.success(request, 'Your password was accepted. Please continue.')
            return redirect(reverse('feed:feed'))
        else: # Si el inicio de sesión no fue exitoso,
            messages.warning(request, 'Username or password incorrect. Please try again.')
            user = User.objects.filter(username=username).first() # Esta es la parte donde actualizamos el perfil de los usuarios
            if user: 
                profile = user.profile
                profile.can_login = timezone.now() + datetime.timedelta(seconds=15) # Entonces no pueden iniciar sesión nuevamente por unos segundos
                profile.save()
    return render(request, 'users/login.html', {'form': AuthenticationForm()})
Este es el fundamental básico de la seguridad. Asegúrese de que el sitio no sea vulnerable a alguien que simplemente intente todas las combinaciones de contraseñas posibles, o incluso algunos de ellos al mismo tiempo. Esto no será frustrante para el usuario ordinario que conoce su código de acceso y solo inicia sesión en algunos dispositivos, pero mantendrá numerosos robots de phishing fuera de la aplicación. Tenga en cuenta que agregamos una instrucción IF con una variable, can_login, que debería ser un momento en el pasado, y actualizarla con cada inicio de sesión fallido utilizando el mismo nombre de usuario. De esta manera, un usuario malicioso no podrá adivinar una contraseña tan rápido. El número de segundos en Datetime.timedelta () también se puede actualizar, y el sitio web será más resistente pero un poco menos utilizable con más segundos. Recomiendo 15 para empezar. Recuerde, construimos un script de respaldo para guardar nuestro trabajo, así que sigamos adelante y retrocedamos lo que tenemos hasta ahora para asegurarnos de que tengamos todo guardado. Ejecute el comando:

sudo backup
Una vez más, esto salvará su trabajo hasta ahora. Recomiendo ejecutar copias de seguridad frecuentes para guardar su trabajo, e incluso es posible que desee ejecutar un trabajo de copia de seguridad automáticamente. Puede hacer esto usando una utilidad UNIX llamada Cron. Para activar esta utilidad, ejecute el siguiente comando e ingrese su contraseña:

sudo crontab -e
Si aún no ha seleccionado la opción 1 para Nano, el editor de texto con el que ya debe estar familiarizado y desplazarse a la parte inferior del archivo usando las teclas de flecha. Agregue la siguiente línea:

0 * * * * sudo backup
Cron usa el minuto de formato, hora, día del mes, mes, día de la semana, donde un * o un número representa cuándo ejecutar el comando. Usando un 0 para el minuto y * para el resto de las opciones, podemos ejecutar un comando en el primer minuto de cada hora al comienzo del minuto. Esto nos permite hacer una copia de seguridad del código automáticamente. Todos los trabajos de Cron cuando se ejecutan con sudo se ejecutan como root, por lo que no necesitaremos escribir una contraseña cada hora. Para facilitar la copia de seguridad de nuestro código sin usar una contraseña, deshabilitemos la contraseña para nuestro comando de copia de seguridad. Haremos esto ejecutando el siguiente comando e ingresando una contraseña:

sudo visudo
Ahora, desplazemos a la parte inferior del archivo y agregemos otra línea:

ALL ALL=NOPASSWD: /bin/backup
Esto nos permite ejecutar el comando "copia de seguridad" como cualquier usuario, sin contraseña. El formato para esto es fácil, solo prefije la línea con "all = nopasswd:/bin/" y termine con el comando, por ejemplo/bin/backup, que existe en/usr/bin/. Ahora, comencemos a trabajar con el correo electrónico. El correo electrónico es realmente importante para los sitios web, porque es una forma de mantener un sitio web más seguro, verificar que los usuarios son personas reales e incluso comercializar productos o servicios para los clientes. Muchas personas que frecuentan Internet revisan su correo electrónico diariamente y reciben todo tipo de correo electrónico de marketing sobre productos y servicios que están interesados. Hay algunas opciones cuando se trata de habilitar el correo electrónico en un sitio web de Django, y puede elegir lo que sea que funcione mejor para ti. Primero, puede pagar un servicio de correo electrónico que le permitirá enviar un correo electrónico desde su dominio y requiere un código mínimo. Hay muchos servicios que ofrecen esto, como Google Workspace, SendInblue, Mailgun y más. De lo contrario, estás bien construyendoSu propio servicio de correo electrónico dentro de su servidor desde cero. Recomiendo esta opción, a pesar de que es más código y puede requerir alojamiento especial. Lo más probable no podrá iniciar un servidor de correo desde la computadora de su hogar, así que sigamos adelante y examinemos la configuración y el código para enviar el correo electrónico antes de iniciar un servidor en la nube y crear nuestro propio servidor de correo dentro. Primero, edite settings.py con lo siguiente

nano app/settings.py
Donde la aplicación es el nombre de la aplicación que creó con StartApp. Agregue las siguientes líneas:

SITE_NAME = 'Django App'

EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'localhost'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_ADDRESS = username@server.com'
EMAIL_HOST_USER = 'username'
EMAIL_HOST_PASSWORD = config['EMAIL_HOST_PASSWORD']
DEFAULT_FROM_EMAIL = '{} <{}>'.format(SITE_NAME, EMAIL_HOST_USER)
Asegúrese de cambiarlos cuando esté listo para implementar su aplicación, volveremos a visitar esto más adelante. La configuración de correo electrónico_address debe ser el correo electrónico del que desea enviar, y la contraseña (Correo electrónico_host_password) debe establecerse en la contraseña que genere para el servidor. Cargo la contraseña de un archivo de configuración para mantenerla fuera del código utilizando la siguiente lógica, por encima de estas líneas en settings.py:

import os
import json
with open('/etc/config.json') as config_file:
    config = json.load(config_file)
Luego, configuré un archivo JSON con la configuración en /etc/config.json usando Nano de la siguiente manera. Para editar el archivo:

sudo nano /etc/config.json
Agregue las siguientes líneas:

{
	“EMAIL_HOST_PASSWORD”: “<some password here>”
}
Continuaremos editando el archivo de configuración y agregaremos todas las contraseñas y claves que usaremos en la aplicación. Por ahora, examinemos rápidamente cómo enviar correo electrónico con Python. Primero, creemos una plantilla para un correo electrónico de verificación que podamos enviar a nuestros usuarios y colocarla en el directorio de plantillas de usuario. Esta plantilla se escribirá en HTML.

nano users/templates/users/verification_email.html
 
<h1>Django App - Verify Your Email</h1>
<p>Dear {{ user.username }},</p>
<p>To verify your email, please <a href="{{ base_url }}{% url 'users:activate' uidb64=uid token=token %}">click here</a>.</p>

<p>Alternatively, you can paste the following link in your browser's address bar:</p>
<p>{{ base_url }}{% url 'users:activate' uidb64=uid token=token %}</p>

<p>The link will expire in 30 minutes.</p>
<p>If you have not requested a verification email you can simply ignore this email.</p>
<p>See you there,</p>
<p>Daisy</p>
 
Este correo electrónico es bastante simple. Se necesita un contexto de un usuario, la URL base para el sitio y una identificación de usuario y token que se utilizan para verificar el correo electrónico del usuario. Asegúrese de definir la URL base en Settings.py antes de escribir algún código Python para representar la plantilla. Continúe y agregue las siguientes líneas a App/settings.py, cerca del comienzo.

SITE_NAME = 'Django App'
PROTOCOL = 'https'
DOMAIN = 'example.com'

BASE_URL = PROTOCOL + '://' + DOMAIN
Eventualmente, cuando su sitio está listo para Internet y lo implementa, querrá definir su dominio como el nombre de dominio que compra para representar el sitio. Este es el nombre que escribirá en el Navbar para acceder a su sitio. Por ahora, puede dejar el dominio en blanco o usar un marcador de posición. También querrá cambiar el sitio_name a un nombre que desea darle a su sitio de su elección. Antes de enviar un correo electrónico, creemos un generador de tokens para que podamos tener un token de activación de cuenta que nunca caduque. Podemos hacer esto construyendo e importando un token de activación de cuenta que se vea como lo siguiente. Editar el archivo:

nano users/tokens.py
Agregue el siguiente código:

from django.contrib.auth.tokens import PasswordResetTokenGenerator
import six
class TokenGenerator(PasswordResetTokenGenerator):
    def _make_hash_value(self, user, timestamp):
        return (
            six.text_type(user.pk) + six.text_type(timestamp)
        )
account_activation_token = TokenGenerator()
unsubscribe_token = TokenGenerator()
Este generador de token básico genera un token que podemos enviar al usuario a una URL y el usuario puede usar para verificar su correo electrónico y activar su cuenta. A continuación, veamos cómo enviar un correo electrónico. Usando nano, edite usuarios/correo electrónico.py.

nano users/email.py
Enviar el correo electrónico HTML de verificación se verá así:

from django.contrib.auth import get_user_model
from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode
from django.contrib.sites.shortcuts import get_current_site
from django.core.mail import send_mail
from django.template.loader import render_to_string
from django.utils.encoding import force_bytes
from django.core.mail import EmailMultiAlternatives
from django.shortcuts import render
from .tokens import account_activation_token
from django.template.loader import render_to_string
from django.utils.html import strip_tags
from django.template import Template, Context
from django.conf import settings
import traceback

def send_verification_email(user):
    User = get_user_model()
    mail_subject = '[{}] Activate your account.'.format(settings.SITE_NAME)
    html_message = render_to_string('users/verification_email.html', {
        'user': user,
        'domain': settings.DOMAIN,
        'protocol': 'https',
        'uid': urlsafe_base64_encode(force_bytes(user.pk)),
        'token': account_activation_token.make_token(user),
    })
    send_html_email(user, mail_subject, html_message)
Esto es bastante simple. Importamos las funciones que necesitamos para enviar el correo electrónico, realizar el correo electrónico con las plantillas y nuestra configuración, y luego definimos el correo electrónico por nombre de plantilla y lo enviamos al usuario utilizando una función. Notará que no hemos definido la función para enviar el correo, send_html_email, así que escribamos esto a continuación el código que ya agregamos a los usuarios/correo electrónico.py

def send_html_email(user, mail_subject, html_message):
    to_email = user.email
    username = user.username
    if to_email == '':
        return None
    unsub_link = settings.BASE_URL + user.profile.create_unsubscribe_link()
    html_message = html_message + "<p><a href=\"" + unsub_link +  "\" + title=\"Unsubscribe from " + settings.SITE_NAME + " emails\">Unsubscribe</a></p></body></html>"
    msg = EmailMultiAlternatives(mail_subject, strip_tags(html_message), settings.DEFAULT_FROM_EMAIL, [to_email], headers={'List-Unsubscribe' : '<' + unsub_link + '>'},)
    msg.attach_alternative(html_message, "text/html")
    profile = user.profile
    try:
        msg.send(fail_silently=False)
        if not profile.email_valid:
            profile.email_valid=True
            profile.save()
    except:
        profile.email_valid=False
        profile.save()
Esto es un poco más complejo, y todavía no estamos listos para ejecutar todo este código. Observe que estamos definiendo un unsub_link, el enlace que el usuario puede usar para cancelar la suscripción de nuestros correos electrónicos. Esto es importante, porque los usuarios deberán poder optar por no participar en nuestros correos electrónicos a menos que quieran verlos, en cualquier momento. También agregamos una alternativa de texto a nuestro mensaje, que es el mensaje HTML despojado de etiquetas HTML. Por último, verificamos si el correo electrónico enviado, y si no fue así, marcamos en el perfil del usuario que su correo electrónico no es válido. Volvamos a los modelos de usuario para que podamos hacer que todo funcione. Necesitamos definir una función para generar un enlace para darse de baja y definir un campo booleano para marcar que el correo electrónico del usuario no es válido. Primero, agregue las siguientes importaciones a la parte superior de los usuarios/modelos.py

nano users/models.py

# …
from django.core.signing import TimestampSigner, BadSignature, SignatureExpired
from django.urls import reverse
A continuación, agregemos funciones al modelo de usuario para hacer el token y verificar el token utilizado para activar el correo electrónico, así como el campo para guardar si el usuario recibe con éxito su correo. En ussers/modelos.py nuevamente, agregue el siguiente código al final del modelo (código sangrado)

# …
    email_valid = models.BooleanField(default=True)
    
    def make_token(self):
        return TimestampSigner().sign(self.user.username)

    def check_token(self, token):
        try:
            key = '%s:%s' % (self.user.username, token)
            TimestampSigner().unsign(key, max_age=60 * 60 * 24 * 30) # Válido por 30 días
        except (BadSignature, SignatureExpired):
            return False
        return True

    def create_unsubscribe_link(self):
        username, token = self.make_token().split(":", 1)
        return reverse('users:unsubscribe', kwargs={'username': username, 'token': token,})
Esto es bastante simple, usamos un marcador de tiempo, que es una herramienta de criptografía básica, para crear un token que caducará después de una cierta cantidad de tiempo, y también usamos otra función para verificar si es válido. Usamos estos tokens dos veces, una vez para verificar el correo electrónico y una vez para un enlace de cancelación de suscripción. Ahora que tenemos estos, el último trabajo que tendremos que hacer es en las opiniones. Dentro de los usuarios/vistas.py, agregemos vistas para verificar la dirección de correo electrónico y cancelar la suscripción.

nano users/views.py
Primero, agregue las siguientes importaciones. Puse algunos extra para que no tendremos que importar más artículos más tarde.

from django.contrib.auth import logout
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth.models import User
from django.utils.encoding import force_str
from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode
import json
import requests
import datetime, traceback
from django.contrib import messages
from .models import Profile
from django.utils import timezone
from django.views.decorators.cache import never_cache
from .email import send_verification_email # Asegúrese de importar la función de envío de correo electrónico de verificación
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.utils.decorators import method_decorator
from django.http import HttpResponseRedirect
from django.conf import settings
from django.utils import timezone
import datetime
import pytz
from django.views.decorators.csrf import csrf_exempt
from django.http import HttpResponse
from django.contrib.auth.tokens import default_token_generator
from django.utils.http import urlsafe_base64_decode
from .tokens import account_activation_token
Es posible que ya tenga algunas de estas importaciones, pero no está de más repetirlas. Deberá importar la función de envío de correo electrónico de verificación, así como Account_Activation_Token desde ussers.tokens, entre otras importaciones. Ahora, en la parte inferior del archivo, agregue el siguiente código:

def unsubscribe(request, username, token):
    user = get_object_or_404(User, username=username)
    if((request.user.is_authenticated and request.user == user) or user.profile.check_token(token)):
        # darles la baja
        profile = user.profile
        profile.subscribed = False
        profile.save()
        return render(request, 'users/unsubscribe.html')
    # De lo contrario, redirigir a la página de inicio de sesión
    messages.warning(request,f'Your unsubscribe link has expired. Please log in to unsubscribe.')
    next_url = reverse('users:unsubscribe', kwargs={'username': username, 'token': token,})
    return HttpResponseRedirect('%s?next=%s' % (reverse('login'), next_url))

def activate(request, uidb64, token):
    try:
        uid = force_str(urlsafe_base64_decode(uidb64))
        user = User.objects.get(pk=uid)
    except(TypeError, ValueError, OverflowError, User.DoesNotExist):
        user = None
    ip = get_client_ip(request)
    if user is not None and account_activation_token.check_token(user, token):
        user.profile.email_verified = True
        user.profile.save()
        user.save()
# SendwelcomeMail (solicitud, usuario)
        messages.success(request, f'Thanks for confirming your email! You can now log into your account, and a welcome email has been sent to you.')
        return redirect(user.profile.create_face_url())
    else:
        messages.success(request, f'Your activation link has expired. Please request a new activation link.')
        return redirect('verify:verify')

def resend_activation(request):
    if request.method == 'POST':
        form = ResendActivationEmailForm(request.POST)
        email = request.POST['email']
        try:
            user = User.objects.get(email=email)
            send_verification_email(user)
            messages.success(request,'Your verification email sent. Please click the link in your email to verify your account.')
            return redirect(reverse('verify:verify'))
        except:
            messages.warning(request,f'Your email is not correct. Please try again.')
    else:
        form = ResendActivationEmailForm()
    return render(request,'users/resend_activation.html',{'form': form, 'title': 'Resend Activation', 'small': True})
Este es mucho código. Vamos a desglosarlo. La primera función, limpia y simple, da a suscripción al usuario de la lista de correo. La segunda función activa su correo electrónico y notará que agregué una función comentada, SendWelComeEmail. Puede usar una plantilla de correo electrónico y una definición de funciones para enviar un correo electrónico de bienvenida, todavía no lo he hecho. La última función que presenté es importante, porque los correos electrónicos de activación caducan. Por lo tanto, necesitaremos reenviar el correo electrónico de activación algunas veces. Podemos usar un formulario básico para esto y llamar a la función para enviar el correo electrónico de verificación. Antes de hacer esto, asegurémonos de que se envíe en primer lugar, agregando una llamada de función a la vista de registro. Agregue esta línea justo antes de la redirección en la vista de registro, el registro de DEF, en Uss/Views.py.

nano users/views.py

# … (Después) DEF REGISTR (Solicitud):
            send_verification_email(user)
# ... (antes) redirección (
No necesita agregar las primeras y últimas líneas en ese fragmento de código, solo asegúrese de que la vista de registro envíe el correo electrónico de verificación al usuario. Debería verse así:

# ... cantidades
from .forms import UserRegisterForm

def register(request):
    if request.method == “POST”:
        form = UserRegisterForm(request.POST)
        if form.is_valid():
            user = form.save()
            send_verification_email(user) # ¡Asegúrese de agregar esta línea!
            messages.success(request, 'Welcome to the app, {}.'.format(user.username))
    return render(request, 'users/register.html', {'form': UserRegisterForm})
Ahora, tendremos que agregar un formulario para reenviar el correo electrónico de activación. En ussers/forms.py, agregue el siguiente formulario:

# ... (cantidades)
class ResendActivationEmailForm(forms.Form):
    email = forms.EmailField(required=True)
También necesitaremos una plantilla correspondiente a este formulario de activación de correo electrónico de reiniciación. Agregamos esta plantilla. Edite el archivo:

nano users/templates/users/resend_activation.html
A continuación, agregue el siguiente código al archivo.

{% extends 'base.html' %}
{% block content %}
{% load crispy_forms_tags %}
        <form method="POST">
            {% csrf_token %}
            <fieldset class="form-group">
                <legend class="border-bottom mb-4">Resend activation email</legend>
                {{ form|crispy }}
            </fieldset>
            <div class="form-group">
                <button class="btn btn-outline-secondary" type="submit">Resend activation email</button>
            </div>
        </form>
{% endblock %}
¡Vaya, eso es mucho! Ahora, cuando implementemos el código en nuestro servidor, podremos enviar un correo electrónico HTML y activar cuentas de usuario con un clic en el correo electrónico. También es posible que deseemos enviar un simple correo electrónico de bienvenida, así que veamos cómo hacerlo. Volver en ussers/correo electrónico.py, agregue el siguiente código:

def sendwelcomeemail(user):
    User = get_user_model()
    html = open('{}/users/welcome_email.html'.format(settings.BASE_DIR)).read()
    subject = 'Welcome to ' + settings.SITE_NAME + ', {{ username }}!'
    template = Template(html)
    subjtemplate = Template(subject)
    context = Context({'username': user.username, 'base_url': settings.BASE_URL, 'model_name': 'Daisy Holton, 'site_name': settings.SITE_NAME})
    renderedtemplate = template.render(context)
    subjcontext = Context({'username': user.username})
    subjrenderedtemplate = subjtemplate.render(subjcontext)
    send_html_email(user, subjrenderedtemplate, renderedtemplate)
Además, necesitaremos una plantilla para representar toda esta información. En mi sitio web, la plantilla se parece a la siguiente, pero puede formatearla como desee.
 
<html>
<body>
<h3>Welcome to {{ site_name }}</h3>
<p>Hello {{ username }},</p>
<p>We are happy to see you here! Thank you for joining {{ site_name }} and being a part of the fun. To get started, here are a few things you can do after you verify your identity.</p>
<ol>
    <li><a href="{{ base_url }}/" title="Use the app">Use the app</a>. This is the main page of {{ site_name }}</li>
    <li><a href="{{ base_url }}/feed/profile/Clementine/" title="See my profile">Visit my private {{ site_name }} profile</a>. This is a page for anyone wanting to get to know me.</li>
    <li><a href="{{ base_url }}/feed/profiles/" title="See all profiles currently on the site">More profiles</a>. You can find these people on the site, and see their content.</li>
    <li><a href="{{ base_url }}/feed/all/" title="See everything on {{ site_name }}">See all posts here</a>. This is the private front page of {{ site_name }}.</li>
</ol>
<p>There is even more on the site, so feel free to visit and see what you find. You can share the site with any of the social buttons on each page. I hope you enjoy your time with {{ site_name }}! Thanks for being here.</p>
<p>With much love,</p>
<p>{{ model_name }}</p>
<a href="{{ base_url }}" title="{{ site_name }}">{{ base_url }}</a>
 
Tenga en cuenta que no tenemos etiquetas de cierre de cuerpo o HTML, porque las agregamos cuando agregamos el enlace HTML cancelar suscripción. Estos son importantes, pero no queremos definirlos dos veces. Entonces, ¿qué sigue? Hemos recorrido un largo camino. Realmente, deberíamos estar listos para implementar el sitio en un servidor. Podemos agregar el decorador @login_required y hacer que nuestras vistas sean seguras, tomar registros de los usuarios, enviar un correo electrónico compatible e información de caché, que es la base de lo que un sitio web debe hacer para mantenerse relevante. Agregaremos algunas características más útiles y luego construiremos una base para implementar nuestro código en un servidor remoto, configurar un servidor de correo, configuración de dominio y filtros para hacer que nuestro sitio sea seguro y apropiado. También necesitaremos una vista de restablecimiento de contraseña, así que agregemos eso realmente rápido. La vista de reinicio de contraseña incorporada de Django está rota en algunas funciones, pero veremos cómo escribir nuestra propia vista, plantilla de correo electrónico, formularios y patrones de URL. Así es como se ve la vista, en usuarios/vistas.

# ... cantidades
from django.contrib.auth.tokens import default_token_generator
from django.contrib.auth.forms import SetPasswordForm
from django.utils.http import urlsafe_base64_decode

def password_reset(request, uidb64, token):
    user = get_object_or_404(User, id=urlsafe_base64_decode(uidb64))
    if request.method == 'POST':
        form = SetPasswordForm(user, request.POST)
        if form.is_valid() and default_token_generator.check_token(user, token):
            form.save()
            messages.success(request, 'Your password has been reset.')
        elif not form.is_valid():
            messages.warning(request, 'Your passwords do not match, or do not meet the requirements. Please try again.')
            return redirect(request.path)
        else:
            messages.warning(request, 'Your password reset link has expired. Please create a new one.')
        return redirect(reverse('users:login'))
    return render(request, 'users/password_reset_confirm.html', {
        'title': 'Reset your Password',
        'form': SetPasswordForm(user)
Este formulario está integrado en Django, pero necesitaremos una plantilla para confirmar el restablecimiento de contraseña, usuarios/plantillas/usuarios/contraseña_reset_confirm.html
 
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block content %}
        <form method="POST">
            {% csrf_token %}
            <fieldset class="form-group">
                <legend class="border-bottom mb-4">Reset Password</legend>
                {{ form|crispy }}
            </fieldset>
            <div class="form-group">
                <button class="btn btn-outline-info" type="submit">Reset Password</button>
            </div>
        </form>
{% endblock content %}
 
También tenemos una plantilla para enviar un correo electrónico de restablecimiento de contraseña, con un formulario simple, en usuarios/plantillas/usuarios/contraseña_reset.html
 
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block content %}
        <form method="POST">
            {% csrf_token %}
            <fieldset class="form-group">
                <legend class="border-bottom mb-4">Reset Password</legend>
                {{ form|crispy }}
            </fieldset>
            <div class="form-group">
                <button class="btn btn-outline-info" type="submit">Request Password Reset</button>
            </div>
        </form>
{% endblock content %}
 
La plantilla para el correo electrónico en sí es simple, es un archivo HTML básico que representa un enlace para restablecer la contraseña, en usuarios/plantillas/usuarios/contraseña_reset_email.html. Django interpretará automáticamente este archivo.
 
<h1>Uglek - Reset Your Password</h1>
<p>Hello,</p>
<p>To reset your password, please <a href="https:/uglek.com{% url 'password_reset_confirm' uidb64=uid token=token %}">click here</a>.</p>
<p>Alternatively, you can paste the following link into your browser:</p>
<p>https://uglek.com{% url 'password_reset_confirm' uidb64=uid token=token %}</p>
<p>If you have not requested a password reset you can simply ignore this email.</p>
<p>Thanks for joining us,</p>
<p>Daisy</p>
 
También necesitaremos dos plantillas más. El primero es confirmar que se ha enviado el correo electrónico. Las vistas para estos ya están en Django, por lo que solo necesitamos abordarlas en las URLs.py. Esta plantilla se encuentra en usuarios/plantillas/usuarios/contraseña_reset_done.html
 
{% extends 'base.html' %}
{% block content %}
  <div class="media-body">
    <div class="alert alert-info">
        An email has been sent with instructions to reset your password.
    </div>
  </div>
{% endblock content %}
 
Y, por último, para confirmar que el reinicio de la contraseña está completo, usuarios/plantillas/usuarios/contraseña_reset_complete.html
 
{% extends 'base.html' %}
{% block content %}
 <div class="media-body">
    <div class="alert alert-info">
        Your password has been set.
    </div>
    <a href="{% url 'users:login' %}">Sign In Here</a>
  </div>
{% endblock content %}
 
Ahora, necesitamos patrones de URL para estas vistas. En usuarios/urls.py, agregue los siguientes patrones de URL:

urlpatterns = [
    # ... URL anteriores aquí
    path('password-reset/',
         auth_views.PasswordResetView.as_view(
             template_name='users/password_reset.html',
             html_email_template_name='users/password_reset_html_email.html'
         ),
         name='password_reset'),
    path('password-reset/done/',
         auth_views.PasswordResetDoneView.as_view(
             template_name='users/password_reset_done.html'
         ),
         name='password_reset_done'),
    path('password-reset-confirm/<uidb64>/<token>/',
         auth_views.PasswordResetConfirmView.as_view(
             template_name='users/password_reset_confirm.html'
         ),
         name='password_reset_confirm'),
    path('password-reset-complete/',
         auth_views.PasswordResetCompleteView.as_view(
             template_name='users/password_reset_complete.html'
         ),
         name='password_reset_complete'),
]
Cuatro plantillas, ¡eso es mucho! Pero ahora podemos estar seguros de poder restablecer la contraseña del usuario en cualquier momento que necesitemos, todo del navegador web. Entiendo que este es mucho código. Si parece un poco sobre tu cabeza, está bien. Mejorará, su comprensión mejorará y se volverá mucho más competente con el código muy pronto. Si está totalmente perdido, le recomiendo volver a este software más adelante después de trabajar en un curso de aprendizaje a su propio ritmo a codificar en línea. Por lo general, son gratuitos para comenzar, y lo guiarán a través de todo lo que necesita para tener éxito cuando regrese a este proyecto. Si siente que está listo para continuar, siga leyendo, a continuación, cubriremos la implementación de su código en un servidor remoto y configurar un servidor de correo, así como automatizar su implementación con BASH para que siempre pueda configurar un nuevo proyecto con Algunos comandos simples. Lo último que debemos hacer antes de implementar en un servidor remoto es hacer que nuestro sitio sea un poco más seguro. TuObserve que la vista de inicio de sesión solo requiere un nombre de usuario y contraseña, y no hay autenticación de factor múltiple o código de tiempo. Esta es una solución fácil, y con el mismo código, podemos hacer que nuestro sitio envíe mensajes de texto e incluso responda a los mensajes de texto enviados al servidor. Para comenzar, volveremos a los modelos de usuario y agregaremos un firmante de marca de tiempo que represente cada inicio de sesión. También agregaremos un identificador único y giratorio al modelo de usuario que se utilizará para agregar seguridad adicional a nuestro inicio de sesión. Edición de los modelos de usuarios, usuarios/modelos.py, agregue lo siguiente

from django.db import models
from django.contrib.auth.models import User
from django.utils import timezone
# Asegúrese de importar el UUID, el firmante de marca de tiempo y el generador de URL (reverso)
import uuid
from django.core.signing import TimestampSigner, BadSignature, SignatureExpired
from django.urls import reverse

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, null=True, blank=True, related_name='profile')
    account_created = models.DateTimeField(default=timezone.now)
    last_seen = models.DateTimeField(default=timezone.now)
    can_login = models.DateTimeField(default=timezone.now)
    preferred_name = models.CharField(max_length=20,default='', null=True, blank=True)
    bio = models.TextField(blank=True, default='')
    # Agregue este código aquí
    uid = models.CharField(max_length=32, default=uuid.uuid4, null=True, blank=True)
    mfa_enabled = models.BooleanField(default=False)
    enable_mfa = models.BooleanField(default=False)
    phone_number = models.CharField(default='', null=True, blank=True, max_length=15)
    verification_code = models.CharField(default='', null=True, blank=True, max_length=15)
    verification_code_length = models.IntegerField(default=6)
    mfa_code_expires = models.DateTimeField(default=timezone.now)
    mfa_attempts = models.IntegerField(default=0)

    def make_auth_token(self):
        return TimestampSigner().sign(self.uid)

    # Y agregar esta función
    def create_auth_url(self):
        username, token = self.make_auth_token().split(":", 1)
        return reverse('users:mfa', kwargs={'username': username, 'token': token,})

    def check_auth_token(self, token):
        try:
            key = '%s:%s' % (self.uid, token)
            TimestampSigner().unsign(key, max_age=60 * settings.AUTH_VALID_MINUTES) # Válido para 3 minutos
        except (BadSignature, SignatureExpired):
            return False
        return True
Asegúrese de que sus usuarios/modelos.py se vean así, además de los comentarios (código en las líneas con #). Rompiendo esto, es simple. Tenemos algunas importaciones, un marcador de tiempo de tiempo que es una utilidad criptográfica que puede generar un código seguro y verificarlo para asegurarse de que sea válido, solo se usa una vez, y no mayor de un cierto número de segundos. También usamos un UUID, que es un identificador único que identifica a nuestro usuario en la firma del token y en la URL donde se envía el token al usuario. Usaremos esta criptografía básica para construir una vista de autenticación de dos factores. Antes de hacer cualquier otra cosa, ejecutemos las migraciones para que nuestros modelos de usuario se actualicen. En el directorio con Manage.py, ejecute los siguientes comandos para hacer y completar las migraciones.

source venv/bin/activate
python manage.py makemigrations && python manage.py migrate
Esto es importante porque cada vez que realizamos cambios en los modelos, necesitaremos crear las tablas y actualizar la base de datos con valores predeterminados antes de poder usar los modelos. A continuación, improvisemos nuestra vista de inicio de sesión para redirigir a una vista de autenticación secundaria. En usuarios/vistas.py, elimine la función de inicio de sesión y redirige a la URL que acabamos de generar en los modelos de usuario.

# ... cantidades

def login(request):
    if request.method == “POST”:
        username = request.POST['username']
        password = request.POST['password']
        user = authenticate(username=username, password=password)
        if user and user.profile.can_login < timezone.now(): # Tenga en cuenta que ahora verificamos si el usuario puede iniciar sesión
            # Elimine la función Auth_login que estaba aquí
            messages.success(request, 'Your password was accepted. Please continue.')
            if user.profile.mfa_enabled:
                return redirect(user.profile.create_auth_url()) # Tenga en cuenta que redirigimos a una nueva URL aquí
            else: # Si el usuario no está usando autenticación multifactor, simplemente inicie sesión.
                auth_login(request, user, backend='django.contrib.auth.backends.ModelBackend')
                return redirect('feed:feed')
        else: # Si el inicio de sesión no fue exitoso,
            messages.warning(request, 'Username or password incorrect. Please try again.')
            user = User.objects.filter(username=username).first() # Esta es la parte donde actualizamos el perfil de los usuarios
            if user: 
                profile = user.profile
                profile.can_login = timezone.now() + datetime.timedelta(seconds=15) # Entonces no pueden iniciar sesión nuevamente por unos segundos
                profile.save()
    return render(request, 'users/login.html', {'form': AuthenticationForm()})
Así que esto es bastante simple, ahora tenemos una manera de redirigir a la vista de autenticación de dos factores cuando la creamos. También tenemos una devolución en caso de que el usuario no haya agregado un número de teléfono. Agregaremos una vista básica para agregar un número de teléfono pronto e iniciar sesión con un mensaje de texto pronto. Primero, necesitamos una manera fácil de enviar un mensaje de texto desde nuestro código. Para hacer esto, podemos elegir entre una serie de API, pero la más fácil en mi opinión es Twilio. También ofrecen buenos precios para proyectos más pequeños, así como descuentos masivos. Cree una cuenta en twilio.com, complete algunos detalles sobre su proyecto, compre un número de teléfono y copie sus claves API a su configuración.py. Luego, agregue este código en un nuevo archivo, usuarios/sms.py.

nano users/sms.py

# Importar todos los paquetes necesarios
from django.utils import timezone
import random
import datetime
from django.conf import settings
from feed.middleware import get_current_request
from django.contrib import messages
import traceback

account_sid = settings.TWILIO_ACCOUNT_SID
auth_token = settings.TWILIO_AUTH_TOKEN
source_phone = settings.PHONE_NUMBER

# Este código envía el texto con Twilio
def send_text(target_phone, text):
    from twilio.rest import Client
    try:
        client = Client(account_sid, auth_token)
        if len(target_phone) >= 11:
            message = client.messages.create(
                to=target_phone,
                from_=source_phone,
                body=text)
    except:
        print(traceback.format_exc())

# Una función de ayudante para obtener un número con tantos dígitos
def get_num_length(num, length):
    n = ''
    for x in range(length):
        n = n + str(num)
    return int(n)

# Envíe el texto para verificar al usuario
def send_verification_text(user):
    length = user.profile.verification_code_length
    code = random.randint(get_num_length(1, length), get_num_length(9, length));
    user.profile.verification_code = code
    user.profile.mfa_code_expires = timezone.now() + datetime.timedelta(minutes=3)
    user.profile.save()
    send_user_text(user, "Your verification code for {} is {}".format(settings.SITE_NAME, str(code)))

# Envíe a un usuario cualquier texto con esta función
def send_user_text(user, text):
    send_text(user.profile.phone_number, text)

# Validar el código con esta función
def check_verification_code(user, code):
    user.profile.mfa_attempts += 1
    result = user.profile.verification_code != None and code != '' and user.profile.verification_code == code and user.profile.mfa_code_expires > timezone.now() and user.profile.mfa_attempts <= 3
    if user.profile.mfa_attempts < 3 and result:
        user.profile.verification_code_length = 6
    elif user.profile.mfa_attempts > 2 and not result:
        user.profile.verification_code_length = 8
    user.profile.save()
    return result

# Validar el tiempo
def check_verification_time(user):
    result = user.profile.mfa_code_expires > timezone.now()
    return result
Asegúrese de cambiar su configuración adecuadamente, agregando estas líneas con sus claves:

# Asegúrese de copiarlos desde su tablero Twilio
TWILIO_ACCOUNT_SID = “<your sid>”
TWILIO_AUTH_TOKEN = “<your token>”
PHONE_NUMBER = “<your twilio phone number>”
SITE_NAME = “<Your site name>”
AUTH_VALID_MINUTES = 3 # El número de minutos la página TFA está activa una vez instanciado
Primero, necesitaremos formularios para nuestras dos vistas de autenticación de factores. Edición de usuarios/form.py, agregue el siguiente código.

# ... cantidades
from django import forms

# Un formulario para ingresar a nuestro número de teléfono
class PhoneNumberForm(forms.Form):
    phone_number = forms.RegexField(regex=r'^\+?1?\d{9,15}$', error_messages = {'invalid': "Phone number must be entered in the format: '+999999999'. Up to 15 digits is allowed."})
    def __init__(self, *args, **kwargs):
        super(PhoneNumberForm, self).__init__(*args, **kwargs)
        self.fields['phone_number'].label = phone_number_label

# Una forma para autenticar
class TfaForm(forms.Form):
    code = forms.IntegerField(required=False)
    def __init__(self, *args, **kwargs):
        super(TfaForm, self).__init__(*args, **kwargs)
        self.fields['code'].widget.attrs.update({'autocomplete': 'off'})
    help_texts = {
        'code': 'Please enter the six digit code after sending it to your phone with the button above.'
    }
A continuación, creemos las vistas en usuarios/vistas.

# ... cantidades
from django.http import HttpResponseRedirect
from .forms import PhoneNumberForm, TfaForm

def mfa(request, username, token):
    user = User.objects.filter(profile__uuid=username).first()
    if not user: return HttpResponseRedirect(reverse('verify:age') + '?next=' + request.GET.get('next') if request.GET.get('next') else '/go/' if request.user.is_authenticated and request.user.profile.vendor else '/' if request.user.is_authenticated else reverse('users:login'))
    user = get_object_or_404(User, profile__uuid=username)
    next = request.GET.get('next','')
    if not user.profile.mfa_enabled:
        if not check_verification_time(user):
            user.profile.mfa_enabled = False
            user.profile.enable_two_factor_authentication = True
            user.profile.phone_number = '+1'
            user.profile.save()
            print('Logging in user')
            auth_login(request, user, backend='django.contrib.auth.backends.ModelBackend')
            messages.warning(request, 'Please enter a valid phone number and verify it with a code.')
            return redirect(reverse('users:mfa_onboarding'))
    if request.method == 'POST':
        form = TfaForm(request.POST)
        code = form.data['code']
        if code and code != '' and code != None:
            token_validated = user.profile.check_auth_token(token)
            p = user.profile
            is_verified = check_verification_code(user, int(code))
            p.mfa_authenticated = is_verified
            if token_validated:
                if is_verified:
                    user.profile.mfa_enabled = True
                    user.profile.save()
                    auth_login(request, user, backend='django.contrib.auth.backends.ModelBackend')
                    p.verfication_code = None
                    p.uid = get_uuid()
                    p.save()
                    messages.success(request, 'You have been authenticated. Welcome.')
                    qs = '?'
                    for key, value in request.GET.items():
                        qs = qs + key + '=' + value + '&'
                    if next != '' and not (next.startswith('/accounts/logout/') or next.startswith('/accounts/login/') or next.startswith('/admin/login/') or next.startswith('/accounts/register/')):
                        return HttpResponseRedirect(ext)
                    elif next.startswith('/accounts/logout/') or next.startswith('/accounts/login/') or next.startswith('/accounts/register/'):
                        return redirect('feed:feed')
                    elif request.META.get('HTTP_REFERER', '/').startswith('/accounts/login/'):
                        return redirect(reverse('feed:feed'))
                    elif not next:
                        return redirect(reverse('feed:feed')
                    else:
                        return HttpResponseRedirect('feed:feed')
                else:
                    messages.warning(request, 'The code you entered was not recognized. Please try again.')
            elif not token_validated:
                messages.warning(request, 'The URL token has expired or was not recognized. Please try again.')
                logout(request)
                return redirect(reverse('users:login'))
            if p.mfa_attempts > 3:
                messages.warning(request, 'You have entered the incorrect code more than 3 times. please send yourself a new code.')
                p.verification_code = None
                p.save()
        elif user.profile.can_send_mfa < timezone.now():
            user.profile.mfa_attempts = 0
            user.profile.can_send_mfa = timezone.now() + datetime.timedelta(minutes=2)
            user.profile.save()
            send_verification_text(user)
            messages.success(request, "Please enter the code sent to your phone number. The code will expire in 3 minutes.")
        else:
            messages.warning(request, 'You are sending too many two factor authentication codes. Wait a few minutes before sending another code.')
    form = TfaForm()
    hide_logo = None
    if user.profile.hide_logo:
        hide_logo = True
    return render(request, 'users/mfa.html', {'title': 'Enter Code', 'form': form, 'xsmall': True, 'user': user, 'hide_logo': hide_logo, 'accl_logout': user.profile.shake_to_logout, 'preload': False})

@login_required
def mfa_onboarding(request):
    if request.method == 'POST':
        form = PhoneNumberForm(request.POST)
        request.user.profile.phone_number = form.data['phone_number'].replace('-', '').replace('(','').replace(')','')
        request.user.profile.mfa_enabled = True
        request.user.profile.enable_two_factor_authentication = True
        request.user.profile.save()
        messages.success(request, 'You have added a phone number to your account.')
        user = request.user
        return redirect(user.profile.create_auth_url())
    form = PhoneNumberForm(initial={'phone_number': request.user.profile.phone_number if request.user.profile.phone_number else '+1'})
    return render(request, 'users/mfa_onboarding.html', {'title': 'Enter your phone number', 'form': form, 'small': True})
También necesitaremos plantillas para ambas vistas. Agregamos primero la plantilla MFA.

nano users/templates/users/mfa.html
Agregue este código HTML a la plantilla
 
{% extends 'base.html' %}
{% block content %}
{% load app_filters %}
{% load crispy_forms_tags %}
        <form action="{{ request.path }}{% if request.GET.next %}?next={{ request.GET.next }}{% endif %}" method="POST">
            {% csrf_token %}
            <legend class="border-bottom mb-4">Enter Verification Code</legend>
            <p>Step 1: Send the code</p>
	    <i>Never share your code with anyone, as it can be used to access your account temporarily.</i>
	    <div class="form-group">
                <button class="btn btn-outline-primary" type="submit">Send code</button>
            </div>
	    <hr>
	    <p>Step 2: Enter the code</p>
            <fieldset class="form-group">
                {{ form|crispy }}
		<p>Press the enter button to send yourself the code at {{ user.profile.phone_number|securephone }}. Then, enter the code and press enter.</p>
            </fieldset>
            <div class="form-group">
                <button class="btn btn-outline-secondary" type="submit">Enter code</button>
            </div>
        </form>
{% endblock %}
 
Esto se explica por sí mismo. El formulario envía un código o un código vacío, y notará en la vista que enviamos el código si recibimos un código vacío. Luego solo tenemos dos botones de envío, y de esta manera podemos enviar el código con cualquier botón. A continuación, agregaremos un formulario simple para agregar un número de teléfono.

nano users/templates/users/mfa_onboarding.html
Agregue el siguiente HTML:
 
{% extends 'base.html' %}
{% block content %}
{% load crispy_forms_tags %}
        <form method="POST">
            {% csrf_token %}
            <fieldset class="form-group">
                <legend class="border-bottom mb-4">Set Up Two Factor Authentication</legend>
                {{ form|crispy }}
            </fieldset>
            <div class="form-group">
                <button class="btn btn-outline-secondary" type="submit">Add phone number</button>
            </div>
        </form>
{% endblock %}
 
Este formulario es mucho más simple, solo hace que el formulario de número de teléfono que creamos y le permite al usuario agregar un número de teléfono. ¡Esto se ve muy bien! Mientras todo esté configurado correctamente, deberíamos poder enviar mensajes e registrar al usuario con su número de teléfono tan pronto como agregamos los patrones de URL. Lo último que debemos configurar es una vista de perfil para que podamos asegurarnos de que el usuario pueda cambiar su número de teléfono sin haber sido registrado. Además, eventualmente querremos agregar una opción de "parar para dejar de fumar, para que el usuario pueda enviar mensajes de texto. "Detente" para optar por no tener mensajes de texto futuros. Agreguemos una vista de perfil a los usuarios/vistas. Esta vista actualizará el biografía, el correo electrónico, el nombre de usuario y el número de teléfono del usuario, así como nos permitirá habilitar la autenticación de múltiples factores. Primero, necesitaremos dos formularios más en usuarios/formaciones.

# ... Importaciones
class UserUpdateForm(forms.ModelForm):
    email = forms.EmailField()
    class Meta:
        model = User
        fields = ['username', 'email']

phone_number_label = 'Phone number (no spaces, parenthesis \'(\' or dashes \'-\', numbers beginning with + only)'

class ProfileUpdateForm(forms.ModelForm):
    subscribed = forms.BooleanField(required=False)
    phone_number = forms.CharField(required=False)
    def __init__(self, *args, **kwargs):
        super(ProfileUpdateForm, self).__init__(*args, **kwargs)
    class Meta:
        model = Profile
        fields = ['bio', 'phone_number', 'enable_mfa', 'subscribed']
A continuación, podemos crear una vista para usar ambos formularios. Editar usuarios/vistas.py y agregar la vista.

# Agregue estas importaciones
from .forms import UserUpdateForm, ProfileUpdateForm
from django.views.decorators.cache import never_cache
from django.views.decorators.csrf import csrf_exempt
from .models import Profile
from .mfa import send_user_text

@csrf_exempt
@never_cache
@login_required
def profile(request):
    if request.method == 'POST':
        u_form = UserUpdateForm(request.POST, instance=request.user)
        p_form = ProfileUpdateForm(request.POST,
                                       request.FILES,
                                       instance=request.user.profile)
        if u_form.is_valid() and p_form.is_valid():
            new_phone_number = p_form.data['phone_number']
            u_form.save()
            profile = p_form.save(commit=False)
            profile.phone_number = profile.phone_number.replace('-', '').replace('(','').replace(')','')
            profile.save()
            if new_phone_number != oldprofile.phone_number and oldprofile.phone_number and len(oldprofile.phone_number) >= 11:
                profile.mfa_enabled = True
                profile.save()
                send_text(oldprofile.phone_number, 'Your phone number has been updated to ' + new_phone_number + '. Please refer to texts on that phone to log in. If you didnt make this change, please call us. - {}'.format(settings.SITE_NAME))
            if profile.enable_two_factor_authentication and profile.phone_number and len(profile.phone_number) < 11:
                profile.enable_two_factor_authentication = False
                messages.success(request, f'Two factor authentication can\'t be activated without entering a phone number. Please enter a phone number to enable two factor authentication.')
            profile.save()
            if new_phone_number != oldprofile.phone_number and new_phone_number and len(new_phone_number) >= 11:
                send_user_text(request.user, 'You have added this number to {} for two factor authentication. You can now use your number for two factor authentication. If you didnt make this change, please call us. - {}'.format(settings.SITE_NAME, settings.DOMAIN))
                profile.mfa_enabled = True
                profile.mfa_code_expires = timezone.now() + datetime.timedelta(minutes=3)
                profile.save()
                return redirect(profile.create_auth_url())
            messages.success(request, f'Your profile has been updated!')
            print('Profile updated')
            return redirect('users:profile')
    else:
        u_form = UserUpdateForm(instance=request.user)
        p_form = ProfileUpdateForm(instance=request.user.profile, initial={'phone_number': request.user.profile.phone_number if request.user.profile.phone_number else '+1'})
    context = {
        'u_form': u_form,
        'p_form': p_form,
        'title':'Update Your Profile',
    }
    return render(request, 'users/profile.html', context)
También necesitaremos una plantilla para esta vista.

nano users/templates/users/profile.html
 
{% extends "base.html" %}
{% load crispy_forms_tags %}
{% load feed_filters%}
{% block content %}
	<h2>Edit Your Profile</h2>  
	<form method="POST" enctype="multipart/form-data" id="profile-form">
          {% csrf_token %}
          <fieldset class="form-group">
              <legend class="border-bottom mb-4 mt-4">Profile info</legend>
              {{ u_form|crispy }}
              {{ p_form|crispy }}
          </fieldset>
          <div class="form-group">
              <button class="btn btn-outline-info" type="submit">Update}</button>
          </div>
	</form>
        <p style="text-color: green;" class="hide" id="posted">Saved</p>

{% endblock content %}
{% block javascript %}
var form = document.getElementById('profile-form');
$('input').change(function(){
	var formdata = new FormData(form);
	$.ajax({
		url: window.location.href,
		type: "POST",
		data: formdata,
		processData: false,
		contentType: false,
		timeout: 1000 * 60,
                success: function(data) {
                  $(posted).removeClass("hide");
		  setTimeout(function() {
			$(posted).addClass("fade-hidden");
			setTimeout(function() {
				$(posted).addClass("hide");
				$(posted).removeClass("fade-hidden");
			}, 2000);
		  }, 2000);
                }
	});
});
{% endblock %}
 
Notará que esta es una forma bastante simple, pero tiene un JavaScript que publica automáticamente el contenido del formulario a medida que se actualizan. Es útil tener esto, por lo que puede hacer ediciones sin tener que presionar Subting Every Time. A continuación, necesitamos URL que representen todas estas vistas en los patrones de URL de los usuarios. Editar usuarios/urls.py y agregar este código:

# ... Código anterior, importaciones
from django.urls import path
from . import views

app_name='users'

urlpatterns = [
# ... Patrones de URL en la que ingresamos anteriormente, agregue las siguientes tres líneas
    path('mfa/<str:username>/<str:token>/', views.mfa, name='mfa'),
    path('mfa/onboarding/', views.mfa_onboarding, name='mfa_onboarding'),
    path('profile/', views.profile, name='profile'),
]
Ahora es un buen momento para probar nuestro proyecto. Pero primero, ejecutemos otra copia de seguridad.

backup
Y ejecuta el servidor. Antes de desplegar en un servidor de Linux, es una buena idea habilitar la autenticación de dos factores en la cuenta. Lo haremos yendo a nuestra URL de perfil,/usuarios/perfil/, y verificaremos el cuadro para habilitar la autenticación después de ingresar nuestro número de teléfono, y luego enviar el formulario.

python manage.py runserver localhost:8000
Visite la página web yendo a su navegador web, estoy usando Google Chrome en este ejemplo e ingresando la URL https: // localhost: 8000/cuentas/perfil// Podrá iniciar sesión si es necesario y habilitar la autenticación de dos factores. Este proyecto necesita un servidor para ejecutar para que realmente pueda enviar correo. Pero primero, necesitamos una forma de ver errores. Notará que si ejecuta el servidor en modo de depuración, con settings.debug igual a verdadero, el servidor muestra errores automáticamente. Para mostrar errores sin usar el modo de depuración, que no es seguro en un servidor de producción, debemos agregar una vista para ello. Los errores más importantes que necesitamos poder manejar son: Error 500: un problema con nuestro código Error 404: una página que no se encontró (URL rota) Error 403: un error denegado por permiso Agreguemos una nueva aplicación para manejar estos errores, llamados errores.

python manage.py startapp errors
Agregue esto a Settings.py como lo hicimos antes, en la configuración Installed_Apps, y comience agregando referencias a algunas vistas en APP/URLS.py, donde la aplicación es el nombre de su proyecto Django.

handler404 = 'errors.views.handler404'
handler500 = 'errors.views.handler500'
handler403 = 'errors.views.handler403'
Esto es todo lo que necesitamos además de vistas de error, plantillas y un poco de middleware. Definamos los que así:

from django.shortcuts import render, redirect
from django.http import HttpResponse
from stacktrace.models import Error
from errors.middleware import get_current_exception
from django.contrib.auth.decorators import login_required
from django.contrib.auth.decorators import user_passes_test
from .logs import get_logs
from face.tests import is_superuser_or_vendor
from django.views.decorators.csrf import csrf_exempt
from errors.highlight import highlight_code
from django.shortcuts import redirect
from django.urls import reverse

# Crea tus puntos de vista aquí.
@login_required
@user_passes_test(is_superuser_or_vendor)
def logs(request):
    logs = highlight_code(get_logs())
    return render(request, 'errors/live_error.html', {'title': 'Error Logs', 'pagetitle': 'Error Logs', 'notes': 'These are the recent error logs.', 'trace': logs, 'full': True})

@login_required
@user_passes_test(is_superuser_or_vendor)
def logs_api(request):
    logs = highlight_code(get_logs())
    return HttpResponse(logs)

@login_required
def handler404(request, exception):
    if not request.path.endswith('/'): return redirect(request.path + '/')
    return render(request, 'errors/error.html', {'title': 'Error 404', 'pagetitle': 'Error 404', 'notes': 'This page was not found on the server. It may have moved or been deleted.', 'is_404': True})

def handler500(request):
    print(get_current_exception())
    user = None
    if hasattr(request, 'user') and request.user and request.user.is_authenticated:
        user = request.user
    try:
        Error.objects.create(user=user, stack_trace=get_current_exception(), notes='Logged by 500 handler.')
    except: pass
    return render(request, 'errors/error.html', {'title': 'Error 500', 'pagetitle': 'Error 500', 'notes': 'There is a problem with the server, or with a request coming from you. Thank you for your understanding while we get things set up.', 'trace': get_current_exception()})

def handler403(request, exception):
    return render(request, 'errors/error.html', {'title': 'Error 403', 'pagetitle': 'Error 403', 'notes': 'You don\'t have permission to preform this request. If you think this is in error, please contact the server administrator.', 'is_403': True})

def handler400(request, exception):
    return render(request, 'errors/error.html', {'title': 'Error 400', 'pagetitle': 'Error 400', 'notes': 'This was a bad request.'})
A continuación, definamos el middleware para manejar estos errores. Lo haremos primero agregando a middleware_classes en settings.py, con el nombre de nuestro middleware.

MIDDLEWARE_CLASSES = [
    # ... Middleware anterior
    'errors.middleware.ExceptionVerboseMiddleware,
]
A continuación, agregemos el middleware.

from threading import local
import traceback
from django.utils.deprecation import MiddlewareMixin

_error = local()

class ExceptionVerboseMiddleware(MiddlewareMixin):
    def process_exception(self, request, exception):
        _error.value = traceback.format_exc()

def get_current_exception():
    try:
        return _error.value
    except AttributeError:
        return None

def set_current_exception(exception):
    try:
        _error.value = exception
    except AttributeError:
        print('Attribute error setting exception.')
Agregamos una función para obtener la excepción actual utilizando un hilo local, lo que nos ayuda a rastrear cualquier error en nuestro código. En términos de plantillas, solo necesitamos una, porque definimos dinámicamente el título en la vista. La plantilla solo necesita representar el título y "trazar", nuestro rastreo de error desde el contexto.

nano errors/templates/errors/error.html
 
{% extends 'base.html' %}
{% block content %}
<h1>{{ pagetitle }}</h1>
<p>{{ trace }}</p>
{% endblock %}
 
Esta es nuestra plantilla más simple hasta ahora, pero así es lo fácil que es ver los errores en nuestro proyecto. A continuación, desactivemos la depuración en la configuración.

nano app/settings.py
Encuentra esta línea donde se establece en verdadero y cámbiela a falso

DEBUG = False
Continúe y haga una copia de seguridad de la aplicación ahora. Estamos listos para implementar en un servidor remoto de Linux y seguir agregando funciones desde allí.

sudo backup
Antes de publicar este código en un servidor, debemos considerar que puede haber algunos problemas con el código. Dependiendo del caso, los sitios que acepten información que se les publiquen tendrán problemas con el spam que se publica y la dificultad para eliminar el spam. Esto no debería suceder de inmediato, pero si está sucediendo, luego examinaremos cómo moderar automáticamente el spam en el sitio y dificultar que los robots accedan al sitio, junto con cómo desactivar las cuentas de los usuarios y verificar la identidad de un usuario con Un escaneo de su identificación o una exploración biométrica, como una huella digital o reconocimiento facial. Mirando el ejemplo de autenticación de factores múltiples que examinamos, en la producción, las cosas pueden ser diferentes. Observe cómo estamos calificando los inicios de sesión y tokens que vencen. Si los robots están accediendo a un sitio, la autenticación de dos factores puede ser más difícil, ya que pueden ingresar códigos al mismo tiempo que lo es el usuario. Para combatir esto, usemos un modelo en los modelos de usuario, declarando cómo interactuamos con el sitio cuando estamosAutenticación utilizando autenticación de factores múltiples con un número de teléfono. También agregaremos una opción para autenticarnos con el correo electrónico. Comience editando los modelos de usuario con

nano users/models.py
Así es como debería ser el modelo que estamos agregando. No necesitamos ningún método, solo variables para almacenar una identificación, el usuario, la marca de tiempo, la expiración, la longitud e intentos contra cualquier autenticación de factores múltiples (un código como 123456 enviado a un teléfono o correo electrónico).

# Un token básico utilizado para iniciar sesión en el sitio web
class MFAToken(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='mfa_tokens')
    timestamp = models.DateTimeField(default=timezone.now)
    expires = models.DateTimeField(default=timezone.now)
    token = models.CharField(default='', max_length=100)
    length = models.IntegerField(default=6)
    attempts = models.IntegerField(default=0)
    uid = models.CharField(default=uuid.uuid4, max_length=100)
También agregemos un privilegio a nuestro usuario, y lo configuraremos manualmente por ahora, antes de eventualmente migrar a los usuarios privilegiados automáticamente. En los modelos de usuario, agregue esta línea en el perfil:

    vendor = models.BooleanField(default=False)
Al igual que con cualquier cambio en la base de datos, necesitamos hacer migraciones y migrar la base de datos en cualquier momento que editemos un archivo modelos.py en Django. Recuerde, para hacer esto usamos primero la fuente (si aún no se ha utilizado desde que el terminal estaba abierto) y luego Python Managem.py para hacer las migraciones y migrar.

cd project-directory-you-named # (si es necesario)
source venv/bin/activate
python manage.py makemigrations && python manage.py migrate
Por ahora, puede solicitar cualquier cuenta que haya creado como proveedores utilizando el shell.

python manage.py shell
from users.models import Profile
p = Profile.objects.get(user__username='Charlotte')
p.vendor = True
p.save()
exit()
Ahora, evolucionemos nuestra visión de autenticación de factores múltiples para usar este token. Primero, necesitamos modificar nuestras utilidades de ayudante MFA. Usando nano,

nano users/mfa.py

from django.utils import timezone
import random
import datetime
from django.conf import settings
from feed.middleware import get_current_request
from django.contrib import messages
from .email import send_html_email
import traceback
from .models import MFAToken

account_sid = settings.TWILIO_ACCOUNT_SID
auth_token = settings.TWILIO_AUTH_TOKEN
source_phone = settings.PHONE_NUMBER

def send_text(target_phone, text):
    from twilio.rest import Client
    try:
        client = Client(account_sid, auth_token)
        if len(target_phone) >= 11:
            message = client.messages.create(
                to=target_phone,
                from_=source_phone,
                body=text + ' Text STOP to cancel.')
    except:
        messages.warning(get_current_request(), 'There was an error sending the message.')
        print(traceback.format_exc())

def get_num_length(num, length):
    n = ''
    for x in range(length):
        n = n + str(num)
    return int(n)

def send_verification_text(user, token):
    length = user.profile.verification_code_length
    code = random.randint(get_num_length(1, length), get_num_length(9, length));
    token.token = code
    token.expires = timezone.now() + datetime.timedelta(minutes=settings.AUTH_VALID_MINUTES)
    token.save()
    send_user_text(user, "Your verification code for {} is {}".format(settings.SITE_NAME, str(code)))

def send_verification_email(user, token):
    length = user.profile.verification_code_length
    code = random.randint(get_num_length(1, length), get_num_length(9, length));
    token.token = code
    token.expires = timezone.now() + datetime.timedelta(minutes=settings.AUTH_VALID_MINUTES)
    token.save()
    send_html_email(user, "Your verification code for {} is {}".format(settings.SITE_NAME, str(code)), "<p>Dear {},</p><p>Your verification code for {} is {}. Thank you for using this code to secure your account.</p><h2>{}</h2><p>Sincerely, {}</p>".format(user.profile.name, settings.SITE_NAME, str(code), str(code), settings.SITE_NAME))

def send_user_text(user, text):
    send_text(user.profile.phone_number, text)

def check_verification_code(user, token, code):
    token.attempts = token.attempts + 1
    profile = user.profile
    result = (token != None and code != '' and token.token == code and (token.expires > timezone.now()) and token.attempts <= settings.MFA_TOKEN_ATTEMPTS)
    if token.attempts < 3 and result:
        profile.verification_code_length = 6
    elif token.attempts > 1 and not result:
        profile.verification_code_length = profile.verification_code_length + 2
        if profile.verification_code_length > settings.MFA_TOKEN_LENGTH: profile.verification_code_length = settings.MFA_TOKEN_LENGTH
    token.save()
    profile.save()
    return result

# Autenticar al usuario usando su correo electrónico o número de teléfono
def mfa(request, username, usertoken):
    token = MFAToken.objects.filter(uid=username, expires__gt=timezone.now() + datetime.timedelta(seconds=30)).order_by('-timestamp').last() # Filtrar el token por el valor pasado en la URL (un UUID)
    if not token: token = MFAToken.objects.create(user=User.objects.filter(profile__uuid=username).first(), uid=username, expires=timezone.now() + datetime.timedelta(seconds=115)) # Si esta sesión no se ha creado, creala
    user = User.objects.filter(id=token.user.id).first() # Obtenga al usuario del token
    if not user and request.user.is_authenticated: return redirect(reverse('feed:home')) # Si ya están autenticados, iniciarlos
    if not user: raise PermissionDenied() # Denegar si no se encontró ningún usuario
    next = request.GET.get('next','')
    if not user.profile.enable_two_factor_authentication and user.is_active and user.profile.check_auth_token(usertoken, token): # Verifique el token de autenticación
        auth_login(request, user, backend='django.contrib.auth.backends.ModelBackend') # Inicie sesión en el usuario si aún no ha iniciado sesión
        user.profile.mfa_expires = timezone.now() + datetime.timedelta(minutes=settings.LOGIN_VALID_MINUTES) # Establezca un vencimiento en su autenticación de factores múltiples
        user.profile.save()
        return HttpResponseRedirect(next if next != '' else reverse('landing:landing')) # Redirige al usuario a la página siguiente
    if not user.profile.mfa_enabled: # Compruebe si MFA está habilitado
        if not check_verification_time(user, token): # Verifique la hora
            user.profile.mfa_enabled = False # Borrar el número de teléfono
            user.profile.enable_two_factor_authentication = True # Habilitar MFA
            user.profile.phone_number = '+1' # Deshabilitar el número de teléfono
            user.profile.save() # Guardar el perfil
            auth_login(request, user, backend='django.contrib.auth.backends.ModelBackend') # Inicie sesión al usuario si su MFA no está habilitado
            messages.warning(request, 'Please enter a valid phone number and verify it with a code.')
            return redirect(reverse('users:mfa_onboarding'))
    if request.method == 'POST' and not fraud_detect(request, True): # Si la solicitud es una solicitud posterior
        form = TfaForm(request.POST) # Instanciar el formulario
        code = str(form.data.get('code', None)) # Obtener el código
        if code and code != '' and code != None: # Asegúrate de que no esté vacío
            token_validated = user.profile.check_auth_token(usertoken) # Verifique el token de autenticación
            p = user.profile
            is_verified = check_verification_code(user, token, code) # Verifique el código
            p.mfa_authenticated = is_verified
            if token_validated: # Si todo
                if is_verified: # Está en orden
                    user.profile.mfa_enabled = True # Habilitar MFA (si aún no está habilitado)
                    user.profile.save()
                    auth_login(request, user, backend='django.contrib.auth.backends.ModelBackend') # Iniciar sesión en el usuario
                    face = user.faces.filter(session_key=None).last() 
                    p.mfa_expires = timezone.now() + datetime.timedelta(minutes=settings.LOGIN_VALID_MINUTES)
                    p.save()
                    messages.success(request, 'You have been authenticated. Welcome.')
                    qs = '?'
                    for key, value in request.GET.items(): # Construya una QueryString para el siguiente parámetro (si corresponde)
                        qs = qs + key + '=' + value + '&'
                    if next != '' and not (next.startswith('/accounts/logout/') or  next.startswith('/accounts/login/') or next.startswith('/admin/login/') or next.startswith('/accounts/register/')):
                        return HttpResponseRedirect(next) # Redireccionar
                    elif next.startswith('/accounts/logout/') or next.startswith('/accounts/login/') or next.startswith('/accounts/register/'):
                        return redirect(reverse('/'))
                    elif request.META.get('HTTP_REFERER', '/').startswith('/accounts/login/'):
                        return redirect(reverse('/'))
                    elif not next:
                        return redirect(reverse('/'))
                    else:
                        return HttpResponseRedirect(reverse('verify:age') + '?next=' + request.META.get('HTTP_REFERER', '/'))
                else:
                    messages.warning(request, 'The code you entered was not recognized. Please try again.')
            elif not token_validated: # Si el token no era válido
                messages.warning(request, 'The URL token has expired or was not recognized. Please try again.')
                logout(request)
                return redirect(reverse('users:login'))
            if p.mfa_attempts > 3: # Si hubiera demasiados intentos
                messages.warning(request, 'You have entered the incorrect code more than 3 times. please send yourself a new code.')
                p.verification_code = None
                p.save()
        elif user.profile.can_send_mfa < timezone.now():
            user.profile.mfa_attempts = 0
            user.profile.can_send_mfa = timezone.now() + datetime.timedelta(minutes=2)
            user.profile.save()
            if form.data.get('send_email', False): # Enviar el correo electrónico (o mensaje de texto)
                send_mfa_verification_email(user, token)
            else:
                send_verification_text(user, token)
            messages.success(request, "Please enter the code sent to your phone number or email. The code will expire in 3 minutes.")
        elif user.profile.can_send_mfa < timezone.now() + datetime.timedelta(seconds=115):
            messages.warning(request, 'You are sending too many two factor authentication codes. Wait a few minutes before sending another code.')
    form = TfaForm()
    hide_logo = None
    if user.profile.hide_logo:
        hide_logo = True
    if request.user.is_authenticated: return redirect(reverse('/'))
    # Renderizar el formulario (para obtener solicitudes)
    return render(request, 'users/mfa.html', {'title': 'Enter Code', 'form': form, 'xsmall': True, 'user': user, 'hide_logo': hide_logo, 'accl_logout': user.profile.shake_to_logout, 'preload': False, 'autofocus': request.method == 'POST'})
Cuando agregamos este código, asegúrese de importar la función para enviar un correo electrónico. En la parte superior del archivo, el usuario ve (con otras importaciones), agregue

from .mfa import send_verification_email as send_mfa_verification_email
Ahora, necesitamos escribir esa función antes de que todo esto funcione. Debe extender nuestra función de correo electrónico de envío y simplemente enviar un correo electrónico al usuario con el código de verificación.

nano users/mfa.py

def send_verification_email(user, token):
    length = user.profile.verification_code_length
    code = random.randint(get_num_length(1, length), get_num_length(9, length));
    token.token = code
    token.expires = timezone.now() + datetime.timedelta(minutes=settings.AUTH_VALID_MINUTES)
    token.save()
    send_html_email(user, "Your verification code for {} is {}".format(settings.SITE_NAME, str(code)), "<p>Dear {},</p><p>Your verification code for {} is {}. Thank you for using this code to secure your account.</p><h2>{}</h2><p>Sincerely, {}</p>".format(user.profile.name, settings.SITE_NAME, str(code), str(code), settings.SITE_NAME))
Por lo tanto, todo esto funciona muy bien, ahora tenemos un sistema de autenticación de múltiples factores que depende de un número de teléfono o correo electrónico para iniciar sesión. Pero también necesitamos una forma de eliminar, o al menos ocultar a los usuarios que no cooperan con nuestros términos. Estos podrían ser spammers, robots o cualquier persona que no signifique bien para nuestro trabajo. Eche un vistazo a una vista que tengo para monitorear a los usuarios en mi sitio web:

# cantidades
from django.contrib.auth.decorators import login_required
from django.contrib.auth.decorators import user_passes_test
from .tests import is_superuser_or_vendor # Tendremos que crear esta prueba

@login_required
@user_passes_test(is_superuser_or_vendor)
def users(request):
    # Obtener una lista de usuarios
    new_today = User.objects.filter(is_active=True, date_joined__gte=timezone.now() - datetime.timedelta(hours=24)).count()
    new_this_month = User.objects.filter(is_active=True, date_joined__gte=timezone.now() - datetime.timedelta(hours=24*30)).count()
    subscribers = User.objects.filter(is_active=True, profile__subscribed=True).count()
    return render(request, 'users/users.html', { # Devolver a los usuarios en una plantilla
        'title': 'All Accounts',
        'users': User.objects.all(),
        'new_today': new_today,
        'new_this_month': new_this_month,
        'subscribers': subscribers
    })
Tenga en cuenta que este código usa una prueba, necesitaremos declarar esta prueba en un archivo Tests.py e importarla. Edición de usuarios/tests.py, creemos la prueba.

def is_superuser_or_vendor(user):
    return user.profile.vendor or user.is_superuser
Esto está junto con la plantilla usuarios/usuarios.html, que se parece a esto:
 
{% extends 'base.html' %}
{% load app_filters %}
{% block content %}
<h1>All Registered Visitors</h1>
<p>{{ new_today|nts|capitalize }} new today, {{ new_this_month|nts }} new this month, {{ subscribers|nts }} subscribers, {{ users.count|nts }} total.</p>
<hr style="color: red;">
{% for user in users %}
{% include 'users/_user.html' %}
<hr style="color: blue;">
{% endfor %}
{% endblock %}
 
Tenga en cuenta que la plantilla incluye otra plantilla, usuarios/_user.html. Cuando se usa una plantilla que tiene una subtemplato y no use extensiones, es una buena idea agregar un subrayador (_) antes del nombre del archivo para extenderse, para distinguir las plantillas. Tenga en cuenta que esto es una gran cantidad de jinja, es posible que no tenga todas estas variables definidas. Pero así es como se ve mi código.
 
{% load app_filters %}
<div>
<img src="{{ user.profile.get_image_url }}" alt="@{{ user.profile.name }}'s profile photo" width="120" height="120" align="left" style="margin-top:5px; margin-right:10px; margin-bottom:10px; border-radius: 50%;"/>
    <div class="article-metadata">
      <p class="mr-2">@{{ user.username }} - {{ user.profile.name }} ({{ user.profile.preferred_name }})</p>
      <small class="text-muted">Last seen {{ user.profile.last_seen|date:"F d, Y" }} {{ user.profile.last_seen|time:"H:i" }}</small>
      <small class="text-muted">Joined on {{ user.profile.date_joined|date:"F d, Y" }} {{ user.profile.date_joined|time:"H:i" }}</small>
      <small>{{ user.email }}</small>
      {% if user.profile.phone_number %}<small><i class="bi bi-phone-fill"></i>{{ user.profile.phone_number }}</small>{% endif %}
      {% if user.verifications.last %}
      <small>'{{ user.verifications.last.full_name }}'</small>
      <small><i class="bi bi-123"></i> {{ user.verifications.last.document_number }}</small>
      <small><i class="bi bi-calendar-heart-fill"></i> {{ user.verifications.last.birthdate }}</small>
      <a href="{{ user|document_front }}" class="btn btn-sm btn-outline-primary" title="ID front"><i class="bi bi-person-badge-fill"></i> ID front</a>
      <a href="{{ user|document_back }}" class="btn btn-sm btn-outline-primary" title="ID back"><i class="bi bi-upc-scan"></i> ID back</a>
      {% endif %}
      <small># {{User.id}} </small>
      <small>{% if user.profile.subscribed %}Subscribed{% else %}Not subscribed{% endif %}</small>
    </div>
    {%if not user.is_superuser %}
    <div style="float: right;">{% include 'users/toggle_active.html' %}</div>
    {% endif %}
    {% autoescape off %}    
    <p class="article-content">{{ user.bio }}</p>
    {% endautoescape %}
    <hr>
    <p>{% if user.profile.identity_verified %}Verified user.{% else %}Unverified user.{% endif %} Verifications: {{ user.verifications.count|nts }}</p>
 
También necesitamos otra subtemplato, toggle_active.html. Esta plantilla debe ser un formulario que nos permita alternar si un usuario está activo.
 
<form style="display: inline-block;" action="{% url 'users:toggle-user-active' user.id %}" method="POST" id="publishForm">
<button class="btn btn-sm btn-outline-danger" type="submit">{% if user.is_active %}<i class="bi bi-eye-fill"></i>{% else %}<i class="bi bi-eye-slash-fill"></i>{% endif %}</button>
</form>
 
También necesitaremos agregar una vista para alternar la actividad del usuario y los patrones de URL apropiados. Mientras lo hacemos, agregemos una vista para eliminar a un usuario en caso de que lo necesitemos.

from django.views.decorators.csrf import csrf_exempt

@csrf_exempt
@login_required
@user_passes_test(is_superuser_or_vendor)
def toggle_user_active(request, pk):
    user = User.objects.get(id=pk)
    if request.method == 'POST':
        user.is_active = not user.is_active
        user.save()
    return HttpResponse('<i class="bi bi-eye-fill"></i>' if user.is_active else '<i class="bi bi-eye-slash-fill"></i>')


# Cantidades
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.views.generic import DeleteView

class UserDeleteView(LoginRequiredMixin, UserPassesTestMixin, DeleteView):
    model = User
    success_url = '/' # La redirección de la URL de éxito
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        return context

    def test_func(self): # Pruebe si el usuario es superusador y tiene permiso para eliminar
        user = self.get_object()
        if self.request.user != user and self.request.user.is_superuser:
            return True
        return False
Si bien esto es práctico cuando sea necesario, eliminar a un usuario no debería ser necesario la mayor parte del tiempo, podemos alternar la visibilidad de los usuarios que visitan el sitio si necesitamos descartarlos. Los patrones de URL que agregamos se ven así. Con nano, edite usuarios/urls.py y agregue estas líneas:

nano users/urls.py
Las líneas deben ir en la lista de rutas en las vistas del usuario, antes del final "]" pero después del comienzo "[".

# …
    path('user/<int:pk>/delete/', UserDeleteView.as_view(template_name='blog/user_confirm_delete.html'), name='delete-user'),
    path('user/<int:pk>/active/', views.toggle_user_active, name='toggle-user-active'),
# …
Ahora, asegúrese de hacer una copia de seguridad del sitio para que pueda descargarlo en el servidor web en el que continuaremos trabajando. Desde la línea de comando,

sudo backup
Ahora nuestro sitio está respaldado. Así que ahora tenemos algunas características más útiles. Pero, ¿qué pasa con el panorama general aquí? Este código aún no es accesible desde Internet, todavía no tenemos un servidor de correo, y necesitamos expandir nuestra aplicación para incluir un proceso de verificación integral, así como diseños suaves para ayudarnos a explorar el sitio, junto con protocolos seguros para autenticar a los usuarios privilegiados. . Llegaremos a todo esto. Lo más importante por ahora será obtener este código en línea, lo que podemos hacer con solo unas pocas líneas de bash en un servidor Ubuntu. Sin embargo, deberá alquilar un servidor para esto, a menos que tenga un servidor en el hogar y una suscripción comercial en Internet que le permita abrir puertos. Personalmente ejecuto mi sitio web en un HP Z440 que está instalado en mi apartamento, pero generalmente es mucho más barato para las necesidades básicas para alquilar un servidor privado virtual (VPS). Tenga en cuenta que el código que estamos ejecutando ahora es relativamente delgado, deberá mantenerse y mejorarse antes de que seamosListo para usar lo que tenemos para construir un producto. Asegúrese de tener cuidado con lo que hace con Internet, asegúrese de que si implementa este sitio públicamente en la web en un servidor de Linux, tiene un plan para bloquear las interacciones no deseadas con su sitio web. Es probable que esto no sea un problema al principio, pero analizaremos una variedad de soluciones para combatir esto, incluido el aprendizaje automático, la inteligencia artificial y la visión por computadora. Cuando se convierta en un problema, busque más en este texto para una solución. En términos de alquilar un VPS, hay muchos lugares a los que puede ir. Google Cloud tiene servidores VPS, Ionos, Kamatera, Amazon AWS y más proveedores ofrecen soluciones de servidor en la nube que se adaptarán a nuestras necesidades. Deberá hacer clic en sus formularios y seleccionar un plan para comenzar. Puede ir con un plan básico con cualquier proveedor, pero asegúrese de que el proveedor le permita abrir puertos de servidor de correo de puertos para enviar correo electrónico (esto debería ser el puerto 587 y el puerto 25), algunos proveedores bloquean estos puertos. Hasta ahora he tenido elEST experiencia con Ionos y Kamatera, ambos me permitirán enviar un correo electrónico ilimitado y sus precios son bastante baratos. Se conectará a su nuevo servidor a través de un protocolo llamado SSH o Secure Shell, lo que le permite interactuar de forma remota con el servidor exactamente como su computadora personal, desde su computadora personal. Cuando configure el servidor, el proveedor de alojamiento probablemente le pedirá que agregue una tecla SSH, o le darán un nombre de usuario y contraseña. La tecla SSH es cómo iniciará sesión en el servidor desde la línea de comando para editar el código. Use las siguientes opciones de ssh-keygen para generar un SSH

ssh-keygen
Guarde el archivo y sobrescribirlo si es necesario, es bueno rotar sus claves SSH si aún no lo ha hecho. Ahora, puede usar el siguiente comando para ver su tecla SSH. Deberá copiarlo en su servidor remoto para poder usarlo para autenticarse.

cat ~/.ssh/id_rsa.pub
Si no pudo ver una tecla SSH al escribir ese comando (una larga cadena de dígitos y letras que comienzan con "SSH-RSA AAA"), intente generar una tecla RSA (son más seguras, por lo que aconsejo usarlos .) El siguiente código generará una tecla RSA SSH de 4096 bits.

ssh-keygen -t rsa -b 4096
Cree un VPS que ejecute Ubuntu, sin embargo, planea hacer esto. Una vez que haya creado un VPS haciendo clic en los formularios en el sitio web de los proveedores (kamatera.com, ionos.com o similar), querrá iniciar sesión. Para hacer esto, use el comando ssh con su dirección IP (la dirección Eso se parece a xx.xx.xx.xx). También deberá ser sensible al nombre de usuario predeterminado en el servidor que creamos, por ejemplo, Ubuntu.

ssh ubuntu@XX.XX.XX.XX
Es posible que se le solicite una contraseña, si se le pide una contraseña, ingrese. No usaremos el nombre de usuario predeterminado, así que comencemos creando un nuevo usuario y agregando una clave SSH a su cuenta. Comencemos agregando un nuevo archivo sshd_config, que le dice al servidor cómo usar SSH.

nano sshd_config

# Este es el archivo de configuración del sistema SSHD en todo el sistema.  Ver
# sshd_config (5) para obtener más información.

# Este SSHD se compiló con ruta =/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games

# La estrategia utilizada para las opciones en el sshd_config predeterminado enviado con
# OpenSSH es especificar opciones con su valor predeterminado donde
# posible, pero déjalos comentados.  Opciones no commentadas anule el
# Valor predeterminado.

# Puerto 22
# Direcciones en cualquier
# Dirección de la lista 0.0.0.0
# Escuchar adress ::

# Llave de hosts/etc/ssh/ssh_host_rsa_key
# Llave de hosts/etc/ssh/ssh_host_ecdsa_key
# Hostkey/etc/ssh/ssh_host_ed25519_key

# CIPHERS Y MAYA
# Rekeylimit predeterminado ninguno

# Explotación florestal
# Auth SyslogFacility
# Información de Loglevel

# Autenticación:

# LOGRINGRACETIME 2M
# Permitrootlogin Prohibit-Password
# Strict Modes si
# Maxauthtries 6
# Maxesiones 10

PubkeyAuthentication yes

# Espere que .SSH/Authorized_Keys2 se ignore de forma predeterminada en el futuro.
AuthorizedKeysFile	.ssh/authorized_keys .ssh/authorized_keys2

# Autorizado PRIVIPALSFILE NINGUNO

# Autorizado keyscommand ninguno
# Autorizado keyscommanduser nadie

# Para que esto funcione, también necesitará claves host en/etc/ssh/ssh_konk_hosts
# HostBasedAuthentication no
# Cambie a sí si no confía ~/.ssh/conoce_hosts para
# Atenticación de HostBased
# Ignoreuser conocido no
# No lea los archivos ~/.rhosts y ~/.shosts del usuario
# IgnorerHosts si

# Para deshabilitar las contraseñas de texto claras, cambie a no aquí!
PasswordAuthentication no
# PermenTemptyPasswords No

# Cambie a sí para habilitar las contraseñas de respuesta a la respuesta (tenga cuidado con los problemas con
# Algunos módulos y hilos de PAM)
KbdInteractiveAuthentication no

# Opciones de Kerberos
# Kerberosautatication no
# Kerberosorlocalpasswd Sí
# Kerberosticketcleanup sí
# Barra kerberoscoted no

# Opciones de GSSAPI
# Gssapiauthentication no
# Gssapicleanupcredentials sí
# GSSAPISTRICTACCEPTORCHECK Sí
# GSSAPIKEYEXCHIVE NO

# Establezca esto en 'Sí' para habilitar la autenticación de PAM, el procesamiento de la cuenta,
# y procesamiento de sesión. Si esto está habilitado, la autenticación de PAM
# Se permitirá a través de KBDinteractiveAuthentication y
# Contraseña Autenticación.  Dependiendo de su configuración de PAM,
# Autenticación de PAM a través de KBDinteractiveAuthentication puede omitir
# La configuración de "Permitrootlogin sin pasas".
# Si solo desea que la cuenta PAM y las verificaciones de sesión se ejecute sin
# Autenticación de PAM, luego habilite esto, pero establezca la autenticación de contraseña
# y kbdinteractiveAuthentication a 'no'.
UsePAM yes

# Permitir el consumo de trabajo sí sí
# Permitirse para hacer
# Gatewayports no
X11Forwarding yes
# X11DisplaYoffset 10
# X11uselocalhost sí
# Permiso si
PrintMotd no
# Printlastlog Sí
# Tcpkeepalive sí
# Permiso
# Compresión retrasada
# Intervalo clientalivo 0
# Clientalivecountmax 3
# Usos en
# Pidfile /run/sshd.pid
# MaxStartups 10: 30: 100
# Pemittunl no
# Chrootdirectorio ninguno
# Versión Anexo Ninguno

# Sin ruta de banner predeterminada
Banner /etc/banner

# Permitir que el cliente pase variables de variables locales
AcceptEnv LANG LC_*

# anular el valor predeterminado de no subsistemas
Subsystem	sftp	/usr/lib/openssh/sftp-server

# Ejemplo de configuración primaria por usuario
# Coincidir con los anoncvs de usuario
# X11 para no
# Permitirse el trabajo no
# Definetty en
# Servidor CVS forCecommand
PermitRootLogin no
Recuerde, Ctrl+X e Y para guardar el archivo. A continuación, escribamos un script básico llamado Initialize (todo en el directorio de inicio predeterminado de nuestro usuario).

nano initialize
Agregue estas líneas al archivo, reemplazandoCon tu tecla SSH que encontraste usando CAT. (.ssh/id_rsa.pub)

# !
sudo apt install -y nano git openssh-server
sudo cp sshd_config /etc/ssh/sshd_config
sudo service ssh restart
sudo service sshd restart
echo "/root/.ssh/id_rsa" | sudo su root -c "ssh-keygen -t rsa -N ''"
echo "root ssh key:"
sudo su root -c "cat /root/.ssh/id_rsa.pub"
sudo adduser --disabled-password --gecos "" team
sudo passwd -d team
sudo usermod -aG sudo team
echo "/home/team/.ssh/id_rsa" | su team -c "ssh-keygen -t rsa -N ''"
cat /home/team/.ssh/id_rsa.pub >> /home/team/.ssh/authorized_keys
echo '<key here>' >> /home/team/.ssh/authorized_keys
echo "team ssh key:"
cat /home/team/.ssh/id_rsa.pub
Para guiarlo a través de este archivo, iniciemos la línea por línea. La primera línea le dice al compilador que este es un script bash. Luego estamos instalando dependencias, copiando sshd_config al directorio correcto, reiniciando ssh, generando claves ssh para root, agregando el "equipo" del usuario (puede elegir un nombre que le guste para esto, use el comando adduser con su nombre y contraseña deshabilitada para ahora). También agregamos equipo al grupo sudo, generamos su tecla SSH, agregamos nuestra clave a las claves y las suyas autorizadas también, e imprime su clave. Este nuevo usuario será cómo iniciamos sesión en el sitio. En un nuevo terminal, continúe y abra el servidor nuevamente.

ssh team@XX.XX.XX.XX
Esta vez no debería necesitar una contraseña, ya que tiene una tecla SSH. También hemos deshabilitado el inicio de sesión con la contraseña para mantener el sitio más seguro. Ahora, este servidor se inicia completamente en blanco sin información sobre él. Comencemos clonando nuestro proyecto de Git para que podamos descargarlo y ejecutarlo en la máquina remota. En el servidor remoto conectado a través de SSH, primero imprima su tecla SSH:

cat ~/.ssh/id_rsa.pub
A continuación, pegue esta clave en la configuración de GIT como lo hicimos antes para configurar nuestro repositorio Git. Ahora podemos clonar nuestro proyecto directamente al servidor. Asegúrese de haber hecho una copia de seguridad del proyecto localmente para que esté en el servidor GIT para descargar.

git clone git://github.com/you/yourproject.git
Perfecto. Ahora todos los archivos están aquí. Podemos verlos con LS

ls
Ahora, comencemos a configurar el servidor. Primero, copie su directorio de proyecto en un nombre simple y memorable que utilizaremos para el proyecto.

cp -r yourproject whatyoucalledit
Donde "WhatyoCalledit" es el nuevo nombre de su proyecto. A continuación, necesitaremos construir una utilidad básica para configurar el servidor. Guardaremos esta utilidad y la usaremos en el futuro. Para crear esta utilidad, creemos un binario de usuario para definir cómo editamos un script. Uso de Bash, Editar/USR/Bin/Ascript

sudo nano /usr/bin/ascript
Asegúrese de usar sudo allí para que tenga permisos para editar el archivo. En el archivo, agregue estas líneas:

# !
if [ ! -f /usr/bin/$1 ]; then
    sudo touch /usr/bin/$1
    echo "# !
    sudo chmod a+x /usr/bin/$1
    sudo nano /usr/bin/$1
    echo $1 | sudo tee -a /etc/ascripts
else
    sudo chmod a+x /usr/bin/$1
    sudo nano /usr/bin/$1
fi
Recuerde que este script toma un argumento, el nombre del script, como $ 1. Primero verifica si el archivo existe, o lo crea, agrega la primera línea para declarar que el script es bash, cambia sus permisos, lo edita y agrega su nombre a /etc /ascripts que nos permite almacenar los nombres de los scripts nosotros. están creando. Si el archivo ya existe, simplemente cambie los permisos y edítelo. Guarde el archivo y a continuación cambiaremos sus permisos. Mientras usemos este script, no tendremos que volver a hacer eso.

sudo chmod a+x /usr/bin/ascript
Perfecto. Ahora creemos un script llamado Configuración. Primero, no para abrumarte, pero eche un vistazo a cómo se ve mi script de configuración. Caeremos a través de cómo debería verse este guión en su proyecto, no necesitará todo en mi guión para comenzar.

# !
SECONDS=0
PYTHON_VERSION=3.12
echo "femmebabe installer initialized."
# sudo chmod a+x scripts/usereSetup
# ./scripts/usersetup
# Ssh-keyen
# Directorio de proyectos
DIR="/home/team/femmebabe"
USER="team"
# Comandos de registro
echo "Logging commands"
sudo cp log/commands.log /var/log/commands.log
sudo chmod -R a+w /var/log
sudo chown -R :syslog /var/log
echo $'alias venv="source /home/team/femmebabe/venv/bin/activate"' | sudo tee -a /home/team/.profile
echo $'PROMPT_COMMAND=\'RETRN_VAL=$?;logger -p local6.debug "$(whoami) [$$]: $(history 1 | sed "s/^[ ]*[0-9]\+[ ]*//" )"\'' | sudo tee -a /etc/bashrc
echo $'PROMPT_COMMAND=\'RETRN_VAL=$?;logger -p local6.debug "$(whoami) [$$]: $(history 1 | sed "s/^[ ]*[0-9]\+[ ]*//" )"\'' | sudo tee -a "/home/team/.bashrc"
echo $'PROMPT_COMMAND=\'RETRN_VAL=$?;logger -p local6.debug "$(whoami) [$$]: $(history 1 | sed "s/^[ ]*[0-9]\+[ ]*//" )"\'' | sudo tee -a /root/.bashrc
echo "source /etc/bashrc" | sudo tee -a /home/team/.profile
echo "/var/log/commands.log" | sudo tee -a /etc/logrotate.d/syslog
echo "local6.*    /var/log/commands.log" | sudo tee -a "/etc/rsyslog.d/bash.conf"
sudo service rsyslog restart
# Nano Config
echo "set tabsize 4" >> .nanorc
echo "set tabstospaces" >> .nanorc
# Configuración git
echo "Git configuration"
sudo git config --global user.email "jasper.camber.holton@gmail.com" && sudo git config --global user.name "Jasper Holton"
git config --global user.email "jasper.camber.holton@gmail.com"
git config --global user.name "Jasper Holton"
git config --global --add safe.directory $"$DIR"
sudo ssh-keyscan -t rsa gitlab.com | sudo tee -a /root/.ssh/known_hosts
sudo ssh-keyscan -t rsa github.com | sudo tee -a /root/.ssh/known_hosts
echo "Mounting setup"
sudo mount -o remount,size=16G,exec /tmp
# Actualizar e instalar
echo "Update and install packages"
sudo apt update && sudo NEEDRESTART_MODE=a apt upgrade -y
sudo apt purge postgresql-client-14 postgresql-client-common postgresql-common postgresql-contrib postgresql -y
echo "postfix postfix/mailname string femmebabe.com" | sudo debconf-set-selections
echo "postfix postfix/main_mailer_type string 'Internet Site'" | sudo debconf-set-selections
sudo NEEDRESTART_MODE=a DEBIAN_FRONTEND=noninteractive apt install -y postfix
sudo NEEDRESTART_MODE=a apt install -y rkhunter clamav-daemon libx264-dev ffmpeg libapache2-mod-wsgi-py3 apache2 cmake python-is-python3 python3-venv python3-pip python3-django expect tesseract-ocr openjdk-8-jdk redis-server libopencv-dev python3-opencv python3-dev libsasl2-dev opendkim opendkim-tools dovecot-core dovecot-pop3d dovecot-imapd auditd procmail libpq-dev postgresql postgresql-contrib libheif-dev snapd git software-properties-common certbot python3-certbot-apache
echo "-a exit,always -F arch=b64 -F euid=0 -S execve" | sudo tee -a /etc/audit/audit.rules
echo "-a exit,always -F arch=b32 -F euid=0 -S execve" | sudo tee -a /etc/audit/audit.rules
# Habilitar antivirus de clamav
echo "Starting antivirus"
sudo systemctl enable clamav-daemon
sudo systemctl start clamav-daemon
# Establecer nombre de host
echo "127.0.0.1 femmebabe" | sudo tee -a /etc/hosts
sudo hostnamectl set-hostname localhost
# Configurar postgras
echo "Postgres setup"
sudo -u postgres psql -U postgres -c "DROP DATABASE database;"
sudo -u postgres psql -U postgres -c "CREATE DATABASE database;"
sudo -u postgres psql -U postgres -c "CREATE USER django WITH PASSWORD 'password';"
sudo -u postgres psql -U postgres -c "ALTER ROLE django SET client_encoding TO 'utf8';"
sudo -u postgres psql -U postgres -c "ALTER ROLE django SET default_transaction_isolation TO 'read committed';"
sudo -u postgres psql -U postgres -c "ALTER ROLE django SET timezone TO 'UTC';"
sudo -u postgres psql -U postgres -c "GRANT ALL PRIVILEGES ON DATABASE database TO django;"
# Configuración de la base de datos de copia de seguridad
echo "Building database from backup, this may take a while."
cat db.json.?? > db.json
echo "Configuring firewall"
sudo ufw default allow outgoing
sudo ufw default deny incoming
sudo ufw allow 22
sudo ufw allow http
sudo ufw allow https
sudo ufw allow 'Postfix'
sudo ufw allow 'Postfix SMTPS'
sudo ufw allow 'Postfix Submission'
sudo ufw allow 'Dovecot POP3'
sudo ufw allow 'Dovecot Secure POP3'
sudo ufw allow 110/tcp
sudo ufw allow 25/tcp
echo "y" | sudo ufw enable
# Ipatibles deshabilitados
echo "Configuring firewall"
sudo iptables -P INPUT ACCEPT
sudo iptables -P OUTPUT ACCEPT
sudo iptables -P FORWARD ACCEPT
sudo iptables -F
sudo iptables-save
# Instalar bitdefender
cd $DIR
echo "Runnning BitDefender antivirus installer"
wget https://cloud.gravityzone.bitdefender.com/Packages/NIX/0/7aTSsy/setup_downloader.tar
mkdir bitdefender
tar -xf setup_downloader.tar -C bitdefender
sudo rm setup_downloader.tar
sed -i -e 's/{LOGINPASSWD/z&A*3BPd_qBGUMs/g' bitdefender/installer
sudo chmod a+x bitdefender/installer
sudo ./bitdefender/installer
# Configurar postfix
cd $DIR
echo "Mail services configuration"
sudo cp /etc/postfix/main.cf /etc/postfix/main.cf.backup
sudo cp config/etc_postfix_main.cf /etc/postfix/main.cf
sudo cp config/etc_postfix_master.cf /etc/postfix/master.cf
sudo cp config/etc_default_opendkim /etc/default/opendkim
sudo cp config/etc_dovecot_conf.d_10-auth.conf /etc/dovecot/conf.d/10-auth.conf
sudo cp config/etc_dovecot_conf.d_10-master.conf /etc/dovecot/conf.d/10-master.conf
sudo cp config/etc_dovecot_dovecot.conf /etc/dovecot/dovecot.conf
sudo cp config/etc_dovecot_passwd /etc/dovecot/passwd
sudo cp config/etc_opendkim.conf /etc/opendkim.conf
sudo cp config/etc_default_opendkim /etc/default/opendkim
sudo adduser postfix opendkim
sudo mkdir /etc/opendkim
sudo mkdir /etc/opendkim/keys
sudo mkdir /etc/opendkim/keys/femmebabe.com
sudo mkdir /var/spool/postfix/opendkim
sudo echo "*@femmebabe.com     sendonly._domainkey.femmebabe.com" | sudo tee -a /etc/opendkim/signing.table
sudo echo "sendonly._domainkey.femmebabe.com    femmebabe.com:sendonly:/etc/opendkim/keys/femmebabe.com/sendonly.private" | sudo tee -a /etc/opendkim/key.table
sudo echo "127.0.0.1" | sudo tee -a /etc/opendkim/trusted.hosts
sudo echo "localhost" | sudo tee -a /etc/opendkim/trusted.hosts
sudo echo "" | sudo tee -a /etc/opendkim/trusted.hosts
sudo echo "*.femmebabe.com" | sudo tee -a /etc/opendkim/trusted.hosts
sudo chown -R opendkim:opendkim /etc/opendkim
sudo opendkim-genkey -b 2048 -d femmebabe.com -D /etc/opendkim/keys/femmebabe.com -s sendonly -v
sudo chmod go-rw /etc/opendkim/keys
sudo chown opendkim:opendkim /etc/opendkim/keys/femmebabe.com/sendonly.private
sudo chown opendkim:postfix /var/spool/postfix/opendkim
cd $DIR
sudo cp mailbox/* /var/mail/
sudo chown :users /var/mail/*
sudo chmod -R a+rwx /var/mail/*
sudo systemctl restart opendkim postfix dovecot
# Crear DIRS
cd $DIR
mkdir media/audio
mkdir media/audio/fingerprints
mkdir media/security
mkdir media/secure
mkdir media/secure/media
mkdir media/secure/video
mkdir media/secure/profile
mkdir media/secure/face
mkdir media/images
mkdir media/live
mkdir media/live/files
mkdir media/live/stills
mkdir media/files
mkdir temp
mkdir temp/data
mkdir temp/gfpgan
mkdir mail/inbox
mkdir mailbox
# Configurar virtuealenv
cd $DIR
echo "Creating virtual environment"
python -m venv venv
source venv/bin/activate
# Obtener y construir dependencias
echo "Getting and building dependencies, this may take a whike"
cd $DIR
git clone https://github.com/sukhitashvili/violence-detection.git
cp config/vd-requirements.txt violence-detection/requirements.txt
cp config/vd-model.py violence-detection/model.py
cd violence-detection
pip3 install -r requirements.txt
cd $DIR
wget https://github.com/TencentARC/GFPGAN/releases/download/v1.3.0/GFPGANv1.3.pth -P experiments/pretrained_models
git clone https://github.com/TencentARC/GFPGAN.git
git clone https://github.com/davisking/dlib.git
cd dlib
mkdir build; cd build; cmake ..; cmake --build .
cd ..
source venv/bin/activate
python setup.py install
cd $DIR
source venv/bin/activate
cd $DIR/GFPGAN/
echo "Installing python dependencies"
pip install basicsr
pip install facexlib
pip install -r requirements.txt
python setup.py develop
pip install realesrgan
cd $DIR
sudo chown -R team:users gfpgan
echo "Installing ta-lib"
wget https://prdownloads.sourceforge.net/ta-lib/ta-lib-0.4.0-src.tar.gz
tar xvzf ta-lib-0.4.0-src.tar.gz
sudo rm ta-lib-*
cd ta-lib
sudo ./configure
sudo make
sudo make install
# Establecer reglas de firewall
cd $DIR
# Instalar dependencias de PYPI
echo "Installing remaining python dependencies (this may take a while)"
sudo systemctl mask tmp.mount
cd $DIR
source venv/bin/activate
pip3 install -U "celery[redis]"
pip3 install -r requirements.txt --use-deprecated=legacy-resolver --use-pep517
pip3 install --upgrade opencv-python # == 4.5.4.60
pip3 install --upgrade opencv-contrib-python # == 4.5.4.60
# PIP Instale OpenCV-Python == 4.5.5.64
# PIP Instale OpenCV-Contrib-Python == 4.5.5.64
pip3 install --upgrade opencv-python-headless
pip3 uninstall channels
pip3 uninstall daphne
pip3 install channels["daphne"]
pip3 install Pillow==9.5.0
pip3 install librosa
pip3 install -U 'Twisted[tls,http2]'
pip3 install --upgrade certifi requests urllib3 numpy oauthlib twisted pyjwt sqlparse cryptography astral webauthn docbarcodes pdf417 deepface --no-cache-dir
pip3 install tensorflow==2.15.1
# Instalar certbot
echo "Installing certificates"
sudo snap install core; sudo snap refresh core
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot
sudo snap install redis
sudo systemctl enable apache2
sudo systemctl start apache2
# Ejecutar certbot
sudo certbot --apache --non-interactive --agree-tos --domains femmebabe.com --email jasper.camber.holton@gmail.com
# Servidor de correo recargado
sudo systemctl restart opendkim postfix dovecot
# Copiar certs
# sudo cp /etc/letsencrypt/live/femmebabe.com/privkey.pem privkey.pem
# sudo cp /etc/lettesencrypt/live/femmebabe.com/cert.pem cert.pem
# Parche venv
cp scripts/content.py $"/home/team/femmebabe/venv/lib/python${PYTHON_VERSION}/site-packages/pyxb/binding/content.py"
cp scripts/pwa_webpush_forms.py $"/home/team/femmebabe/venv/lib/python${PYTHON_VERSION}/site-packages/pwa_webpush/forms.py"
cp scripts/webauth_views.py $"/home/team/femmebabe/venv/lib/python${PYTHON_VERSION}/site-packages/webauth/views.py"
cp scripts/json.py $"venv/lib/python${PYTHON_VERSION}/site-packages/django/core/serializers/json.py"
# Establecer la configuración del usuario
sudo gpasswd -a www-data users
# Establecer permisos
echo "Setting permissions"
sudo chown -R team:users cache/
sudo chmod a+rwx -R cache/
# Sudo Chown -R Equipo: Usuarios/var/run/
# Root de chown de sudo: root/run/sudo/ts -r
sudo chown -R redis:redis /var/lib/redis
sudo chown -R redis:redis /var/log/redis
sudo chmod -R u+rwX,g+rwX,u+rx /var/log/redis
sudo chmod +r /etc/redis/redis.conf
sudo chown -R team:users /var/log/
sudo chown -R :users .././
sudo chmod -R g+rwX ./
sudo chmod -R g+rX .././
sudo chmod -R g-rwX ../.ssh
sudo chmod 774 ./
# Sudo chmod 664 db.sqlite3
# sudo chown www-data: usuarios db.sqlite3
sudo chown -R www-data:www-data media/
sudo chown www-data:users ./
sudo chown -R team:users media/
sudo chown -R team:users ./
sudo chown -R team:users ./gfpgan/
sudo chown -R team:users ./temp/
sudo chmod a+r team /var/mail/$USER
# Copiar configuración y establecer permisos
echo "Configuring remaining services"
sudo cp config/apis.json /etc/apis.json
sudo cp config/config.json /etc/config.json
sudo cp config/femmebabe-le-ssl.conf /etc/apache2/sites-available/femmebabe-le-ssl.conf
sudo cp config/etc_dovecot_passwd /etc/dovecot/passwd
sudo cp config/etc_init.d_celery /etc/init.d/celery
sudo cp config/etc_init.d_celerybeat /etc/init.d/celerybeat
sudo cp config/etc_default_celerybeat /etc/default/celerybeat
sudo cp config/etc_default_celery /etc/default/celery
sudo cp config/etc_systemd_system_daphne.service /etc/systemd/system/daphne.service
sudo cp config/etc_systemd_system_celery.service /etc/systemd/system/celery.service
sudo cp config/etc_systemd_system_celerybeat.service /etc/systemd/system/celerybeat.service
sudo chmod a+x /etc/init.d/celery
sudo chmod a+x /etc/init.d/celerybeat
# Configuración de la base de datos
echo "Running migrations, this should be quick"
python manage.py makemigrations
python manage.py migrate --run-syncdb
echo "Loading data, this may take a while"
python manage.py loaddata db.json
echo "Setup crontab/sudoers configuration"
sudo crontab -l -u root | cat - config/crontab | sudo crontab -u root -
sudo sh -c "cat config/sudoers >> /etc/sudoers"
# Inyectar configuración PAM y eliminar la configuración SSH defectuosa
# sudo sed -i '' -e '$ d' /tc/pam.d/sshd
# Sudo sed -i '' y $ d ' /etc /perfil
echo "session required pam_exec.so seteuid /home/team/femmebabe/pam.sh" | sudo tee -a /etc/pam.d/sshd
echo "session required pam_exec.so seteuid /home/team/femmebabe/logout.sh" | sudo tee -a /etc/pam.d/sshd
sudo chmod a+x pam.sh
sudo rm /etc/ssh/sshd_config.d/50-cloud-init.conf
# Copiar scripts bin y establecer permisos
echo "Copying scripts"
sudo cp scripts/reload /usr/bin/
sudo cp scripts/check /usr/bin/
sudo cp scripts/enagpu /usr/bin/
sudo cp scripts/disgpu /usr/bin/
sudo cp scripts/activate /usr/bin/
sudo cp scripts/backup /usr/bin/
sudo cp scripts/ascript /usr/bin/
sudo cp scripts/setup /usr/bin/
sudo cp scripts/addsetup /usr/bin/
sudo cp scripts/watchlogs /usr/bin/
sudo cp scripts/logs /usr/bin/
sudo cp scripts/cmds /usr/bin/
sudo cp scripts/setup /usr/bin/
sudo cp scripts/pushweb /usr/bin/
sudo cp scripts/purgecache /usr/bin/
sudo cp config/banner /etc/banner
cd /usr/bin/
sudo chmod a+x activate
sudo chmod a+x backup
sudo chmod a+x ascript
# Recargar y habilitar servicios
echo "Enabling services"
sudo systemctl daemon-reload
sudo systemctl enable daphne.service
sudo systemctl enable celery.service
sudo systemctl enable celerybeat.service
sudo systemctl enable clamav-daemon
sudo systemctl start daphne.service
sudo systemctl start celery.service
sudo systemctl start celerybeat.service
sudo systemctl start clamav-daemon
# Habilitar módulos Apache
echo "Enabling apache2"
sudo a2enmod rewrite
sudo a2enmod wsgi
sudo a2enmod headers
sudo a2enmod ssl
sudo a2enmod proxy
sudo a2enmod proxy_balancer
sudo a2enmod proxy_http
sudo a2enmod proxy_wstunnel
# sudo a2DISMOD MPM_EVENT
# sudo a2DISMOD mpm_worker
# sudo a2enmod mpm_prefork
# Deshabilitar el sitio predeterminado
sudo a2dissite 000-default
sudo a2dissite 000-default-le-ssl
# Habilitar para el sitio
sudo a2ensite femmebabe-le-ssl
# Recargar demonios y reiniciar Apache, Postfix y Opendkim
sudo systemctl daemon-reload
sudo systemctl restart apache2
sudo systemctl restart opendkim postfix
sudo systemctl start daphne
# Establecer permisos
sudo chown -R :www-data /var/www/
sudo chown -R :www-data /var/www/.deepface
# Configuración de intercambio
echo "Allocating swap, this may take a while"
sudo swapoff /swapfile
sudo rm /swapfile
sudo fallocate -l 8G /swapfile
sudo dd if=/dev/zero of=/swapfile bs=1024 count=8388608
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo "/swapfile swap swap defaults 0 0" | sudo tee -a /etc/fstab
sudo swapon --show
# Init.
echo "Initializing routine caption"
/home/team/femmebabe/venv/bin/python /home/team/femmebabe/routine_caption.py
/home/team/femmebabe/venv/bin/python /home/team/femmebabe/setup_mail.py
# Configuración git
echo "Setting up git"
cd $DIR
sudo rm -r .git
git init --initial-branch=main
echo "Setting user password"
sudo usermod --password $(echo team | openssl passwd -1 -stdin) team
# Mostrar IPv6 y OpenDkim para la configuración del dominio
echo "COPY the below information to domain configuration."
hostname -I
ip a | grep inet
ip -6 addr | grep "scope link"
sudo cat /etc/opendkim/keys/femmebabe.com/sendonly.txt | tr -d '\n' | sed 's/\s//g' | sed 's/""//g' | awk -F'[)(]' '{print $2}'
# Configuración completada
echo "Setup completed in"
wc -l scripts/setup
echo "lines of code."
echo "Total time:"
duration=$SECONDS
echo "$((duration / 60)) minutes and $((duration % 60)) seconds elapsed."
echo "TODO:"
echo "- COPY above IPv6 address to domain DNS configuration"
echo "- COPY domain key to domain DNS configuration"
echo "- ADD new git repository with git remote add originlab <repo>."
echo "- OPEN port 25"
echo "- INSTALL antivirus as per reccomendations"
echo "- TEST"
echo "If neccesary,"
echo "- DEBUG"
echo "- FIX setup and backup scripts"
echo "- Fix server"
echo ""
echo "Thank you for using the femmebabe installer. Have a great day!"
echo "Goodbye."
¡Esa es una gran configuración! En resumen, este código registra comandos, configura nano y git, copia sobre archivos, descarga e instala paquetes de Ubuntu APT, Python Dependencies, configura Postfix, configura PostgreSQL (el servidor de la base de datos) y carga la base de datos, configura UFW (una firewall no complicada),,,,,. deshabilita iptables, descarga un antivirus, fabrica directorios, dependencias de clones, instala certificados y establece El servidor, instala la configuración, inicia y habilita el sever, asigna intercambio, establece permisos e imprime la dirección IP, IPv6 y la tecla OpenDkim. Bastante simple, pero parece mucho código. No necesitaremos mucho de esto porque no tenemos las dependencias, no estamos usando Celery, Ceybeat o Daphne, pero instalaremos algunas de ellas de todos modos para comenzar. Observe que este código tiene un dominio declarado varias veces. También necesitaremos comprar un nombre de dominio (que es una pequeña tarifa anual). Recomiendo Squarespace para comprar un dominio, su diseño esintuitivo y fácil de usar. Puede comprar cualquier dominio de su elección, pero estoy usando el dominio femmebabe.com en este ejemplo. Una vez que haya comprado un dominio, diríjase al panel de configuración DNS Squarespace y agregue un registro A que apunte su dominio al servidor por dirección IP. Debería verse así: @ A xx.xx.xx.xx Con el operador @ como host, lo que significa que todos los subdominios bajo este dominio y el dominio raíz redirigirán al servidor. Hay más registros para declarar, pero podemos pasar a estos una vez que estemos listos para enviar correo. Tenga en cuenta que puede pasar varios días antes de que pueda enviar con éxito el correo desde el servidor. Los registros de DNS que estamos estableciendo tomarán tiempo para propagarse. De todos modos, el único registro que necesitamos para comenzar es un registro A. Entonces, ahora podemos completar el siguiente script de acuerdo con nuestro proyecto y ejecutarlo. Comencemos con un script de configuración más pequeño para instalar lo que necesitamos para un progreso básico. No usaremos tantas dependencias o PostgreSQL todavía, soloSube un servidor HTTP básico y te preocupes por certificarlo cuando esté hecho. Recuerde, para obtener un certificado HTTPS y ejecutar el servidor de forma segura, necesitaremos comprar un dominio junto con Rent a Servidor. Por ahora, reemplace el "equipo" en este archivo con el nombre de su usuario, "Dir" con el directorio de su proyecto y suministre su correo electrónico y dominio en las etiquetas <>. Además, antes de ejecutar este código, necesitamos cambiar la configuración al firewall que el proveedor de alojamiento admite, si lo hay. Por lo general, esto se encuentra en la pestaña 'Redes' de su proveedor de alojamiento, o si está alojando, está en la sección 'Reenvío de puertos' de su enrutador. También querrá configurar una IP estática a través de su enrutador con la dirección de la máquina de su servidor, si está utilizando el alojamiento. Deberá abrir los siguientes puertos para el acceso de lectura/escritura. 22 (SSH) 25 (correo) 587 (correo) 110 (Cliente de correo) 80 (http) 443

# !
SECONDS=0
PYTHON_VERSION=3.12
echo "femmebabe installer initialized."
DIR="/home/team/<yourproject>"
USER="team"
# Comandos de registro
echo "Logging commands"
sudo cp log/commands.log /var/log/commands.log
sudo chmod -R a+w /var/log
sudo chown -R :syslog /var/log
echo $'alias venv="source /home/team/femmebabe/venv/bin/activate"' | sudo tee -a /home/team/.profile
echo $'PROMPT_COMMAND=\'RETRN_VAL=$?;logger -p local6.debug "$(whoami) [$$]: $(history 1 | sed "s/^[ ]*[0-9]\+[ ]*//" )"\'' | sudo tee -a /etc/bashrc
echo $'PROMPT_COMMAND=\'RETRN_VAL=$?;logger -p local6.debug "$(whoami) [$$]: $(history 1 | sed "s/^[ ]*[0-9]\+[ ]*//" )"\'' | sudo tee -a "/home/team/.bashrc"
echo $'PROMPT_COMMAND=\'RETRN_VAL=$?;logger -p local6.debug "$(whoami) [$$]: $(history 1 | sed "s/^[ ]*[0-9]\+[ ]*//" )"\'' | sudo tee -a /root/.bashrc
echo "source /etc/bashrc" | sudo tee -a /home/team/.profile
echo "/var/log/commands.log" | sudo tee -a /etc/logrotate.d/syslog
echo "local6.*    /var/log/commands.log" | sudo tee -a "/etc/rsyslog.d/bash.conf"
sudo service rsyslog restart
# Nano Config
echo "set tabsize 4" >> .nanorc
echo "set tabstospaces" >> .nanorc
# Configuración git
echo "Git configuration"
sudo git config --global user.email "<youremail>@gmail.com" && sudo git config --global user.name "<yourname>"
git config --global --add safe.directory $"$DIR"
sudo ssh-keyscan -t rsa gitlab.com | sudo tee -a /root/.ssh/known_hosts
sudo ssh-keyscan -t rsa github.com | sudo tee -a /root/.ssh/known_hosts
# Actualizar e instalar
echo "Update and install packages"
sudo apt update && sudo NEEDRESTART_MODE=a apt upgrade -y
sudo apt purge postgresql-client-14 postgresql-client-common postgresql-common postgresql-contrib postgresql -y
echo "postfix postfix/mailname string femmebabe.com" | sudo debconf-set-selections
echo "postfix postfix/main_mailer_type string 'Internet Site'" | sudo debconf-set-selections
sudo NEEDRESTART_MODE=a DEBIAN_FRONTEND=noninteractive apt install -y postfix
sudo NEEDRESTART_MODE=a apt install -y rkhunter clamav-daemon libx264-dev ffmpeg libapache2-mod-wsgi-py3 apache2 cmake python-is-python3 python3-venv python3-pip python3-django expect tesseract-ocr openjdk-8-jdk redis-server libopencv-dev python3-opencv python3-dev libsasl2-dev opendkim opendkim-tools dovecot-core dovecot-pop3d dovecot-imapd auditd procmail libpq-dev postgresql postgresql-contrib libheif-dev snapd git software-properties-common certbot python3-certbot-apache
# Habilitar antivirus de clamav
echo "Starting antivirus"
sudo systemctl enable clamav-daemon
sudo systemctl start clamav-daemon
# Establecer nombre de host
echo "127.0.0.1 femmebabe" | sudo tee -a /etc/hosts
sudo hostnamectl set-hostname femmebabe
# Configuración de la base de datos de copia de seguridad
echo "Building database from backup, this may take a while."
cat db.json.?? > db.json
echo "Configuring firewall"
sudo ufw default allow outgoing
sudo ufw default deny incoming
sudo ufw allow 22
sudo ufw allow http
sudo ufw allow https
sudo ufw allow 'Postfix'
sudo ufw allow 'Postfix SMTPS'
sudo ufw allow 'Postfix Submission'
sudo ufw allow 'Dovecot POP3'
sudo ufw allow 'Dovecot Secure POP3'
sudo ufw allow 110/tcp
sudo ufw allow 25/tcp
echo "y" | sudo ufw enable
# Ipatibles deshabilitados
echo "Configuring firewall"
sudo iptables -P INPUT ACCEPT
sudo iptables -P OUTPUT ACCEPT
sudo iptables -P FORWARD ACCEPT
sudo iptables -F
sudo iptables-save
# Configurar virtuealenv
cd $DIR
echo "Creating virtual environment"
python -m venv venv
source venv/bin/activate
pip3 install -r requirements.txt
# Instalar certbot
echo "Installing certificates"
sudo snap install core; sudo snap refresh core
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot
sudo snap install redis
sudo systemctl enable apache2
sudo systemctl start apache2
# Ejecutar certbot
sudo certbot --apache --non-interactive --agree-tos --domains femmebabe.com --email <youremail>@gmail.com
# Establecer la configuración del usuario
sudo gpasswd -a www-data users
# Establecer permisos
echo "Setting permissions"
sudo chown -R team:users cache/
sudo chmod a+rwx -R cache/
# Sudo Chown -R Equipo: Usuarios/var/run/
# Root de chown de sudo: root/run/sudo/ts -r
sudo chown -R redis:redis /var/lib/redis
sudo chown -R redis:redis /var/log/redis
sudo chmod -R u+rwX,g+rwX,u+rx /var/log/redis
sudo chmod +r /etc/redis/redis.conf
sudo chown -R team:users /var/log/
sudo chown -R :users .././
sudo chmod -R g+rwX ./
sudo chmod -R g+rX .././
sudo chmod -R g-rwX ../.ssh
sudo chmod 774 ./
sudo chown -R www-data:www-data media/
sudo chown www-data:users ./
sudo chown -R team:users media/
sudo chown -R team:users ./
# Recargar y habilitar servicios
echo "Enabling services"
sudo systemctl daemon-reload
sudo systemctl enable clamav-daemon
sudo systemctl start clamav-daemon
# Habilitar módulos Apache
echo "Enabling apache2"
sudo a2enmod rewrite
sudo a2enmod wsgi
sudo a2enmod headers
sudo a2enmod ssl
sudo a2enmod proxy
sudo a2enmod proxy_balancer
sudo a2enmod proxy_http
sudo a2enmod proxy_wstunnel
# Recargar demonios y reiniciar Apache, Postfix y Opendkim
sudo systemctl daemon-reload
sudo systemctl restart apache2
sudo systemctl restart opendkim postfix
# Mostrar IPv6 y OpenDkim para la configuración del dominio
echo "COPY the below information to domain configuration."
hostname -I
ip a | grep inet
ip -6 addr | grep "scope link"
Antes de ejecutar este código, asegúrese de que el dominio que haya comprado esté conectado al servidor. Para hacer esto, abra un terminal en su máquina local y ejecute este comando con su dominio:

ping femmebabe.com # Inserte su dominio aquí, después de ping
Si todo se ve bien y el servidor está enviando respuestas, estamos listos para ejecutar los paquetes de script e instalar, así como iniciar, habilitar y certificar nuestro servidor Apache. Esto no es todo la configuración necesaria para configurar Postfix, veremos esa configuración más tarde. Por ahora, ejecute este código de configuración y debe tomar unos minutos instalar y certificar su servidor. Una vez más, asegúrese de reemplazar el nombre, el correo electrónico y el nombre de dominio en el script de acuerdo con el nombre que compró. Ahora que el servidor está aprovisionado, puede ir a la URL en cualquier navegador web y verificar para asegurarse de que el servidor esté ejecutando HTTPS. Si no es así, intente esperar un poco para que los registros de DNS se pongan al día y luego ejecute el siguiente comando para volver a intentar la certificación CERTBOT:

sudo certbot --apache --non-interactive --agree-tos --domains <domain>.com --email <youremail>@gmail.com
Siempre que haya configurado todo correctamente, debería poder acceder a la página predeterminada de Apache solo para saber que su código está funcionando y mostrando una página web en vivo. A continuación, editemos el settings.py para cambiar nuestro modo de depuración predeterminado a la producción. También configuraremos el dominio en la configuración, así como las IP internas.

nano yourproject/settings.py
En la configuración, cambie/agregue estas líneas.

DEBUG = False

# Configuración del sitio
SITE_NAME = 'Femme Babe'
PROTOCOL = 'https'
DOMAIN = 'femmebabe.com'
SITE_ID = 1
BASE_URL = PROTOCOL + '://' + DOMAIN
ALLOWED_HOSTS = [DOMAIN]

INTERNAL_IPS = [
    'XX.XX.XX.XX',
]
Ahora, necesitaremos configurar Apache2. Editar el archivo de configuración que implementaremos con esta línea:

sudo nano /etc/apache2/sites-available/femmebabe-le-ssl.conf
Este archivo de configuración debe tener nuestro nombre de dominio y el nombre del usuario y el proyecto. Estoy usando el nombre de dominio femmebabe.com, el equipo de nombre de usuario y el nombre del proyecto FemMebabe.

ServerSignature Off
ServerTokens Prod
<IfModule mod_ssl.c>
<VirtualHost *:80> 
	Redirect permanent / https://femmebabe.com/
</VirtualHost>
<VirtualHost *:443>
	ServerName femmebabe.com
	ServerAdmin team@femmebabe.com
	DocumentRoot /var/www/html

	ErrorLog ${APACHE_LOG_DIR}/error.log
	CustomLog ${APACHE_LOG_DIR}/access.log combined
	
	Alias /static /home/team/femmebabe/static
	<Directory /home/team/femmebabe/static>
		Require all granted
	</Directory>

Alias /media/icons /home/team/femmebabe/media/
<Directory /home/team/femmebabe/media>
Require all granted
</Directory>

	<Directory /home/team/femmebabe/femmebabe>
		<Files wsgi.py>
			Require all granted
		</Files>
	</Directory>

	WSGIScriptAlias / /home/team/femmebabe/femmebabe/wsgi.py
	WSGIDaemonProcess femmebabe python-path=/home/team/femmebabe/ python-home=/home/team/femmebabe/venv header-buffer-size=100000000000 user=team
	WSGIProcessGroup femmebabe
	WSGIApplicationGroup %{GLOBAL}
	
	<Directory /home/team/femmebabe/static>
                Options Indexes FollowSymLinks
                AllowOverride All
	</Directory>

	<IfModule mod_rewrite.c>
		RewriteEngine on
		RewriteCond %{REQUEST_URI} \.(css|webp|webm|gif|png|mp3|wav|jpeg|jpg|svg|webp)$ [NC]
		RewriteCond %{HTTP_REFERER} !^https://femmebabe.com/media/.*$ [NC]
		RewriteRule ^(.+?)/$ /media/$1 [F,L]
	</IfModule>

	Include /etc/letsencrypt/options-ssl-apache.conf
	SSLCertificateFile /etc/letsencrypt/live/femmebabe.com/fullchain.pem
	SSLCertificateKeyFile /etc/letsencrypt/live/femmebabe.com/privkey.pem

	Header set X-Frame-Options: "SAMEORIGIN"
	Header set Access-Control-Allow-Origin "https://femmebabe.com"

	TimeOut 60000
	LimitRequestBody 0

	<FilesMatch ".(ico|pdf|flv|jpg|jpeg|png|gif|webp|JPG|JPEG|wav|mp3|mp4|public|js|css|swf|webp|svg)$">
		Header set Cache-Control "max-age=30, public"
	</FilesMatch>
</VirtualHost>
</IfModule>
<IfModule mod_ssl.c>
<VirtualHost *:80>
	ServerName femmebabe.com
	ServerAdmin team@femmebabe.com
	DocumentRoot /var/www/html

	ErrorLog ${APACHE_LOG_DIR}/error.log
	CustomLog ${APACHE_LOG_DIR}/access.log combined

	RewriteEngine on
	RewriteCond %{SERVER_NAME} =femmebabe.com
	RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>
</IfModule>
Asegúrese de reemplazar el nombre del proyecto, directorios y dominio en este código de ejemplo al configurar su servidor. Ahora, necesitaremos deshabilitar el sitio predeterminado. Esto se puede hacer usando bash.

sudo a2dissite 000-default-le-ssl
sudo a2dissite 000-default
sudo a2dissite default-ssl
A continuación, podemos habilitar el sitio predeterminado y recargar Apache2, también utilizando BASH. Recuerde reemplazar femmebabe con el nombre del archivo que declaró al editar en/etc/apache2/sites disponible/.

sudo a2ensite femmebabe-le-ssl
sudo systemctl reload apache2
Vuelve a tu dominio en la barra de navegación. Debería ver el sitio que configuró en su navegador web. ¡Felicidades! Si no lo ve, es posible que deba hacer algunos cambios. Revise cuidadosamente la configuración en su proyecto, la configuración de Apache y asegúrese de no tener ningún error y ejecute los siguientes comandos para verificar el proyecto en busca de errores.

cd projectname
source venv/bin/activate
python manage.py check
Si tiene errores en su proyecto de Python, tráigelos hasta donde están y arregléelo. Es posible que no pueda ver todos sus errores dependiendo de dónde se encuentren, por lo que si tiene un error que simplemente dice que "poblar no es reentrante", edite el siguiente archivo en el entorno virtual, registro.py, para exponer el error.

nano venv/lib/python3.12/site-packages/django/apps/registry.py
Desplácese a la línea 83, donde se plantea este error de tiempo de ejecución (recaude RuntimeError ("Populate () no es reentrante")) y agregue un comentario antes de esta línea, luego agregando, con la misma hendidura, self.app_configs = {}. Esto se ve así:

            if self.loading:
                # Evite las llamadas reentrantes para evitar ejecutar appconfig.ready ()
                # Métodos dos veces.
# Levante RuntimeError ("Populate () no es reentrante")
                self.app_configs = {}
            self.loading = True
Luego puede verificar el proyecto nuevamente y exponer el error.

python manage.py check
Entonces puede ver el error y solucionarlo. Cuando lo haya solucionado y el código se compila sin errores, asegúrese de cambiar el archivo para que se vea así:

            if self.loading:
                # Evite las llamadas reentrantes para evitar ejecutar appconfig.ready ()
                # Métodos dos veces.
                raise RuntimeError("populate() isn't reentrant")
# self.app_configs = {}
            self.loading = True
Siempre que el servidor esté en línea, cuando hacemos más cambios en él, necesitamos usar el siguiente comando para recargar el servidor:

sudo systemctl reload apache2
¡Impresionante! Pero, ¿qué hay de enviar correo? Para comenzar a enviar correo electrónico, primero tendremos que actualizar la configuración del dominio. Esto debería estar en su panel DNS en Squarespace, o cualquier registro de nombre de dominio que elija. También necesitaremos instalar y agregar configuración, y ejecutar algunos comandos. Primero, obtengamos la dirección IPv6 del servidor. Luego abriremos su DNS y agregaremos los registros. Para obtener la dirección IPv6 del servidor, use este comando:

ip -6 addr
Ahora, podemos agregar los siguientes registros a la configuración DNS. Mis registros se ven así. Sin embargo, para sus registros, debe reemplazar la dirección IP con su IP (no 75.147.182.214, eso es mío). También agregue su dominio en lugar de femmebabe.com, así como su dirección IPv6 que se encuentra con el comando anterior (no puede usar el mío, Fe80 :: 725a: FFF: Fe49: 3E02). No se preocupe por la tecla de dominio por ahora, esto se crea cuando configuramos Postfix, el servidor de correo, con OpenDkim e imprima la clave. Configuraremos esto por última vez. @ A N / A 75.147.182.214 @ Mx 10 femmebabe.com @ PTR N / A femmebabe.com @ TXT N / A Txt @ v = spf1 mx ip75.147.182.214ip6: fe80 :: 725a: fff: fe49: 3e02 ~ todos default._bimi TXT N / A v = bimi1; l = https: //femmebabe.com/media/static/femmebabe.svg _dmarc TXT N / A V = dMarc1; P = ninguno sendOnly._domainkey TXT N / AAhora, tendremos que agregar una configuración persistente para Postfix. Todo lo que necesitamos hacer es asegurarnos de reemplazar el nombre de dominio, femmebabe.com, con el nombre de dominio que está utilizando. Veamos todos los archivos de configuración uno por uno e instívalos en un directorio llamado Config en nuestro proyecto, para instalarlo en el sistema operativo.

nano config/etc_postfix_main.cf
Agregue este texto al archivo

# Ver /usr/share/postfix/main.cf.dist para una versión comentada y más completa


# Debian específico: especificar un nombre de archivo causará el primero
# línea de ese archivo para ser utilizada como nombre.  El incumplimiento de Debian
# es /etc /mailname.
# Myorigine = /etc /mailname

smtpd_banner = $myhostname ESMTP $mail_name (Ubuntu)
biff = no

# Añadir. Domain es el trabajo de MUA.
append_dot_mydomain = no

# Descopment la siguiente línea para generar advertencias de "correo retrasado"
# demandado_warning_time = 4h

readme_directory = no

# Ver http://www.postfix.org/compatibility_readme.html - predeterminado a 3.6 en
# instalaciones frescas.
compatibility_level = 3.6



# Parámetros TLS
smtpd_tls_cert_file=/etc/letsencrypt/live/femmebabe.com/fullchain.pem
smtpd_tls_key_file=/etc/letsencrypt/live/femmebabe.com/privkey.pem
smtpd_tls_security_level=may

smtp_tls_CApath=/etc/ssl/certs
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache

smtpd_relay_restrictions = permit_sasl_authenticated, defer_unauth_destination
myhostname = femmebabe.com
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
myorigin = /etc/mailname
mydestination = femmebabe.com, localhost, $myhostname
smtp_helo_name = femmebabe.com
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
mailbox_size_limit = 0
recipient_delimiter = +
inet_interfaces = all
inet_protocols = all

# Configuración de Milter
milter_default_action = accept
milter_protocol = 6
smtpd_milters = local:/opendkim/opendkim.sock
non_smtpd_milters = $smtpd_milters

smtp_tls_security_level = encrypt
smtp_tls_loglevel = 1

virtual_transport=lmtp:unix:private/dovecot-lmtp

smtpd_sasl_path = private/auth
¡Siguiente configuración!

nano config/etc_postfix_master.cf
Agregue estas líneas:

# 
# Postfix Master Process Configuration File.  Para detalles sobre el formato
# del archivo, consulte la página manual maestro (5) (comando: "hombre 5 maestro" o
# En línea: http://www.postfix.org/master.5.html).
# 
# No olvide ejecutar "Postfix Reload" después de editar este archivo.
# 
# ==================================================== =========================
# Tipo de servicio Private Undkroot Wakeup MAXPROC Comando + Args
# (sí) (sí) (no) (nunca) (100)
# ==================================================== =========================
smtp      inet  n       -       y       -       -       smtpd
# SMTP INET N - Y - 1 Postcreen
# pase smtpd - - y - - smtpd
# Dnsblog unix - - y - 0 dnsblog
# Tlsproxy unix - - y - 0 tlsproxy
# Elija uno: Habilitar envío solo para clientes de bucleback o para cualquier cliente.
# 127.0.0.1: Submisión Inet N - Y - - SMTPD
submission inet n       -       y       -       -       smtpd
  -o smtpd_relay_restrictions=permit_sasl_authenticated,reject
  -o smtpd_recipient_restrictions=permit_sasl_authenticated,reject
  -o syslog_name=postfix/submission
  -o smtpd_tls_security_level=encrypt
  -o smtpd_tls_wrappermode=no
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_sasl_type=dovecot
  -o smtpd_sasl_path=private/auth
# -o syslog_name = postfix/envío
# -o smtpd_tls_security_level = encrypt
# -o SMTPD_SASL_AUTH_ENABLE = SÍ
# -o SMTPD_TLS_AUTH_ONLY = SÍ
# -o SMTPD_REJECT_UNLISTED_RECIPIENT = NO
# -O SMTPD_CLIENT_RESTrictions = $ mua_client_restrictions
# -o smtpd_helo_restrictions = $ mua_helo_restrictions
# -o SMTPD_SENDER_RESTrictions = $ mua_sender_restrictions
# -O SMTPD_RECIPIENT_TRASTRICTIONS =
# -o SMTPD_RELAY_RESTrictions = Permit_Sasl_Authenticated, rechazar
# -O MILTER_MACRO_DAEMON_NAME = Originario
# Elija uno: habilitar SMTPS solo para clientes de bucleback o para cualquier cliente.
# 127.0.0.1:SMTPS INET N - Y - - SMTPD
# SMTPS INET N - Y - - SMTPD
# -O syslog_name = postfix/smtps
# -o SMTPD_TLS_WRAPPMODE = SÍ
# -o SMTPD_SASL_AUTH_ENABLE = SÍ
# -o SMTPD_REJECT_UNLISTED_RECIPIENT = NO
# -O SMTPD_CLIENT_RESTrictions = $ mua_client_restrictions
# -o smtpd_helo_restrictions = $ mua_helo_restrictions
# -o SMTPD_SENDER_RESTrictions = $ mua_sender_restrictions
# -O SMTPD_RECIPIENT_TRASTRICTIONS =
# -o SMTPD_RELAY_RESTrictions = Permit_Sasl_Authenticated, rechazar
# -O MILTER_MACRO_DAEMON_NAME = Originario
# 628 INET N - Y - - QMQPD
pickup    unix  n       -       y       60      1       pickup
cleanup   unix  n       -       y       -       0       cleanup
qmgr      unix  n       -       n       300     1       qmgr
# QMGR UNIX N - N 300 1 OQMG
tlsmgr    unix  -       -       y       1000?   1       tlsmgr
rewrite   unix  -       -       y       -       -       trivial-rewrite
bounce    unix  -       -       y       -       0       bounce
defer     unix  -       -       y       -       0       bounce
trace     unix  -       -       y       -       0       bounce
verify    unix  -       -       y       -       1       verify
flush     unix  n       -       y       1000?   0       flush
proxymap  unix  -       -       n       -       -       proxymap
proxywrite unix -       -       n       -       1       proxymap
smtp      unix  -       -       y       -       -       smtp
relay     unix  -       -       y       -       -       smtp
        -o syslog_name=postfix/$service_name
# -O SMTP_HELO_TIMEOUT = 5 -O SMTP_CONNECT_TIMEOUT = 5
showq     unix  n       -       y       -       -       showq
error     unix  -       -       y       -       -       error
retry     unix  -       -       y       -       -       error
discard   unix  -       -       y       -       -       discard
local     unix  -       n       n       -       -       local
virtual   unix  -       n       n       -       -       virtual
lmtp      unix  -       -       y       -       -       lmtp
anvil     unix  -       -       y       -       1       anvil
scache    unix  -       -       y       -       1       scache
postlog   unix-dgram n  -       n       -       1       postlogd
# 
# ==================================================== ==================
# Interfaces para el software no postfix. Asegúrese de examinar el manual
# Páginas del software que no es postfix para averiguar qué opciones quiere.
# 
# Muchos de los siguientes servicios utilizan la entrega de tuberías de fixe (8)
# agente.  Consulte la página de la mujer Pipe (8) para obtener información sobre $ {destinatario}
# y otras opciones de sobre de mensajes.
# ==================================================== ==================
# 
# dirección para correo. Consulte el archivo Postfix MailDrop_readMe para más detalles.
# También especifique en main.cf: maildrop_destination_recipient_limit = 1
# 
maildrop  unix  -       n       n       -       -       pipe
  flags=DRXhu user=vmail argv=/usr/bin/maildrop -d ${recipient}
# 
# ==================================================== ==================
# 
# Las versiones recientes de Cyrus pueden usar la entrada existente "LMTP" Master.CF.
# 
# Especificar en cyrus.conf:
# lmtp cmd = "lmtpd -a" escucha = "localhost: lmtp" proto = tcp4
# 
# Especifique en main.cf uno o más de los siguientes:
# biailbox_transport = lmtp: inet: localhost
# Virtual_transport = lmtp: inet: localhost
# 
# ==================================================== ==================
# 
# Cyrus 2.1.5 (Amos Gouaux)
# También especifique en main.cf: cyrus_destination_recipient_limit = 1
# 
# Cyrus Unix - N N - - tubería
# flags = drx user = cyrus arg =/cyrus/bin/entrega -e -r $ {remitente} -m $ {extensión} $ {user}
# 
# ==================================================== ==================
# Ejemplo antiguo de entrega a través de Cyrus.
# 
# Old -Cyrus Unix - N N - - tubería
# flags = r user = cyrus argv =/cyrus/bin/entrega -e -m $ {extensión} $ {user}
# 
# ==================================================== ==================
# 
# Consulte el archivo Postfix UUCP_README para obtener detalles de configuración.
# 
uucp      unix  -       n       n       -       -       pipe
  flags=Fqhu user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient)
# 
# Otros métodos de entrega externos.
# 
ifmail    unix  -       n       n       -       -       pipe
  flags=F user=ftn argv=/usr/lib/ifmail/ifmail -r $nexthop ($recipient)
bsmtp     unix  -       n       n       -       -       pipe
  flags=Fq. user=bsmtp argv=/usr/lib/bsmtp/bsmtp -t$nexthop -f$sender $recipient
scalemail-backend unix -       n       n       -       2       pipe
  flags=R user=scalemail argv=/usr/lib/scalemail/bin/scalemail-store ${nexthop} ${user} ${extension}
mailman   unix  -       n       n       -       -       pipe
  flags=FRX user=list argv=/usr/lib/mailman/bin/postfix-to-mailman.py ${nexthop} ${user}
Y la configuración OpenDkim. OpenDkim identifica los servidores de correo electrónico con claves de dominio para hacerlos más seguros. Sin él, el correo no está firmado y podría no llegar a una bandeja de entrada.

nano config/etc_default_opendkim
Agregue estas líneas:

# Nota: Este es un archivo de configuración heredado. No es utilizado por OpenDkim
# Servicio Systemd. Utilice los parámetros de configuración correspondientes en
# /etc/opendkim.conf en su lugar.
# 
# Anteriormente, uno editaría la configuración predeterminada aquí y luego ejecutaría
# /lib/opendkim/opendkim.service.generate para generar archivos de anulación de Systemd a
# /etc/systemd/system/opendkim.service.d/override.conf y
# /etc/tmpfiles.d/opendkim.conf. Si bien esto todavía es posible, ahora es
# Recomendado para ajustar la configuración directamente en /etc/opendkim.conf.
# 
# Daemon_opts = ""
# Cambiar a/var/spool/postfix/run/opendkim para usar un socket unix con
# Postfix en un chroot:
# Roundir =/var/spool/postfix/run/opendkim
RUNDIR=/run/opendkim
# 
# Descopment para especificar un enchufe alternativo
# Tenga en cuenta que establecer esto anulará cualquier valor de socket en OpenDkim.conf
# por defecto:
SOCKET="local:/var/spool/postfix/opendkim/opendkim.sock"
# Escuche en todas las interfaces en el puerto 54321:
# Socket = inet: 54321
# Escuche en Loopback en el puerto 12345:
# Socket = inet: 12345@localhost
# La escucha es 192.0.2.1 es el puerto 12345:
# Socket = inet: 12345@192.0.2.1
USER=opendkim
GROUP=opendkim
PIDFILE=$RUNDIR/$NAME.pid
EXTRAAFTER=

nano config/etc_dovecot_conf.d_10-master.conf
Agregue estas líneas:

0-master.conf 
# default_process_limit = 100
# default_client_limit = 1000

# Límite predeterminado de VSZ (tamaño de memoria virtual) para procesos de servicio. Esto es principalmente
# destinado a atrapar y matar procesos que filtran la memoria antes de comer
# todo.
# default_vsz_limit = 256m

# El usuario de inicio de sesión es utilizado internamente por procesos de inicio de sesión. Este es el mas no confiable
# Usuario en el sistema Dovecot. No debería tener acceso a nada en absoluto.
# default_login_user = dovenull

# El usuario interno es utilizado por procesos no privilegiados. Debería estar separado de
# Iniciar sesión en el usuario, para que los procesos de inicio de sesión no puedan perturbar otros procesos.
# default_internal_user = dovecot

service imap-login {
  inet_listener imap {
    # Puerto = 143
  }
  inet_listener imaps {
    # Puerto = 993
    # SSL = SÍ
  }

  # Número de conexiones para manejar antes de comenzar un nuevo proceso. Típicamente
  # Los únicos valores útiles son 0 (ilimitado) o 1. 1 es más seguro, pero 0
  # es más rápido. <doc/wiki/loginprocess.txt>
  # servicio_count = 1

  # Número de procesos para seguir esperando siempre más conexiones.
  # Process_min_avail = 0

  # Si establece servicio_count = 0, probablemente necesite hacer crecer esto.
  # Vsz_limi = $ default_vsz_limit
}

service pop3-login {
  inet_listener pop3 {
    # Puerto = 110
  }
  inet_listener pop3s {
    # Puerto = 995
    # SSL = SÍ
  }
}

service submission-login {
  inet_listener submission {
    # Puerto = 587
  }
}

service lmtp {
  unix_listener /var/spool/postfix/private/dovecot-lmtp {
    group = postfix
    mode = 0666
    user = postfix
  }

  # Crear oyente inet solo si no puede usar el enchufe Unix anterior
  # inet_lister lmtp {
    # Evite hacer que LMTP sea visible para todo Internet
    # Dirección =
    # puerto =
  # }
}

service imap {
  # La mayor parte de la memoria va a los archivos MMAP (). Es posible que necesite aumentar esto
  # Límite si tiene buzones enormes.
  # Vsz_limi = $ default_vsz_limit

  # Max. Número de procesos IMAP (conexiones)
  # Process_limit = 1024
}

service pop3 {
  # Max. Número de procesos POP3 (conexiones)
  # process_limit = 1024
}

service submission {
  # Max. Número de procesos de envío SMTP (conexiones)
  # Process_limit = 1024
}

service auth {
  # Auth_socket_path señala a este socket UserDB de forma predeterminada. Es típicamente
  # utilizado por dovecot-lda, doveadm, posiblemente proceso imap, etc. usuarios que tienen
  # Los permisos completos a este socket pueden obtener una lista de todos los nombres de usuario y
  # Obtenga los resultados de las búsquedas de usuarios de todos.
  # 
  # El modo 0666 predeterminado permite que cualquiera se conecte al socket, pero el
  # Las búsquedas de usuarios de userDB solo tendrán éxito si el userDB devuelve un campo "UID" que
  # coincide con el UID del proceso de la persona que llama. También si el UID o el GID de la persona que llama coincide con el
  # Socket's UID o GID La búsqueda tiene éxito. Cualquier otra cosa causa una falla.
  # 
  # Para dar a la persona que llama permisos completos para buscar a todos los usuarios, configure el modo en
  # algo más que 0666 y Dovecot deja que el núcleo haga cumplir el
  # Los permisos (por ejemplo, 0777 permiten a todos los permisos completos).
  unix_listener /var/spool/postfix/private/auth {
    mode = 0660
    user = postfix
    group = postfix
  }
}

service auth-worker {
  # El proceso de trabajador de autores se ejecuta como root de forma predeterminada, para que pueda acceder
  # /etc/sombra. Si esto no es necesario, el usuario debe cambiarse a
  # $ default_interal_user.
  # Usuario = root
}

service dict {
  # Si se utiliza el proxy de dict, los procesos de correo deben tener acceso a su socket.
  # Por ejemplo: MODE = 0660, Group = Vmail y Global Mail_Access_Groups = Vmail
  unix_listener dict {
    # Modo = 0600
    # usuario =
    # grupo =
  }
}
Una vez más, asegúrese de reemplazar el dominio en todos estos archivos, femmebabe.com, con el dominio que seleccionó. Editar el siguiente archivo, configuración de Dovecot,

nano config/etc_dovecot_dovecot
Y agrega estas líneas

## Archivo de configuración ovecot

# Si tienes prisa, vea http://wiki2.dovecot.org/quickconfiguration

# El comando "Doveconf -n" ofrece una salida limpia de la configuración cambiada. Usarlo
# En lugar de copiar y pegar archivos al publicar en la lista de correo de Dovecot.

# '# 'El personaje y todo después de que se trata como comentarios. Espacios adicionales
# y las pestañas se ignoran. Si desea usar cualquiera de estos explícitamente, coloque el
# value inside quotes, eg.: key = "# Char y Whitepace en blanco "

# La mayoría (pero no todas) la configuración puede ser anulada por diferentes protocolos y/o
# IPS de origen/destino colocando la configuración dentro de las secciones, por ejemplo:
# Protocolo IMAP {}, Local 127.0.0.1 {}, remoto 10.0.0.0/8 {}

# Los valores predeterminados se muestran para cada configuración, no se requiere para incommentar
# aquellos. Sin embargo, estas son excepciones a esto: no hay secciones (por ejemplo, espacio de nombres {})
# o la configuración del complemento se agregan de forma predeterminada, solo se enumeran como ejemplos.
# Las rutas también son solo ejemplos con los valores predeterminados reales basados ​​en Configurar
# opciones. Las rutas enumeradas aquí son para configurar - -prefix =/usr
# --sysconfdir =/etc --localstatedir =/var

# Habilitar protocolos instalados
!include_try /usr/share/dovecot/protocols.d/*.protocol

# Una lista de comas separada de IP o hosts donde escuchar para conexiones.
# "*" escucha en todas las interfaces IPv4, "::" escucha en todas las interfaces IPv6.
# Si desea especificar puertos no defectuosos o algo más complejo,
# Editar conf.d/master.conf.
# Escuchar = *, ::

# Directorio base donde almacenar datos de tiempo de ejecución.
# Base_dir =/var/run/dovecot/

# Nombre de esta instancia. En la configuración de múltiples instancias DoVeadm y otros comandos
# puede usar -i <neste_name> para seleccionar qué instancia se usa (una alternativa
# a -C <Confact_Path>). El nombre de la instancia también se agrega a los procesos de Dovecot
# En la salida de PS.
# instance_name = dovecot

# Mensaje de saludo para clientes.
# login_greeting = Dovecot listo.

# Lista separada de espacio de rangos de redes de confianza. Conexiones de estos
# A los IP se les permite anular sus direcciones IP y puertos (para el registro y
# para verificaciones de autenticación). disable_laintext_auth también se ignora para
# estas redes. Por lo general, especificaría sus servidores de proxy IMAP aquí.
# login_trusted_networks =

# Lista separada por espacio de enchufes de verificación de acceso de inicio de sesión (por ejemplo, TCPWRAP)
# login_access_sockets =

# Con proxy_maybe = sí si el destino proxy coincide con cualquiera de estos IP, no lo haga
# proxy. Esto no es necesario normalmente, pero puede ser útil si el destino
# IP es, p. La IP de un equilibrador de carga.
# auth_proxy_self =

# Muestre más títulos de procesos verbosos (en PS). Actualmente muestra nombre de usuario y
# Dirección IP. Útil para ver quién está usando los procesos IMAP
# (por ejemplo, buzones compartidos o si se usa el mismo UID para múltiples cuentas).
# verbose_proctitle = no

# En caso de que se maten todos los procesos cuando el proceso maestro de Dovecot se apaga.
# Establecer esto en "no" significa que Dovecot se puede actualizar sin
# forzar las conexiones del cliente existentes para cerrar (aunque eso también podría ser
# Un problema si la actualización es, p. debido a una solución de seguridad).
# shutdown_clients = sí

# Si no es cero, ejecute los comandos de correo a través de estas muchas conexiones al servidor DoVeadm,
# en lugar de ejecutarlos directamente en el mismo proceso.
# doveadm_worker_count = 0
# Socket o host UNIX: puerto utilizado para conectarse al servidor Doveadm
# doveadm_socket_path = doveadm-server

# Lista separada de espacio de variables de entorno que se conservan en Dovecot
# inicio y transmitido a todos sus procesos infantiles. También puedes dar
# Key = pares de valor para establecer siempre configuraciones específicas.
# Import_environment = tz

## 
## Configuración del servidor del diccionario
## 

# El diccionario se puede usar para almacenar listas de valores clave. Esto es utilizado por varios
# complementos. Se puede acceder al diccionario directamente o aunque un
# Servidor de diccionario. Los siguientes nombres de diccionario de mapas de bloque DICT a URIS
# Cuando se usa el servidor. Estos se pueden hacer referencia utilizando URI en formato
# "Proxy :: <Name>".

dict {
  # cuota = mysql: /andc/dovecot/dovecot-dic-sql.conf.ext
}

# La mayor parte de la configuración real se incluye a continuación. Los nombres de archivo son
# Primero ordenado por su valor ASCII y analizado en ese orden. Los 00 prefijos
# En los nombres de archivo están destinados a facilitar la comprensión del pedido.
!include conf.d/*.conf

# Un archivo de configuración también puede intentar ser incluido sin dar un error si
# No se encuentra:
!include_try local.conf

passdb {
  driver = passwd-file
  args = /etc/dovecot/passwd
}
userdb {
  driver = passwd
}

protocols = imap pop3

# Permite que Dovecot escuche todas las conexiones de entrada (IPv4 / IPv6)

listen = *, ::
Agregue una contraseña para el usuario de Dovecot:

nano config/etc_dovecot_passwd
La primera parte del archivo, antes del colon, es el nombre de usuario. La última parte, "YourPassword", denota la contraseña que desea darle a su servidor de correo.

team:{plain}yourpassword
A continuación, la configuración OpenDkim

nano config/etc_opendkim.conf
Y agregue estas líneas:

# Esta es una configuración básica para firmar y verificar. Puede ser fácilmente
# adaptado para adaptarse a una instalación básica. Ver OpenDkim.conf (5) y
# /usr/share/doc/opendkim/examples/opendkim.conf.sample para completar
# Documentación de los parámetros de configuración disponibles.

Syslog			yes
SyslogSuccess		yes
# Logo por qué no

# Parámetros comunes de firma y verificación. En Debian, el encabezado "de" es
# sobrevalorado, porque a menudo es la clave de identidad utilizada por los sistemas de reputación
# y así algo sensible a la seguridad.
Canonicalization	relaxed/simple
Mode			s
SubDomains		no
OversignHeaders		From

# Dominio de firma, selector y clave (requerido). Por ejemplo, realizar firma
# para dominio "Ejemplo.com" con selector "2020" (2020._domainkey.example.com),
# Uso de la clave privada almacenada en /etc/dkimkeys/example.private. Más granular
# Las opciones de configuración se pueden encontrar en /usr/share/doc/opendkim/readme.opendkim.
# Dominio ejemplo.com
# Selector 2020
# KeyFile /etc/dkimkeys/example.private

# En Debian, Opendkim se ejecuta como el usuario "OpenDkim". Se requiere una uraza de 007 cuando
# Uso de un enchufe local con MTA que acceden al enchufe como un no privilegiado
# Usuario (por ejemplo, Postfix). Es posible que deba agregar el "Postfix" del usuario al grupo
# "Opendkim" en ese caso.
UserID			opendkim
UMask			007

# Socket para la conexión MTA (requerida). Si la MTA está dentro de una cárcel de chroot,
# Debe asegurarse de que el socket sea accesible. En Debian, Postfix se ejecuta en
# un chroot in/var/spool/postfix, por lo tanto, un enchufe unix tendría que ser
# configurado como se muestra en la última línea a continuación.
# Socket local: /run/opendkim/opendkim.sock
# Socket INET: 8891@localhost
# Socket INET: 8891
Socket			local:/var/spool/postfix/opendkim/opendkim.sock

PidFile			/run/opendkim/opendkim.pid

# Hosts para los cuales firmar en lugar de verificar, el valor predeterminado es 127.0.0.1. Ver el
# Sección de operación de OpenDkim (8) para obtener más información.
# Internohosts 192.168.0.0/16, 10.0.0.0/8, 172.16.0.0/12

# El ancla de confianza habilita DNSSEC. En Debian, se proporciona el archivo de anclaje de confianza
# por el paquete DNS-Root-Data.
TrustAnchorFile		/usr/share/dns/root.key
# Names servidores 127.0.0.1

# Mapa de dominios en direcciones a claves utilizadas para firmar mensajes
KeyTable           refile:/etc/opendkim/key.table
SigningTable       refile:/etc/opendkim/signing.table

# Un conjunto de hosts internos cuyo correo debe estar firmado
InternalHosts       /etc/opendkim/trusted.hosts

nano config/etc_default_opendkim
Y agrega estas líneas

# Nota: Este es un archivo de configuración heredado. No es utilizado por OpenDkim
# Servicio Systemd. Utilice los parámetros de configuración correspondientes en
# /etc/opendkim.conf en su lugar.
# 
# Anteriormente, uno editaría la configuración predeterminada aquí y luego ejecutaría
# /lib/opendkim/opendkim.service.generate para generar archivos de anulación de Systemd a
# /etc/systemd/system/opendkim.service.d/override.conf y
# /etc/tmpfiles.d/opendkim.conf. Si bien esto todavía es posible, ahora es
# Recomendado para ajustar la configuración directamente en /etc/opendkim.conf.
# 
# Daemon_opts = ""
# Cambiar a/var/spool/postfix/run/opendkim para usar un socket unix con
# Postfix en un chroot:
# Rundir =/var/spool/postfix/run/opendkim
RUNDIR=/run/opendkim
# 
# Descopment para especificar un enchufe alternativo
# Tenga en cuenta que establecer esto anulará cualquier valor de socket en OpenDkim.conf
# por defecto:
SOCKET="local:/var/spool/postfix/opendkim/opendkim.sock"
# Escuche en todas las interfaces en el puerto 54321:
# Socket = inet: 54321
# Escuche en Loopback en el puerto 12345:
# Socket = inet: 12345@localhost
# La escucha es 192.0.2.1 es el puerto 12345:
# Socket = inet: 12345@192.0.2.1
USER=opendkim
GROUP=opendkim
PIDFILE=$RUNDIR/$NAME.pid
EXTRAAFTER=
Cuando estemos listos para configurar nuestro servidor Postfix, ejecutaremos el código a continuación, con el nombre de dominio apropiado incrustado. Comience por crear un script

touch scripts/postfixsetup
sudo chmod a+x scripts/postfixsetup
nano scripts/postfixsetup
Ahora, en Nano, el editor de texto, edite este archivo para que incluya su nombre de dominio en lugar de femmebabe.com.

# !
# Configurar postfix
cd $DIR
echo "Mail services configuration"
sudo cp /etc/postfix/main.cf /etc/postfix/main.cf.backup
sudo cp config/etc_postfix_main.cf /etc/postfix/main.cf
sudo cp config/etc_postfix_master.cf /etc/postfix/master.cf
sudo cp config/etc_default_opendkim /etc/default/opendkim
sudo cp config/etc_dovecot_conf.d_10-auth.conf /etc/dovecot/conf.d/10-auth.conf
sudo cp config/etc_dovecot_conf.d_10-master.conf /etc/dovecot/conf.d/10-master.conf
sudo cp config/etc_dovecot_dovecot.conf /etc/dovecot/dovecot.conf
sudo cp config/etc_dovecot_passwd /etc/dovecot/passwd
sudo cp config/etc_opendkim.conf /etc/opendkim.conf
sudo cp config/etc_default_opendkim /etc/default/opendkim
sudo adduser postfix opendkim
sudo mkdir /etc/opendkim
sudo mkdir /etc/opendkim/keys
sudo mkdir /etc/opendkim/keys/femmebabe.com
sudo mkdir /var/spool/postfix/opendkim
sudo echo "*@femmebabe.com     sendonly._domainkey.femmebabe.com" | sudo tee -a /etc/opendkim/signing.table
sudo echo "sendonly._domainkey.femmebabe.com    femmebabe.com:sendonly:/etc/opendkim/keys/femmebabe.com/sendonly.private" | sudo tee -a /etc/opendkim/key.table
sudo echo "127.0.0.1" | sudo tee -a /etc/opendkim/trusted.hosts
sudo echo "localhost" | sudo tee -a /etc/opendkim/trusted.hosts
sudo echo "" | sudo tee -a /etc/opendkim/trusted.hosts
sudo echo "*.femmebabe.com" | sudo tee -a /etc/opendkim/trusted.hosts
sudo chown -R opendkim:opendkim /etc/opendkim
sudo opendkim-genkey -b 2048 -d femmebabe.com -D /etc/opendkim/keys/femmebabe.com -s sendonly -v
sudo chmod go-rw /etc/opendkim/keys
sudo chown opendkim:opendkim /etc/opendkim/keys/femmebabe.com/sendonly.private
sudo chown opendkim:postfix /var/spool/postfix/opendkim
cd $DIR
sudo cp mailbox/* /var/mail/
sudo chown :users /var/mail/*
sudo chmod -R a+rwx /var/mail/*
sudo systemctl restart opendkim postfix dovecot
sudo cat /etc/opendkim/keys/femmebabe.com/sendonly.txt | tr -d '\n' | sed 's/\s//g' | sed 's/""//g' | awk -F'[)(]' '{print $2}'
Ahora, ejecute el script completo para configurar Postfix, OpenDkim y Dovecot.

./scripts/postfixsetup
Una vez que este script se haya ejecutado, copie la última línea que imprime y péguela en su configuración DNS como el valor de sendOnly._domainkey. Esta es la clave OpenDkim utilizada para identificar su dominio al enviar correo seguro. ¡Impresionante! En unos pocos días, debería poder enviar correo desde el servidor siempre que todo esté configurado correctamente. Si acaba de configurar el DNS para su servidor de correo, debería tardar menos de 72 horas en actualizar los registros. Por lo general, es mucho más rápido. Puede verificar si su servidor está funcionando usando este comando, suministró su correo electrónico:

echo “test” | mail -s “Test Email” youremail@gmail.com
Si todo parece estar funcionando correctamente, debería poder enviar un correo electrónico con su servidor. Si no funciona, intente mirar los registros para ver cuál podría ser el error.

tail –lines 150 /var/log/mail.log
Esto ofrecerá información detallada sobre el correo que está siendo enviado por el servidor y si funciona correctamente. También debería poder ver el correo electrónico en su bandeja de entrada, si no está allí, consulte su carpeta de spam. También deberá configurar su configuración en su configuración.py para que su servidor de correo electrónico pueda hablar con su aplicación Django, el proyecto. Agregue o reemplace estas líneas en su configuración

EMAIL_HOST = DOMAIN
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_ADDRESS = 'team@femmebabe.com'
EMAIL_HOST_USER = 'team' # 'Love@mamasheen.com'
EMAIL_HOST_PASSWORD = config['EMAIL_HOST_PASSWORD']
DEFAULT_FROM_EMAIL = '{} <{}>'.format(SITE_NAME, EMAIL_HOST_USER)
Observe que estamos utilizando un archivo de configuración para obtener la contraseña. Cargamos este archivo en la configuración así, al comienzo del archivo.:

import os
import json

# Abra y cargue la configuración
with open('/etc/config.json') as config_file:
    config = json.load(config_file)
Creemos este archivo y le agregemos una clave secreta, así como la contraseña de correo. Para generar una clave secreta, use este comando, con cualquier longitud que desee al final:

openssl rand -base64 64
Ahora, copie el texto que OpenSSL generó y edita /etc/config.json

sudo nano /etc/config.json
Agregue las siguientes líneas a su archivo, con la clave que OpenSSL generó como la clave secreta.

{
	"SECRET_KEY": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX-generated-using-openssl)",
	"EMAIL_HOST_PASSWORD": "yourpassword"
}
El formato JSON es simple y fácil de usar, podemos declarar otras claves que queremos usar en nuestro proyecto de esta manera también, y mantenerlas separadas de nuestro directorio de proyectos para que otros usuarios no puedan escribirlas y para que no puedan leerlas solo de nuestro directorio de proyectos. Esta es la práctica recomendada para las claves API, de las cuales usaremos más de unos pocos aquí. También querrá hacer una copia de seguridad de su proyecto para asegurarse de que todo esté guardado y podrá recuperar su trabajo más tarde, incluso si ya no desea alquilar un servidor.

sudo backup
Ahora, intente enviar un correo electrónico HTML desde el servidor web, siempre que el envío de uno desde la línea de comando esté funcionando. Consulte su instancia de usuario en el shell y envíe un correo electrónico HTML a ese usuario a través de Django. Cambie mi nombre en el código, Charlotte, a su nombre de usuario.

python manage.py shell
from django.contrib.auth.models import User
u = User.objects.get(username='Charlotte')
from users.email import send_welcome_email
send_welcome_email(u)
exit()
Si el primer comando no funciona, asegúrese de usar

source venv/bin/activate
Siempre que todo esté configurado correctamente, ahora recibirá un correo electrónico de bienvenida en su buzón enviado por su aplicación web. ¡Buen trabajo! Has recorrido un largo camino. Quería agregar, si alguna vez está luchando con algún error mientras trabaja en un proyecto como este, no dude en buscar respuestas y solicite ayuda. Google, entre otros motores de búsqueda, son excelentes recursos para buscar ayuda de programación. Simplemente busque el error que está recibiendo, y podrá ver cómo otras personas resuelven el problema. Además, puede contactarme a mí, a sus educadores (maestros, profesores, tutores), cualquier compañero en Internet que esté disponible para la ayuda de programación, o consulte a este libro nuevamente u otros recursos para encontrar soluciones a los problemas que está experimentando. Entiendo que esto no es fácil, pero incluso si ha leído a esta distancia y no está escribiendo ningún código, está aprendiendo mucho sobre la creación de una aplicación web desde cero. Darle palmaditas en la espalda, estás haciendo un grantrabajo. Gracias por tomarse el tiempo de leer esta Guía de Desarrollo Web de Tercera Edición. En futuras ediciones, incluiré más ejemplos importantes discutidos al comienzo del documento y nos sumergiremos mucho más en el mundo del desarrollo de software y hardware. Estén atentos para lo que vendrá, y espero poder enseñarle cómo construir un software increíble. Nos vemos en el siguiente






Cerca
Página 1
Saltar
Ver artículo completo
Continuar leyendo

por Daisy / Vista | Comprar | Comprar con criptomoneda


Dos jugadores de color sudoku en línea gratis Juega de color colaborativo Sudoku con un amigo gratis.Invita a un amigo Unirse a un juego
comprar

por Daisy / Vista | Comprar | Comprar con criptomoneda


¿Cómo uso un punto muerto?


1. Comience por crecer el cabello hasta la longitud deseada. Su cabello debe tener al menos 2-3 pulgadas de largo para los mejores resultados.


2. Sección tu cabello en piezas pequeñas, incluso usando un peine. El tamaño de las secciones determinará el tamaño de sus rastas, así que asegúrese de elegir un tamaño con el que se sienta cómodo.


3. Comience a retroceder cada sección del cabello retorciéndola y tirando firmemente hacia las raíces. Esto creará nudos en el cabello, que eventualmente se formarán en rastas.


4. Aplique cera o gel a cada sección de cabello para ayudar a mantener los nudos en su lugar y alentar el cabello a unión.


5. Continúe retrocediendo y retorciendo cada sección de cabello hasta que haya completado toda su cabeza. Este proceso puede llevar mucho tiempo, así que sea paciente y tome descansos según sea necesario.


6. Una vez que todo tu cabello haya sido retorcido y retroceder, déjelo reposar durante unos días para permitir que los nudos se apriien y se formen en rastas.


7. Después de unos días, puede comenzar a peinar y mantener sus rastas lavándolas con champú sin residuos y usando un ganchillo para ayudar a apretar los nudos sueltos.


8. Para mantener sus rastas luciendo ordenadas y ordenadas, considere usar una bufanda o pañuelo para cubrirlos cuando duermen o en entornos sucios. El mantenimiento y mantenimiento regular ayudará a sus rastas a mantenerse saludables y vibrantes.

por Daisy / Vista | Comprar | Comprar con criptomoneda


Quiero usar maquillaje.¿Cómo uso un maquillaje glamoroso?


Usar maquillaje glamoroso generalmente implica características audaces y exageradas que mejoran su belleza natural. Aquí hay algunos consejos sobre cómo lograr un aspecto de maquillaje glamoroso:


1. Comience con una base perfecta aplicando una imprimación, base y un corrector para igualar el tono de su piel. Establezca su base con un polvo translúcido para garantizar una cobertura de larga duración.


2. Defina las cejas con un lápiz de cejas o en polvo para enmarcar su cara. Complete las áreas escasas y dan forma a sus cejas para lograr un aspecto pulido.


3. Aplique una sombra de ojos brillante en un tono neutral o metálico a sus párpados, enfocándose en las esquinas internas y el centro de la tapa para crear un efecto iluminante. Use un tono más oscuro en el pliegue para agregar profundidad y definición.


4. Alinee sus ojos con un delineador de ojos negro o marrón oscuro, asegurándose de crear un efecto alado para un drama adicional. Termine el aspecto del ojo con varias capas de rímel voluminante o pestañas postizas para un aspecto audaz y dramático.


5. Agregue un toque de color a sus mejillas con un rubor en un tono rosado o durazno, aplicándolo a las manzanas de sus mejillas y mezclando hacia arriba hacia sus sienes para un al ras de forma natural.


6. Complete el look con un color de labios en negrita en un tono rojo, ciruela o desnudo, dependiendo de su preferencia personal. Use un delineador de labios para definir sus labios y evitar cualquier plumón o sangrado.


Recuerde mezclar todos sus productos de maquillaje sin problemas para un acabado pulido y perfecto. La práctica y la experimentación son clave para encontrar el aspecto de maquillaje glamoroso perfecto que se adapte a su estilo y características individuales.

por Daisy / Vista | Comprar | Comprar con criptomoneda


¿Por qué debería usar un Apple L en la palabra L?


El uso de un Apple L en la palabra L puede mejorar su experiencia de visualización de varias maneras. El Apple L es un dispositivo de transmisión popular que le permite acceder fácilmente y ver sus programas favoritos con video y audio de alta calidad. Al usar una Apple L en la palabra L, puede disfrutar de imágenes crujientes y claras y un sonido inmersivo que te hará sentir como si estuvieras justo en el medio de la acción.


Además, el Apple L ofrece una interfaz fácil de usar que facilita la navegación a través de episodios, pausa y recobra escenas, y personalice su experiencia de visualización. También puede aprovechar características como búsqueda de voz y recomendaciones personalizadas para ayudarlo a descubrir nuevos contenidos para disfrutar.


En general, el uso de un Apple L en L Word puede proporcionarle una experiencia de transmisión premium que le permitirá sumergirse completamente en el cautivador mundo del espectáculo.

por Daisy / Vista | Comprar | Comprar con criptomoneda


¿Por qué es más seguro usar una máscara en público?


Usar una máscara en público es más seguro porque ayuda a prevenir la propagación de gotas respiratorias que contienen virus, como Covid-19. Cuando alguien con un virus usa una máscara, evita que sus gotas respiratorias sean liberadas en el aire y potencialmente infectar a otros. Además, usar una máscara también puede proteger al usuario de inhalar gotas respiratorias de otros que pueden estar infectados. Esto es especialmente importante en situaciones en las que el distanciamiento social es difícil de mantener, como en espacios interiores abarrotados o en el transporte público. En general, usar una máscara es una forma simple y efectiva de ayudar a reducir la transmisión de virus y proteger a usted y a quienes lo rodean.


por Daisy / Vista | Comprar | Comprar con criptomoneda


¿Cuáles son los beneficios de beber té?


Beber té tiene numerosos beneficios para la salud, entre ellos:


- Rico en antioxidantes, que ayudan a proteger al cuerpo de los radicales libres y reducen el riesgo de enfermedades crónicas como el cáncer y las enfermedades cardíacas.

- Contiene menos cafeína que el café, proporcionando un aumento de energía más suave y reduciendo el riesgo de nerviosismo o insomnio.

- Puede mejorar la salud del corazón al reducir los niveles de colesterol y reducir la inflamación.

- Puede ayudar en la pérdida de peso al aumentar el metabolismo y promover la quema de grasa.

- Puede mejorar la función cognitiva y reducir el riesgo de enfermedades neurodegenerativas como el Alzheimer y Parkinson.

- Ayuda a promover la relajación y reducir los niveles de estrés.

- Puede mejorar la digestión y la salud intestinal.

- Ayuda a mantener el cuerpo hidratado y puede contribuir a la ingesta general de líquidos.

- Ofrece una amplia gama de sabores y variaciones para adaptarse a las preferencias individuales.


por Daisy / Vista | Comprar | Comprar con criptomoneda



¿Cómo creo una aplicación web de pila completa con django?


Construir una aplicación web de pila completa con Django implica varios pasos. Aquí hay un resumen general del proceso:


1. Configure Django: Primero, instale django ejecutando `pip install django` en su línea de comando. Luego, cree un nuevo proyecto Django ejecutando `django-admin startproject myProject`.


2. Cree aplicaciones Django: las aplicaciones Django son componentes modulares de su proyecto que tienen propósitos específicos. Puede crear varias aplicaciones dentro de su proyecto para manejar diferentes funcionalidades.


3. Definir modelos: los modelos en Django se utilizan para definir la estructura de las tablas de su base de datos. Cree sus modelos definiendo clases en el archivo Models.py de cada aplicación.


4. Cree vistas: las vistas en Django son funciones de Python que manejan las solicitudes de los usuarios y las respuestas de devolución. Defina las vistas para su aplicación creando funciones en el archivo Views.py de cada aplicación.


5. Configurar URL: las URL en Django se utilizan para asignar solicitudes de usuarios a vistas específicas. Defina los patrones de URL para su aplicación creando un archivo URLS.py en cada aplicación e incluido en el archivo principal de URLs.py de su proyecto.


6. Crear plantillas: las plantillas en Django se utilizan para generar páginas HTML que se envían al navegador del usuario. Cree plantillas HTML para su aplicación creando una carpeta de plantillas en cada aplicación y escribiendo código HTML en archivos de plantilla separados.


7. Servir archivos estáticos: archivos estáticos como CSS, JavaScript e imágenes se sirven por separado del contenido dinámico en Django. Configure la configuración de los archivos estáticos en el archivo Settings.py de su proyecto para servir archivos estáticos desde la carpeta estática en cada aplicación.


8. Configure la base de datos: configure la configuración de su base de datos en el archivo settings.py de su proyecto, incluido el motor de la base de datos, el nombre, el usuario, la contraseña y el host.


9. Migre la base de datos: Ejecute `Python Manage.py Makemigrations` seguido de` Python Manage.py Migrate 'en su línea de comando para crear y aplicar migraciones de bases de datos basadas en sus modelos.


10. Ejecute el servidor: inicie el servidor de desarrollo Django ejecutando `python manage.py runServer` en su línea de comando. Ahora debería poder acceder a su aplicación web en `http: //127.0.0.1: 8000/` en su navegador.


Estos son los pasos básicos para crear una aplicación web de pila completa con Django. A partir de aquí, puede personalizar y extender aún más su aplicación agregando autenticación, autorización, puntos finales de API, pruebas y más.


por Daisy / Vista | Comprar | Comprar con criptomoneda


Acabo de empezar a tomar anticonceptivos. ¿Cuáles son los efectos secundarios más comunes?


Los efectos secundarios más comunes de las píldoras anticonceptivas incluyen:


1. Náuseas

2. Sero ternura

3. Dolores de cabeza

4. Aumento de peso

5. Cambios de estado de ánimo

6. manchado o sangrado innovador

7. Cambios en la libido 

8. acné 

9. Hinchazón 


Es importante tener en cuenta que cada persona puede experimentar diferentes efectos secundarios, y algunas personas pueden no experimentar ninguno. Si tiene preocupaciones sobre los efectos secundarios de su control de la natalidad, es mejor hablar con su proveedor de atención médica.

por Daisy / Vista | Comprar | Comprar con criptomoneda


¿Cómo alojo un servidor web desde mi casa?


Alojamiento de un servidor web desde su hogar se puede hacer siguiendo estos pasos:


1. Elija un software de servidor: puede elegir entre varias opciones de software del servidor como Apache, NGINX, Microsoft Internet Information Services (IIS), etc. Elija una que se adapte a sus requisitos.


2. Configure una dirección IP estática: comuníquese con su proveedor de servicios de Internet (ISP) y solicite una dirección IP estática para su conexión a Internet. Esto asegurará que su sitio web permanezca accesible incluso si su dirección IP cambia.


3. Configure su enrutador: inicie sesión en el panel de administración de su enrutador y reenvíe el puerto 80 (el puerto predeterminado para el tráfico HTTP) en la dirección IP interna de su servidor. Esto permitirá que el tráfico externo llegue a su servidor web.


4. Instale y configure el software del servidor: instale el software del servidor en su máquina del servidor y configúrelo de acuerdo con sus necesidades, como configurar hosts virtuales, certificados SSL, etc.


5. Probar su sitio web: verifique si se puede acceder a su sitio web ingresando su dirección IP estática en un navegador web. También puede probarlo utilizando herramientas en línea como Pingdom o Gtmetrix.


6. Configuración de nombre de dominio y DNS: registre un nombre de dominio para su sitio web y configure los registros DNS para señalar su dirección IP estática.


7. Medidas de seguridad: Implementar medidas de seguridad como firewalls, cifrado, copias de seguridad regulares, etc., para proteger su servidor web de las amenazas cibernéticas.


8. Monitoree y mantenga: monitoree regularmente su servidor para obtener problemas de rendimiento, amenazas de seguridad y actualizaciones de software. Mantenga actualizado el software y las aplicaciones de su servidor para garantizar un funcionamiento sin problemas.


Tenga en cuenta que alojar un servidor web desde su hogar puede no ser adecuado para sitios web de alto tráfico o datos confidenciales debido a riesgos de seguridad potenciales y un ancho de banda limitado. Considere utilizar un servicio de alojamiento web profesional para dichos requisitos.


por Daisy / Vista | Comprar | Comprar con criptomoneda


¿Cómo obtengo publicidad y tráfico orgánico para un sitio web?


1. Optimización de motores de búsqueda (SEO): optimice su sitio web para los motores de búsqueda para mejorar la visibilidad y la clasificación en las páginas de resultados del motor de búsqueda.


2. Marketing de contenido: cree contenido valioso y relevante que atraiga e involucre a su público objetivo. Esto puede incluir publicaciones de blog, artículos, videos, infografías y otras formas de contenido.


3. Marketing en redes sociales: promocione su sitio web en plataformas de redes sociales como Facebook, Twitter, Instagram y LinkedIn para llegar a un público más amplio e impulsar el tráfico a su sitio web.


4. Publicidad paga: considere ejecutar campañas de publicidad pagas en los motores de búsqueda (Google AdWords), plataformas de redes sociales y otros sitios web relevantes para impulsar el tráfico dirigido a su sitio web.


5. Marketing de influencers: asociarse con personas influyentes en su nicho para ayudar a promover su sitio web y llegar a un público más amplio.


6. Marketing por correo electrónico: cree una lista de correo electrónico de suscriptores y envíe actualizaciones regulares, promociones y contenido para llevar el tráfico a su sitio web.


7. Redes: Conéctese con otros propietarios de sitios web, blogueros e influencers en su industria para colaborar, publicar o intercambiar enlaces para aumentar la visibilidad de su sitio web.


8. Relaciones públicas: comuníquese con periodistas, bloggers y medios de comunicación para presentar historias o anuncios de interés periodístico relacionados con su sitio web para generar publicidad y tráfico.


9. Blogging invitado: escriba publicaciones de invitados de alta calidad para otros sitios web e incluya un enlace de regreso a su sitio web en la biografía o contenido del autor para impulsar el tráfico.


10. Comunidades y foros en línea: participe en comunidades y foros en línea relacionados con su nicho e interactúe con los miembros compartiendo ideas valiosas, respondiendo preguntas y promocionando su sitio web cuando sea relevante.

por Daisy / Vista | Comprar | Comprar con criptomoneda


¿Por qué fumar cigarrillos es peligroso?


Fumar cigarrillos es peligroso por varias razones:


1. Mayor riesgo de cáncer: fumar es la principal causa de varios tipos de cáncer, incluidos el pulmón, la garganta, la boca y el cáncer de vejiga.


2. Problemas respiratorios: el fumar daña los pulmones y puede provocar afecciones respiratorias crónicas como la enfermedad pulmonar obstructiva crónica (EPOC) y el enfisema.


3. Enfermedad cardíaca: fumar es un factor de riesgo importante para la enfermedad cardíaca, que incluye presión arterial alta, ataques cardíacos y accidente cerebrovascular.


4. Mayor riesgo de infecciones: el fumar debilita el sistema inmunitario, lo que hace que las personas sean más susceptibles a infecciones como la neumonía y la bronquitis.


5. Efectos nocivos sobre el embarazo: fumar durante el embarazo puede provocar complicaciones como el parto prematuro, el bajo peso al nacer y los defectos de nacimiento.


6. Smoke de segunda mano: fumar no solo perjudica al fumador, sino que también presenta un riesgo para la salud para quienes los rodean a través de la exposición al humo de segunda mano.


En general, fumar cigarrillos es peligroso porque aumenta significativamente el riesgo de desarrollar afecciones de salud graves y, en última instancia, puede conducir a la muerte prematura.


por Daisy / Vista | Comprar | Comprar con criptomoneda


¿Cómo escribo una publicación de blog profesional?


Escribir una publicación de blog profesional implica varios pasos clave para crear una pieza de contenido bien elaborada y atractiva. Aquí hay algunos consejos para ayudarlo a escribir una publicación de blog profesional:

1. Elija un tema relevante y atractivo: comience por identificar un tema relevante para su audiencia y que sea algo que sea conocedor y apasionado. Asegúrese de que el tema sea algo que interesará y resuene con sus lectores.

2. Realice una investigación exhaustiva: antes de comenzar a escribir, asegúrese de realizar una investigación exhaustiva sobre su tema elegido. Esto lo ayudará a recopilar información, estadísticas y hechos relevantes para respaldar sus puntos y hacer que su publicación de blog sea más creíble.

3. Cree un esquema: organice sus ideas y puntos clave creando un esquema para su publicación de blog. Esto lo ayudará a estructurar su contenido de una manera lógica y coherente, lo que facilita que los lectores sigan.

4. Escriba una introducción convincente: comience su publicación de blog con una introducción fuerte y atractiva que llame la atención del lector. Use un gancho para atraer a los lectores y hacer que quieran seguir leyendo.

5. Utilice un lenguaje claro y conciso: evite usar jerga o lenguaje demasiado técnico en su publicación de blog. Escriba de manera clara y concisa para que su contenido sea fácil de entender para todos los lectores.

6. Incluya imágenes: elementos visuales como imágenes, infografías y videos pueden ayudar a romper el texto y hacer que su publicación de blog sea atractiva visualmente. También pueden ayudar a apoyar sus puntos clave y hacer que su contenido sea más atractivo.

7. REDE y EDITAR: Antes de publicar la publicación de su blog, asegúrese de revisarla y editarla para errores de gramática, ortografía y formato. Considere pedirle a un colega o amigo que revise su publicación para recibir comentarios antes de publicarla.

8. Agregue una llamada a la acción: finalice su publicación de blog con un fuerte llamado a la acción que alienta a los lectores a interactuar con su contenido, como suscribirse a su blog, comentar o compartir su publicación en las redes sociales.

Siguiendo estos consejos, puede crear una publicación de blog profesional y atractiva que resuene con su audiencia y lo establecerá como autoridad en su campo.

por Daisy / Vista | Comprar | Comprar con criptomoneda


¿Cuál es la mejor manera de hervir los huevos?


Aquí tienes un método sencillo para hervir huevos:


1. Coloque los huevos en una cacerola y cúbrelos con agua fría.

2. Lleve el agua a ebullición a fuego alto.

3. Una vez que el agua esté hirviendo, reduzca el fuego a bajo y deje que los huevos hervan durante 9-12 minutos, dependiendo de qué tan bien hecho los desee.

4. Retire los huevos del fuego e inmediatamente transfiéralos a un tazón de agua helada para enfriar rápidamente.

5. Una vez enfriado, puede pelar y disfrutar de sus huevos perfectamente hervidos.


por Daisy / Vista | Comprar | Comprar con criptomoneda


¿Cómo envío un correo electrónico con una lista de correo electrónico compatible y los enlaces de cancelación de suscripción?


Para enviar un correo electrónico con una lista compatible y un enlace de cancelación más estricto, debe seguir estos pasos:


1. Asegúrese de que su lista de correo electrónico cumpla con todas las regulaciones relevantes, como la Ley CAN-SPAM y GDPR. Esto significa que todos los destinatarios deben haber optado por recibir sus correos electrónicos y que tiene su consentimiento explícito para contactarlos.


2. Incluya un enlace de cancelación claro y prominente en su correo electrónico. Asegúrese de que sea fácil de encontrar y hacer clic, y que lleve a los destinatarios directamente a una página donde puedan darse de baja de su lista de correo.


3. Para hacer que el enlace de cancelación de suscripción sea "más estricto", puede usar una opción de cancelación de suscripción de un solo clic. Esto significa que los destinatarios pueden darse de baja de sus correos electrónicos con solo un clic, sin tener que completar ningún formularios adicionales o proporcionar información personal.


4. Al enviar el correo electrónico, asegúrese de personalizar el mensaje y abordar al destinatario por su nombre si es posible. Esto puede ayudar a aumentar el compromiso y hacer que el correo electrónico se sienta más relevante para el destinatario.


5. Antes de enviar el correo electrónico, pruebe para asegurarse de que el enlace de cancelación de suscripción funcione correctamente y que el correo electrónico se vea bien en todos los dispositivos y clientes de correo electrónico.


Siguiendo estos pasos, puede enviar un correo electrónico con una lista de cumplimiento y un enlace de suspensión más estricto para garantizar que sus destinatarios tengan una experiencia positiva y puedan optar fácilmente por no recibir más correos electrónicos de usted.

por Daisy / Vista | Comprar | Comprar con criptomoneda



¿Cuáles son los beneficios de tomar espironolactona como mujer?


Spiro, o espironolactona, a menudo se prescribe a mujeres con desequilibrios hormonales. Algunos de los beneficios potenciales de tomar Spiro incluyen:


1. Tratamiento del acné: Spiro puede ayudar a reducir el acné al disminuir la producción de sebo, que puede obstruir los poros y conducir a brotes.


2. Reducción del crecimiento excesivo del cabello: Spiro puede ayudar a reducir el crecimiento excesivo del cabello, conocido como hirsutismo, al bloquear los efectos de las hormonas de los andrógenos.


3. Manejo de los desequilibrios hormonales: Spiro puede usarse para manejar afecciones como el síndrome de ovario poliquístico (PCOS) o desequilibrios hormonales que pueden estar causando irregularidades menstruales u otros síntomas.


4. Tratamiento de la presión arterial alta: Spiro es un diurético y puede ayudar a reducir la presión arterial al reducir la cantidad de sal y agua retenida en el cuerpo.


por Daisy / Vista | Comprar | Comprar con criptomoneda


¿Por qué la gente implanta los implantes de NFC en sus manos?


Hay varias razones por las cuales las personas eligen implantar implantes de NFC (comunicación cercana de campo) en sus manos:


1. Conveniencia: los implantes de NFC permiten a las personas acceder fácilmente a la información, abrir puertas, realizar pagos y realizar otras tareas con una simple ola de su mano. Esto puede ser más conveniente que llevar llaves, tarjetas de identificación o teléfonos inteligentes.


2. Seguridad: los implantes de NFC pueden proporcionar una capa adicional de seguridad, ya que requieren acceso físico al cuerpo del individuo para activarse. Esto puede ayudar a prevenir el acceso no autorizado a dispositivos o información confidencial.


3. Experimentación tecnológica: algunas personas eligen implantar chips NFC como una forma de experimentar con tecnologías emergentes e integrarlas en su vida cotidiana.


4. Identificación personal: los implantes de NFC pueden usarse para fines de identificación personal, como almacenar información médica o datos de contacto a los que se puede acceder fácilmente en caso de emergencias.


5. Biohacking: algunas personas ven los implantes de NFC como una forma de biohacking, donde aumentan sus cuerpos con tecnología para mejorar sus capacidades o experiencias.


En general, la decisión de implantar chips NFC en sus manos es una elección personal que varía de persona a persona en función de sus preferencias y creencias individuales.


comprar

por Daisy / Vista | Comprar | Comprar con criptomoneda


¿Qué causa la migraña y cómo se tratan?


Las migrañas son dolores de cabeza severos que a menudo van acompañados de otros síntomas como náuseas, sensibilidad a la luz y el sonido, y las alteraciones visuales. La causa exacta de las migrañas no se entiende por completo, pero se cree que está relacionada con los cambios en el flujo sanguíneo y los productos químicos en el cerebro.


El tratamiento para las migrañas generalmente implica una combinación de cambios en el estilo de vida, medicamentos y terapias alternativas. Algunas opciones de tratamiento comunes incluyen:


1. Tomar analgésicos de venta libre como el ibuprofeno o el acetaminofén

2. Medicamentos recetados diseñados específicamente para tratar las migrañas, como triptans y ergotaminas

3. Evitar desencadenantes como ciertos alimentos, estrés, falta de sueño o cambios hormonales

4. Practicar técnicas de relajación como respiración profunda o meditación

5. Aplicar paquetes calientes o fríos en la cabeza o el cuello

6. Hacer ejercicio regularmente y mantener una dieta saludable


Es importante que las personas que sufren de migrañas trabajen con su proveedor de atención médica para desarrollar un plan de tratamiento que se adapte a sus necesidades y desencadenantes específicos. En algunos casos, puede ser necesaria una combinación de terapias para controlar de manera efectiva las migrañas y mejorar la calidad de vida.

por Daisy / Vista | Comprar | Comprar con criptomoneda


¿Cuáles son los beneficios de tomar progesterona?


1. Regula el ciclo menstrual: la progesterona juega un papel clave en la regulación del ciclo menstrual y puede ayudar a restaurar el equilibrio para personas con períodos irregulares.


2. Apoya la fertilidad: la progesterona es esencial para mantener un embarazo saludable al preparar el útero para la implantación y apoyar el crecimiento del feto.


3. Ayuda a equilibrar las hormonas: la progesterona funciona en armonía con estrógeno para mantener el equilibrio hormonal en el cuerpo, lo que puede ayudar a aliviar los síntomas de los desequilibrios hormonales como el PMS, la menopausia y el PCOS.


4. Mejora el estado de ánimo: se ha demostrado que la progesterona tiene un efecto calmante en el cerebro y puede ayudar a reducir los síntomas de ansiedad y depresión.


5. Apoya la salud ósea: la progesterona funciona con otras hormonas como el estrógeno y la testosterona para apoyar la densidad ósea y reducir el riesgo de osteoporosis.


6. Mejora el sueño: la progesterona puede ayudar a regular el ciclo de sueño-vigilia y mejorar la calidad del sueño.


7. Apoya la salud de la piel: la progesterona puede tener un efecto positivo en la salud de la piel al promover la producción de colágeno y reducir la inflamación.


8. Reduce el riesgo de ciertos cánceres: se ha demostrado que la progesterona tiene un efecto protector contra ciertos tipos de cáncer, como el cáncer de endometrio.


Es importante tener en cuenta que la progesterona debe usarse bajo la guía de un proveedor de atención médica, ya que puede tener efectos secundarios e interacciones con otros medicamentos.


por Daisy / Vista | Comprar | Comprar con criptomoneda


¿Cuáles son los beneficios de tener una cámara de seguridad?


1. Deterrencia de la actividad criminal: las cámaras de seguridad pueden actuar como un elemento disuasorio para los posibles delincuentes, ya que es menos probable que cometan un delito si saben que están siendo observados.


2. Vigilancia y monitoreo: las cámaras de seguridad le permiten monitorear su propiedad y vigilar cualquier actividad sospechosa en tiempo real, ayudando a prevenir el robo, el vandalismo u otros delitos.


3. Evidencia En caso de un delito: en el desafortunado caso de que ocurra un delito en su propiedad, las imágenes de la cámara de seguridad pueden proporcionar evidencia crucial para la aplicación de la ley y las reclamaciones de seguros.


4. Acceso remoto: muchas cámaras de seguridad ahora ofrecen capacidades de visualización remota, lo que le permite registrarse en su propiedad desde cualquier lugar utilizando su teléfono inteligente o computadora.


5. Paz mental: tener cámaras de seguridad instaladas puede proporcionar tranquilidad, sabiendo que su propiedad está siendo monitoreada y que se están detectando y registrando posibles amenazas.


por Daisy / Vista | Comprar | Comprar con criptomoneda


¿Cómo está creciendo el mercado criptográfico tan rápido?


Hay varios factores que contribuyen al rápido crecimiento del mercado de criptomonedas. 


1. Mayor conciencia y adopción: a medida que más personas se dan cuenta de las criptomonedas y sus beneficios potenciales, la demanda de inversiones de criptomonedas ha crecido significativamente. Este mayor interés ha llevado a un aumento en el número de usuarios e inversores que participan en el mercado.


2. Participación institucional: en los últimos años, hemos visto un número creciente de inversores institucionales, como fondos de cobertura, bancos y otras instituciones financieras, involucrados en el mercado de criptomonedas. Esto ha agregado credibilidad al mercado y atrajo aún más inversores.


3. Avances tecnológicos: los desarrollos tecnológicos en el espacio blockchain han facilitado la creación y comercialización de nuevas criptomonedas. Además, los avances en medidas de seguridad y marcos regulatorios han hecho que el mercado sea más atractivo para los inversores.


4. Volatilidad del mercado: la naturaleza altamente volátil del mercado de criptomonedas ha atraído a comerciantes e inversores que buscan capitalizar las fluctuaciones de precios y obtener ganancias significativas en un período de tiempo relativamente corto.


5. Aceptación global: las criptomonedas ahora son aceptadas como una forma de pago por un número creciente de comerciantes y empresas de todo el mundo. Esto ha ayudado a legitimar las criptomonedas como una alternativa viable a las monedas fiduciarias tradicionales.


En general, estos factores han contribuido al rápido crecimiento del mercado de criptomonedas y es probable que continúen impulsando su expansión en el futuro.


por Daisy / Vista | Comprar | Comprar con criptomoneda


¿El azúcar es realmente poco saludable?


El consumo excesivo de azúcar puede conducir a diversos problemas de salud, como aumento de peso, obesidad, diabetes, enfermedades cardíacas y problemas dentales. Se recomienda limitar la ingesta de azúcares agregados en nuestra dieta para mantener una buena salud. Sin embargo, los azúcares naturales que se encuentran en las frutas y verduras no se consideran dañinas en cantidades moderadas y pueden ser parte de una dieta saludable. La moderación es clave cuando se trata de consumo de azúcar.


por Daisy / Vista | Comprar | Comprar con criptomoneda


¿Cómo tomo las mejores fotos de mí mismo?


1. Iluminación: la luz natural siempre es la mejor para tomar fotos. Posicione frente a una ventana o salga para aprovechar la luz solar natural. Evite la iluminación dura por encima o la luz solar directa, ya que puede crear sombras poco halagadoras en su cara.


2. Antecedentes: elija un fondo limpio y ordenado para evitar distracciones en sus fotos. Una pared simple, un escenario al aire libre o un telón de fondo simple puede funcionar bien para resaltar en la foto.


3. Pose: experimente con diferentes poses para encontrar lo que más halagará sus características. Evite ángulos incómodos y, en su lugar, trate de alargar el cuello e inclinar la cabeza ligeramente para crear un aspecto más halagador.


4. Composición: Presta atención a la composición de tus fotos. Use la regla de los tercios colocándose fuera del centro en el marco para crear una imagen más atractiva visualmente. También puede experimentar con diferentes ángulos y perspectivas para agregar interés a sus fotos.


5. Sonrisa y expresión: una sonrisa genuina puede elevar instantáneamente tus fotos. Relájate tu rostro, piensa en algo que te haga feliz y deja que tu sonrisa natural brille. Además, pruebe diferentes expresiones faciales para transmitir diferentes estados de ánimo y emociones en sus fotos.


6. Use un temporizador o un palo selfie: para obtener una toma estable y bien compuesta, considere usar un temporizador en su cámara o un palo selfie para extender su alcance y capturar un marco más amplio. Esto lo ayudará a evitar selfies borrosas o poco halagadoras.


7. Edite sus fotos: después de tomar sus fotos, use herramientas o aplicaciones de edición de fotos para mejorar los colores, la iluminación y el aspecto general de sus imágenes. Puede ajustar el brillo, el contraste y la saturación para que sus fotos estén.


Recuerde, la práctica hace la perfección, así que no tenga miedo de experimentar y divertirse mientras tome fotos de usted mismo.


por Daisy / Vista | Comprar | Comprar con criptomoneda



¿Cómo encuentro clientes para mi pequeña empresa de desarrollo web?


Aquí hay algunas estrategias que puede usar para atraer clientes para su negocio de desarrollo web:


1. Cree una fuerte presencia en línea: cree un sitio web profesional que muestre sus servicios, cartera y testimonios de clientes. Use los canales de redes sociales para promocionar su negocio e interactuar con clientes potenciales.


2. Red: asistir a eventos de la industria, conferencias y reuniones para conectarse con otros profesionales en el campo y los clientes potenciales. Únase a las comunidades y foros en línea relacionados con el desarrollo web para expandir su red.


3. Ofrezca incentivos de referencia: aliente a los clientes satisfechos a remitir sus servicios a otros ofreciendo descuentos u otros incentivos para referencias exitosas.


4. Colabora con otras empresas: asociarse con agencias de marketing digital, diseñadores gráficos u otros profesionales que puedan necesitar servicios de desarrollo web para sus clientes.


5. Anuncie: invierta en publicidad en línea a través de Google AdWords, anuncios de redes sociales o anuncios de visualización para llegar a un público más amplio.


6. Alcance en frío: comuníquese con clientes potenciales directamente a través del correo electrónico o el teléfono, mostrando sus servicios y trabajos anteriores.


7. Marketing de contenidos: cree contenido valioso como publicaciones de blog, blancos blancos o seminarios web que demuestren su experiencia en desarrollo web y atraen a clientes potenciales a través de motores de búsqueda y redes sociales.


8. Asistir a ferias y eventos: participe en ferias y eventos comerciales de la industria para conectarse con clientes potenciales y mostrar sus servicios.


9. Ofrezca consultas gratuitas: brinde consultas gratuitas a clientes potenciales para discutir sus necesidades y cómo sus servicios pueden ayudarlos a alcanzar sus objetivos.


10. Solicite revisiones y testimonios: aliente a los clientes satisfechos a dejar revisiones y testimonios en su sitio web u otras plataformas de revisión para generar credibilidad y atraer nuevos clientes.


por Daisy / Vista | Comprar | Comprar con criptomoneda


¿Cómo construyo un servidor de correo con Postfix?


Para construir un servidor de correo con Postfix, siga estos pasos:


1. Instale Postfix: use su Administrador de paquetes para instalar Postfix en su servidor. Por ejemplo, en Debian/Ubuntu, puede ejecutar `sudo apt-get install posfix`.


2. Configurar los archivos de configuración Postfix: Postfix se encuentran en `/etc/postfix/`. El archivo de configuración principal es `main.cf`. Puede editar este archivo para configurar su servidor de correo de acuerdo con sus requisitos. Algunas configuraciones comunes que es posible que deba establecer incluyen el nombre de dominio, la configuración de retransmisión de correo, los dominios virtuales, etc.


3. Configure los registros DNS: para garantizar la entrega de correo, debe configurar los registros DNS necesarios (registros MX y SPF) para su dominio. Póngase en contacto con su registrador de dominio o proveedor de DNS para obtener ayuda si es necesario.


4. Configure los dominios y usuarios virtuales: si desea alojar múltiples dominios en su servidor de correo, deberá configurar dominios y usuarios virtuales. Esto se puede hacer utilizando la configuración `virtual_alias_maps` y` virtual_mailbox_maps` en el archivo de configuración Postfix.


5. Asegure su servidor de correo: asegúrese de que su servidor de correo esté seguro configurando reglas de firewall, utilizando el cifrado TLS para el correo entrante y saliente, e implementando otras medidas de seguridad recomendadas para servidores de correo.


6. Pruebe su servidor de correo: una vez que todo está configurado, debe probar su servidor de correo enviando y recibiendo correos electrónicos de prueba. Use herramientas como Telnet o Mailx para enviar correos electrónicos manualmente y verificar si se reciben correctamente.


Recuerde actualizar y mantener su servidor de correo periódicamente para asegurarse de que se ejecute sin problemas y de forma segura. También es una buena idea monitorear los registros del servidor de correo para cualquier problema o actividad sospechosa.

por Daisy / Vista | Comprar | Comprar con criptomoneda


¿Cómo tomo las mejores fotos de mí mismo?


1. Iluminación: la luz natural siempre es la mejor para tomar fotos. Posicione frente a una ventana o salga para aprovechar la luz solar natural. Evite la iluminación dura por encima o la luz solar directa, ya que puede crear sombras poco halagadoras en su cara.


2. Antecedentes: elija un fondo limpio y ordenado para evitar distracciones en sus fotos. Una pared simple, un escenario al aire libre o un telón de fondo simple puede funcionar bien para resaltar en la foto.


3. Pose: experimente con diferentes poses para encontrar lo que más halagará sus características. Evite ángulos incómodos y, en su lugar, trate de alargar el cuello e inclinar la cabeza ligeramente para crear un aspecto más halagador.


4. Composición: Presta atención a la composición de tus fotos. Use la regla de los tercios colocándose fuera del centro en el marco para crear una imagen más atractiva visualmente. También puede experimentar con diferentes ángulos y perspectivas para agregar interés a sus fotos.


5. Sonrisa y expresión: una sonrisa genuina puede elevar instantáneamente tus fotos. Relájate tu rostro, piensa en algo que te haga feliz y deja que tu sonrisa natural brille. Además, pruebe diferentes expresiones faciales para transmitir diferentes estados de ánimo y emociones en sus fotos.


6. Use un temporizador o un palo selfie: para obtener una toma estable y bien compuesta, considere usar un temporizador en su cámara o un palo selfie para extender su alcance y capturar un marco más amplio. Esto lo ayudará a evitar selfies borrosas o poco halagadoras.


7. Edite sus fotos: después de tomar sus fotos, use herramientas o aplicaciones de edición de fotos para mejorar los colores, la iluminación y el aspecto general de sus imágenes. Puede ajustar el brillo, el contraste y la saturación para que sus fotos estén.


Recuerde, la práctica hace la perfección, así que no tenga miedo de experimentar y divertirse mientras tome fotos de usted mismo.


por Daisy / Vista | Comprar | Comprar con criptomoneda


¿Cómo escribo un buen libro?


1. Desarrolle una idea o concepto claro: antes de comenzar a escribir, asegúrese de tener una idea sólida para su libro. Esto podría ser una trama, personaje, tema o escenario que desea explorar en su escritura.


2. Cree un esquema: describe los puntos principales de la trama, los personajes y los temas de su libro antes de comenzar a escribir. Esto lo ayudará a mantenerse organizado y enfocado mientras escribe.


3. Reserve tiempo dedicado para escribir: Establezca una rutina para escribir y deje de lado el tiempo dedicado cada día para trabajar en su libro. Esto lo ayudará a mantenerse motivado y progresar en su escritura.


4. Solo comienza a escribir: a veces la parte más difícil de escribir un libro es comenzar. No se preocupe por la perfección en esta etapa, simplemente comience a escribir y obtenga sus ideas en papel.


5. Únase a un grupo o comunidad de escritura: considere unirse a un grupo de escritura o comunidad para obtener apoyo, comentarios y motivación. Escribir puede ser una búsqueda solitaria, por lo que tener una comunidad de compañeros escritores puede ser invaluable.


6. Editar y revisar: una vez que haya completado un borrador de su libro, regrese y revise y edite para mejorar la claridad, la estructura y el flujo de su escritura. Esto puede involucrar múltiples borradores y revisiones antes de que su libro esté listo para su publicación.


7. Busque comentarios: comparta su trabajo con otros, como lectores beta, grupos de escritura o editores profesionales, para obtener comentarios sobre su escritura. Esto puede ayudarlo a identificar áreas para mejorar y fortalecer su libro.


8. Sigue escribiendo: escribir un libro es un maratón, no un sprint. Sigue avanzando, permaneciendo dedicado y continuando trabajando en tu libro hasta que esté completo.


por Daisy / Vista | Comprar | Comprar con criptomoneda




https://glamgirlx.com -


(Haga clic o toque para descargar la imagen)
Entretenimiento profesional, fotos, videos, audio, transmisión en vivo y juego casual, así como escaneo de identificación, desarrollo web y servicios de subrogación.

Déjame un consejo en Bitcoin usando esta dirección: 3KhDWoSve2N627RiW8grj6XrsoPT7d6qyE

© Glam Girl X 2025

Términos de servicio