Vista html de cierre de sesión de Stargazer. Iniciar y cerrar sesión vistas

04.08.2021

Principalmente para desarrollar interfaces de usuario. Para usarlo, necesita crear un tipo de Modelo que represente el estado completo del programa, un tipo de Mensaje que describa eventos ambientales externos a los que el programa debe responder cambiando su estado, una función de actualización que cree un nuevo estado del programa del estado y mensaje antiguos, y una función de visualización que, en función del estado del programa, calcula los impactos requeridos en el entorno externo, que generan eventos del tipo Mensaje. El patrón es muy conveniente, pero tiene un pequeño inconveniente: no permite describir qué eventos tienen sentido para estados específicos del programa.

Un problema similar surge (y se resuelve) cuando se utiliza el patrón State OO.

El lenguaje Elm es simple, pero muy estricto: verifica que la función de actualización maneje de alguna manera todas las combinaciones posibles de modelo-estado y eventos de mensaje. Por lo tanto, hay que escribir código adicional, aunque trivial, que normalmente deja el modelo sin cambios. Quiero demostrar cómo se puede evitar esto en lenguajes más complejos: Idris, Scala, C++ y Haskell.

Todo el código que se muestra aquí está disponible en GitHub para experimentación. Echemos un vistazo a los lugares más interesantes.


La función msg es inusual: devuelve un tipo, no un valor. Durante la ejecución, no se sabe nada sobre los tipos de valores: el compilador borra toda la información innecesaria. Es decir, dicha función sólo se puede llamar en la etapa de compilación.

MUV es un constructor. Acepta parámetros: modelo: el estado inicial del programa, actualizador: una función para actualizar el estado ante un evento externo y vista: una función para crear una vista externa. Tenga en cuenta que el tipo de funciones de actualización y visualización depende del valor del modelo (usando la función msg de los parámetros de tipo).

Ahora veamos cómo iniciar esta aplicación.

MuvRun: (modelo de aplicaciónTipo msgTipo IO) -> IO a muvRun (vista del actualizador del modelo MUV) = hacer mensaje<- view model muvRun (MUV (updater model msg) updater view)
Elegimos una operación de entrada/salida como una representación externa (vista) (en Idris, como en Haskell, las operaciones de entrada/salida son valores de primera clase; para que se ejecuten, se deben tomar acciones adicionales, generalmente devolviendo dicha operación). de la función principal).

Brevemente sobre IO

Al realizar una operación de tipo (IO a), se produce algún impacto en el mundo exterior, posiblemente vacío, y se devuelve un valor de tipo a al programa, pero las funciones de la biblioteca estándar están diseñadas de tal manera que puede sólo se procesará generando un nuevo valor de tipo IO b. De esta forma se separan las funciones puras de las funciones con efectos secundarios. Esto es inusual para muchos programadores, pero ayuda a escribir código más confiable.


Dado que la función muvRun genera E/S, debería devolver IO, pero como nunca se completará, el tipo de operación puede ser cualquier cosa: IO a.

Ahora describamos los tipos de entidades con las que vamos a trabajar.

Modelo de datos = Cerrado sesión | Datos de cadena conectados MsgOuted = Datos de cadena de inicio de sesión MsgIned = Cerrar sesión | Saludo total msgType: Modelo -> Tipo msgType Cerrado = MsgOuted msgType (Iniciado _) = MsgIned
Aquí describimos un tipo de modelo que refleja la presencia de dos estados de interfaz: el usuario no ha iniciado sesión y el usuario con un nombre de tipo String sí ha iniciado sesión.

A continuación describimos dos diferentes tipos de mensajes relevantes para diferentes variantes del modelo: si estamos desconectados, solo podemos iniciar sesión con un nombre determinado, y si ya estamos conectados, podemos cerrar sesión o saludar. Idris es un lenguaje fuertemente tipado que no permitirá la posibilidad de mezclar diferentes tipos.

Y finalmente, una función que establece la correspondencia del valor del modelo con el tipo de mensaje.

La función se declara total, es decir, no debería fallar ni congelarse, el compilador intentará monitorear esto. msgType se llama en el momento de la compilación, y su totalidad significa que la compilación no se congelará debido a nuestro error, aunque no puede garantizar que la ejecución de esta función agote los recursos del sistema.
También se garantiza que no ejecutará "rm -rf /" porque no hay IO en su firma.

Describamos el actualizador:

Actualizador total: (m:Model) -> (msgType m) -> Actualizador de modelo Cerrado (nombre de inicio de sesión) = Actualizador de nombre registrado (nombre de inicio de sesión) Cerrar sesión = Actualizador desconectado (nombre de inicio de sesión) Saludo = Nombre de inicio de sesión
Creo que la lógica de esta función es clara. Me gustaría señalar una vez más la totalidad: significa que el compilador de Idris comprobará que hemos considerado todas las alternativas permitidas por el sistema de tipos. Elm también realiza esta verificación, pero no puede saber que no podemos cerrar sesión si aún no hemos iniciado sesión, y requerirá un procesamiento explícito de la condición.

Actualizador Cerrado Cerrar sesión = ???
Idris encontrará discrepancias de tipos en una comprobación innecesaria.

Ahora pasemos a la vista; como es habitual en la interfaz de usuario, esta será la parte más difícil del código.

Total loginPage: IO MsgOuted loginPage = do putStr "Iniciar sesión: " map Iniciar sesión getLine total genMsg: String -> MsgIned genMsg "" = Cerrar sesión genMsg _ = Saludar a total workPage: String -> IO MsgIned workPage nombre = do putStr ("Hola, " ++ nombre ++ "\n") putStr "Ingrese una cadena vacía para cerrar sesión o no vacía para saludar\n" mapa genMsg getLine vista total: (m: Modelo) -> IO (msgType m) vista Cerrado de sesión = vista de página de inicio de sesión (nombre de inicio de sesión ) = nombre de la página de trabajo
La vista debe crear una operación de E/S que devuelva mensajes, cuyo tipo nuevamente depende del valor del modelo. Tenemos dos opciones: loginPage, que imprime un mensaje "Iniciar sesión:", lee una cadena del teclado y la envuelve en un mensaje de inicio de sesión, y página de trabajo con un parámetro de nombre de usuario, que imprime un saludo y devuelve mensajes diferentes (pero del mismo tipo). - MsgIned) dependiendo de si el usuario ingresa una cadena vacía o no vacía. view devuelve una de estas operaciones dependiendo del valor del modelo, y el compilador verifica su tipo, aunque sea diferente.

Ahora podemos crear y ejecutar nuestra aplicación.

Aplicación: Modelo de aplicación Main.msgType Aplicación IO = MUV Vista del actualizador desconectado principal: IO () principal = aplicación muvRun
Cabe señalar aquí un punto sutil: la función muvRun devuelve IO un, donde no se especificó a y el valor main es de tipo E/S(), Dónde () es el nombre de un tipo generalmente llamado Unidad, que tiene un valor único, también escrito como una tupla vacía () . Pero el compilador puede manejar esto fácilmente. sustituyendo a() en su lugar.

Scala y tipos dependientes de la ruta

Scala no tiene soporte completo para tipos dependientes, pero hay tipos que dependen de la instancia del objeto a través del cual se hace referencia (tipos dependientes de ruta). En la teoría de los tipos dependientes, pueden describirse como una variante del tipo sigma. Los tipos dependientes de la ruta permiten prohibir la suma de vectores de diferentes espacios vectoriales o describir quién puede besar a quién. Pero los usaremos para tareas más sencillas.

Clase abstracta sellada Clase de caso MsgLogined Login (nombre: Cadena) extiende la clase abstracta sellada MsgLogouted Clase de caso MsgLogined Logout() extiende la clase de caso MsgLogined Greet() extiende la clase abstracta MsgLogined Ver (def run(): Msg) Clase abstracta sellada Modelo (tipo Mensaje def view(): Ver) clase de caso Cerrado de sesión() extiende el modelo (tipo Mensaje = MsgLogined anulación def view(): Ver....) clase de caso Cerrado de sesión (nombre: Cadena) extiende el modelo (tipo Mensaje = MsgLogined anulación def view( ) : Vista .... )
Los tipos algebraicos en Scala se modelan mediante herencia. El tipo corresponde a algunos clase abstracta sellada, y cada constructor heredado de él clase de caso. Intentaremos usarlos exactamente como tipos algebraicos, describiendo todas las variables como pertenecientes al padre. clase abstracta sellada.

Las clases MsgLogined y MsgLogouted dentro de nuestro programa no tienen un ancestro común. La función de vista tenía que distribuirse entre diferentes clases del modelo para tener acceso a un tipo específico de mensaje. Esto tiene sus ventajas, que los partidarios de OO apreciarán: el código está agrupado de acuerdo con la lógica empresarial, todo lo relacionado con un caso de uso está cerca. Pero prefiero separar la vista en una función separada, cuyo desarrollo podría transferirse a otra persona.

Ahora implementemos el actualizador.

Actualizador de objetos (def actualización(modelo: Modelo)(msg: modelo.Mensaje): Modelo = (coincidencia de modelo (caso Cerrar sesión() => coincidencia de mensaje (caso Iniciar sesión(nombre) => Iniciar sesión(nombre)) caso Iniciar sesión(nombre) => coincidencia de mensaje ( caso Cerrar sesión() => Cerrar sesión() caso Saludar() => modelo ) ) ) )
Aquí utilizamos tipos dependientes de la ruta para describir el tipo del segundo argumento a partir del valor del primero. Para que Scala acepte tales dependencias, las funciones deben describirse en forma curry, es decir, como una función del primer argumento, que devuelve una función del segundo argumento. Desafortunadamente, Scala no realiza muchas comprobaciones de tipos en este momento para las cuales el compilador tenga suficiente información.

Ahora demos una implementación completa del modelo y veamos.

La clase de caso Logoouted() extiende el modelo ( tipo Mensaje = MsgLogouted anula def view() : Vista = nueva Vista ( anula def run() = ( println("Ingrese nombre ") val nombre = scala.io.StdIn.readLine() Iniciar sesión (nombre) ) ) clase de caso Iniciado sesión (nombre: Cadena) extiende el modelo (tipo Mensaje = MsgLogined override def view() : Vista = nueva Vista ( override def run() = ( println(s"Hola, $nombre") println ( "Cadena vacía para cerrar sesión, no vacía para saludar".) scala.io.StdIn.readLine() match ( case "" => Cerrar sesión() case _ => Greet() ) ) ) vista de clase abstracta ( def run() : Msg) Visor de objetos (def vista(modelo: Modelo): Vista = (model.view()))
El tipo de retorno de una función de vista depende de la instancia de su argumento. Pero para la implementación se recurre al modelo.

La aplicación creada así se inicia así:

Objeto principal ( import scala.annotation.tailrec @tailrec def proceso(m: Modelo) ( val msg = Viewer.view(m).run() proceso(Updater.update(m)(msg)) ) def principal(args: Matriz) = (proceso (cerrado sesión ())))
Por tanto, el código del sistema de ejecución no sabe nada sobre la estructura interna de los modelos y tipos de mensajes, pero el compilador puede comprobar que el mensaje coincide con el modelo actual.

Aquí no necesitábamos todas las capacidades proporcionadas por los tipos dependientes de la ruta. Aparecerán propiedades interesantes si trabajamos en paralelo con varias instancias de sistemas Model-Updater-View, por ejemplo, al simular un mundo de múltiples agentes (la vista entonces representaría la influencia del agente en el mundo y la recepción de retroalimentación). En este caso, el compilador comprobó que el mensaje fue procesado exactamente por el agente al que estaba destinado, a pesar de que todos los agentes son del mismo tipo.

C++

C++ sigue siendo sensible al orden de las definiciones, incluso si todas están hechas en el mismo archivo. Esto crea algunos inconvenientes. Presentaré el código en una secuencia conveniente para demostrar ideas. Puede encontrar una versión compilable en GitHub.

Los tipos algebraicos se pueden implementar de la misma manera que en Scala: una clase abstracta corresponde a un tipo y los descendientes concretos corresponden a constructores (llamémoslos "clases constructoras", para no confundirlos con los constructores ordinarios de C++) del sistema algebraico. tipo.

C++ admite tipos dependientes de la ruta, pero el compilador no puede usar el tipo en abstracto sin conocer el tipo real al que está asociado. Por lo tanto, es imposible implementar Model-Updater-View con su ayuda.

Pero C++ tiene un poderoso sistema de plantillas. La dependencia del tipo del valor del modelo se puede ocultar en un parámetro de plantilla de una versión especializada del sistema ejecutivo.

Procesador de estructura (procesador constante virtual *next() const = 0;); plantilla estructura ProcessorImpl: Procesador público ( const CurModel * modelo; ProcessorImpl (const CurModel* m): modelo(m) ( ); const Procesador *next() const (const Ver * vista = modelo->vista(); const nombre de tipo CurModel::Mensaje * msg = ver->ejecutar(); eliminar vista; const Modelo * nuevoModelo = mensaje->proceso(modelo); borrar mensaje; devolver nuevoModelo->procesador(); ) );
Describimos un sistema de ejecución abstracto, con un único método para hacer lo que sea necesario y devolver un nuevo sistema de ejecución adecuado para la siguiente iteración. La versión específica tiene un parámetro de plantilla y estará especializada para cada "clase de constructor" del modelo. Es importante aquí que todas las propiedades del tipo CurModel se verifiquen durante la especialización de la plantilla con un parámetro de tipo específico, y en el momento de compilar la plantilla en sí, no es necesario describirlas (aunque es posible usando conceptos u otras formas de implementar clases de tipos). Scala también tiene un sistema bastante potente de tipos parametrizados, pero comprueba las propiedades de los tipos de parámetros durante la compilación del tipo parametrizado. Allí, la implementación de dicho patrón es difícil, pero posible gracias al soporte de clases de tipos.

Describamos el modelo.

Modelo de estructura ( virtual ~Model() (); virtual const Procesador *procesador() const = 0; ); struct Iniciado sesión: modelo público ( struct Mensaje ( const modelo virtual * proceso (const iniciado sesión * m) const = 0; virtual ~Message() (); struct Cerrar sesión: mensaje público ( const Modelo * proceso (const iniciado sesión * m) const; struct Saludo: Mensaje público ( const Modelo * proceso (const Iniciado sesión * m) const; ); const std::string nombre; (...); vista constante * view() const ( devuelve nuevo LoginedView(nombre); ); const Procesador *procesador() const (devuelve nuevo ProcessorImpl (este); (...); vista constante ); ); struct Cerró sesión: Modelo público ( struct Mensaje ( const virtual Modelo * proceso (const Cerró sesión * m) const = 0; virtual ~Message() (); struct Inicio de sesión: Mensaje público ( const std::nombre de cadena; Iniciar sesión(std :: cadena lname): nombre (lname) (); const Modelo * proceso (const Cerrado de sesión * m) const; * view() const ( devuelve nueva LogooutedView(); ); const Procesador *procesador() const (devuelve nuevo ProcessorImpl
(este);

); );

Modelo constante * Cerrado de sesión::Inicio de sesión::proceso(const Cerrado de sesión * m) const (eliminar m; devolver nuevo Cerrado de sesión(nombre); ); const Modelo * Iniciado sesión::Cerrar sesión::proceso(const Iniciar sesión * m) const ( eliminar m; devolver nuevo Cerrar sesión(); ); const Modelo * Iniciado sesión::Saludo::proceso(const Iniciado sesión * m) const ( return m; );
Ahora juntemos todo lo relacionado con la vista, incluidas las entidades internas de los modelos.

Plantilla estructura Vista (virtual constante Mensaje * ejecutar() const = 0; virtual ~Ver () (); ); struct Iniciado sesión: modelo público (struct LoginedView: Vista pública ( const std::nombre de cadena; LoginedView(std::string lname) : nombre(lname) (); virtual const Mensaje * run() const ( char buf; printf("Hola %s", nombre.c_str()) ; fgets(buf, 15, stdin); retorno (*buf == 0 || *buf == "\n" || *buf == "\r") ? (nuevo cerrar sesión()): static_cast (nuevo saludo); ); ); vista constante * view() const ( devuelve nuevo LoginedView(nombre); ); ); estructura cerrada sesión: modelo público (estructura cerrada sesión: vista pública ( virtual const Mensaje * run() const ( char buf; printf("Iniciar sesión: "); fgets(buf, 15, stdin); devolver nuevo inicio de sesión(buf); ); ); vista constante * view() const ( devuelve nueva LogooutedView(); ); );
Y finalmente, escribamos principal.

Int main(int argc, char ** argv) (const Procesador * p = nuevo ProcessorImpl (nuevo Cerrado de sesión()); while(verdadero) ( ​​const Procesador * pnew = p->next(); eliminar p; p = pnew; ) devuelve 0; )

Y nuevamente Scala, esta vez con clases de tipos.

En estructura, esta implementación replica casi por completo la versión C++.

Parte similar del código.

clase abstracta Vista ( def run(): Mensaje ) clase abstracta Procesador ( def next(): Procesador; ) clase abstracta sellada Modelo ( def procesador(): Procesador ) clase abstracta sellada LoginedMessage clase de caso Logout() extiende la clase de caso LoginedMessage Greet( ) extiende la clase de caso LoginedMessage Logined (nombre de valor: Cadena) extiende el Modelo ( anula el procesador def(): Procesador = nuevo ProcessorImpl(this) ) clase abstracta sellada Clase de caso LogoutedMessage Inicio de sesión (nombre: Cadena) extiende la clase de caso LoginedMessage Logouted() extiende el Modelo ( anular def procesador(): Procesador = nuevo ProcessorImpl(this) ) objeto Principal ( import scala.annotation.tailrec @tailrec def proceso(p: Procesador) ( proceso(p.next()) ) def principal(args: Matriz) = ( proceso (nuevo procesadorImpl (cerrado sesión ()))))


Pero en la implementación del entorno de ejecución surgen sutilezas.

Clase ProcessorImpl(modelo: M)(actualizador implícito: (M, Mensaje) => Modelo, vista: M => Ver) extiende el Procesador ( def next(): Procesador = ( val v = vista(modelo) val msg = v. ejecutar() val nuevoModelo = actualizador(modelo,msg) nuevoModelo.procesador() ) )
Aquí vemos nuevos parámetros misteriosos. (actualizador implícito: (M, Mensaje) => Modelo, vista: M => Ver). La palabra clave implícita significa que al llamar a esta función (más precisamente, al constructor de la clase), el compilador buscará objetos de tipos adecuados marcados como implícitos en el contexto y los pasará como parámetros apropiados. Este es un concepto bastante complejo, una de cuyas aplicaciones es la implementación de clases de tipos. Aquí le prometen al compilador que para implementaciones específicas del modelo y mensaje, nosotros proporcionaremos todas las funciones necesarias. Ahora cumplamos esta promesa.

Actualizadores de objetos (implícito def logoutedUpdater(modelo: Logoouted, msg: LogoutedMessage): Modelo = ((modelo, msg) match ( case (Logouted(), Login(name)) => Logined(name) ) ) implícito def viewLogouted(modelo : Cerrado de sesión) = nueva Vista ( anular def run() : LogoutedMessage = ( println("Ingrese nombre ") val nombre = scala.io.StdIn.readLine() Iniciar sesión(nombre) ) ) implícito def loginedUpdater(modelo: Iniciado sesión, msg : LoginedMessage): Modelo = ( (modelo, mensaje) coincidencia ( caso (Iniciado sesión (nombre), Cerrar sesión ()) => Cerrar sesión () case (Iniciar sesión (nombre), Saludar ()) => modelo)) implícito def viewLogined ( modelo: Iniciado sesión) = nueva Vista (val nombre = model.name override def run() : LoginedMessage = ( println(s"Hola, $nombre") println("Cadena vacía para cerrar sesión, no vacía para saludar.") scala.io .StdIn.readLine() coincidencia ( case "" => Cerrar sesión() case _ => Greet() ) ) ) importar actualizadores._

Haskell

No hay tipos dependientes en Haskell convencional. También carece de herencia, que utilizamos significativamente al implementar el patrón en Scala y C++. Pero la herencia de un solo nivel (con elementos de tipos dependientes) se puede modelar utilizando extensiones de lenguaje más o menos estándar: TypeFamilies y ExistentialQuantification. Para la interfaz común de las clases secundarias de programación orientada a objetos, se crea una clase de tipo, en la que hay un tipo "familiar" dependiente, las clases secundarias en sí se representan mediante un tipo separado y luego se envuelven en un tipo "existencial" con un único constructor. .

Modelo de datos = forall m. (Actualizable m, Visualizable m) => Modelo m clase Actualizable m donde datos Mensaje m:: * actualización:: m -> (Mensaje m) -> Modelo clase (Actualizable m) => Visible m donde vista:: m -> (Ver (Mensaje m)) datos Cerrado sesión = Datos cerrados sesión Cerrado = Cerrado sesión Cadena
Intenté separar el actualizador y la vista en la medida de lo posible, así que creé dos clases de tipos diferentes, pero hasta ahora no ha funcionado bien.

La implementación del actualizador es simple.

Instancia actualizable Cerrado sesión donde datos Mensaje Cerrado sesión = Actualización de cadena de inicio de sesión Cerrado sesión (nombre de inicio de sesión) = Modelo (nombre de inicio de sesión) instancia Actualizable Cerrado sesión donde datos Mensaje Cerrado sesión = Cerrar sesión | Saludo actualización m Cerrar sesión = Modelo Cerrar sesión actualizar m Saludo = Modelo m
Tuve que arreglar IO como Vista. Los intentos de hacerlo más abstracto complicaron mucho todo y aumentaron el acoplamiento del código: el tipo de modelo debe saber qué Vista vamos a utilizar.

Importar System.IO tipo Ver a = IO una instancia Visible Cerrar sesión donde ver Cerrar sesión = do putStr "Iniciar sesión: " hFlush stdout fmap Iniciar sesión getLine instancia Visible Cerrar sesión donde ver (Nombre de inicio de sesión) = do putStr $ "Hola " ++ nombre ++ " !\n" hSalida estándar de descarga l<- getLine pure $ if l == "" then Logout else Greeting
Bueno, el entorno ejecutable difiere poco del similar en Idris.

RunMUV::Model -> IO a runMUV (Modelo m) = hacer mensaje<- view m runMUV $ update m msg main:: IO () main = runMUV (Model Logouted)

Editar el archivo URL.py aplicaciones cuenta:

desde django.conf.urls importar URL desde . importar vistas urlpatterns = [# vista de inicio de sesión anterior # url(r"^iniciar sesión/$", vistas.user_login, nombre="iniciar sesión"),# URL de inicio de sesión/cierre de sesión url(r"^login/$" , "django.contrib.auth.views.login", nombre="iniciar sesión" ), url(r"^cerrar sesión/$" , "django.contrib.auth.views.cerrar sesión", nombre="cerrar sesión" ), url(r"^cerrar sesión-luego-iniciar sesión/$" , "django.contrib.auth.views.logout_then_login", nombre="logout_then_login" ), ]

Hemos comentado la plantilla de URL para la vista. inicio de sesión de usuario, creado anteriormente para usar la vista acceso Django.

Cree un nuevo directorio en el directorio de plantillas de la aplicación. cuenta y nómbralo registro. Cree un nuevo archivo en un nuevo directorio, asígnele un nombre iniciar sesión.html

(% extiende "base.html" %) (% título del bloque %) Iniciar sesión (% endblock %) (% contenido del bloque %)

Acceso

(% si formulario.errores %)

Su nombre de usuario y contraseña no coinciden. Inténtelo de nuevo.

(%demás%)

Por favor, utilice el siguiente formulario para iniciar sesión:

(% terminara si %) (%bloque final%)

Esta plantilla de inicio de sesión es muy similar a la creada anteriormente. Usos de Django Formulario de autenticación, situado en django.contrib.auth.forms. Este formulario intenta autenticar al usuario y genera un error de validación si el nombre de usuario era incorrecto. En este caso, podemos buscar errores usando el comando (% if form.errors %). Tenga en cuenta que hemos agregado un elemento oculto. para enviar el valor de una variable llamada próximo.

Parámetro próximo debe ser una URL. Si se especifica este parámetro, una vez que el usuario inicia sesión, se le redirige a la URL especificada.

Ahora crea una plantilla logged_out.html dentro del directorio de plantillas registro y pega el siguiente código en él:

(% extiende "base.html" %) (% título del bloque %) Cerrado sesión (% endblock %) (% contenido del bloque %)

Desconectado

Ha sido desconectado exitosamente. Puedes iniciar sesión nuevamente.

(%bloque final%)

Esta es la plantilla que se mostrará después de que el usuario inicie sesión.

Después de agregar las plantillas de URL y las plantillas para las vistas de entrada y salida, el sitio está listo para iniciar sesión utilizando las vistas de autenticación de Django.

Tenga en cuenta que la presentación cerrar sesión_luego_iniciar sesión, incluido en nuestro configuración de URL, no necesita una plantilla ya que redirige a iniciar sesión ver.

Ahora creemos una nueva vista para mostrar un panel para el usuario, de modo que sepamos cuándo el usuario inicia sesión en su cuenta. Abre el archivo vistas.py aplicaciones cuenta y agrégale el siguiente código:

desde django.contrib.auth.decorators importar login_required @login_required panel def (solicitud): return render(solicitud, "cuenta/dashboard.html", ("sección": "tablero"))

Agregamos un decorador a nuestra vista. Necesario iniciar sesión marco de autenticación. Decorador Necesario iniciar sesión comprueba si el usuario actual está autenticado. Si el usuario está autenticado, se ejecutará el envío; Si el usuario no está autenticado, será redirigido a la página de inicio de sesión.

También definimos una variable sección. Usaremos esta variable para rastrear qué sección del sitio está viendo el usuario.

Ahora necesita crear una plantilla para la vista del panel. Crea un nuevo archivo dentro de plantillas/cuenta plantillas/cuenta/ y nómbralo tablero.html :

(% extiende "base.html" %) (% título del bloque %) Panel de control (% endblock %) (% contenido del bloque %)

Panel

Bienvenido a su panel de control.

(%bloque final%)

Luego agregue el siguiente patrón de URL para este archivo de cambio URL.py aplicaciones cuenta:

Patrones de URL = [ # ... url(r"^$", vistas.tablero, nombre="tablero"), ]

Ahora edite el archivo configuración.py:

de django.core.urlresolvers importar Reverse_lazy LOGIN_REDIRECT_URL = Reverse_lazy("tablero") LOGIN_URL = Reverse_lazy("iniciar sesión") LOGOUT_URL = Reverse_lazy("cerrar sesión")
  • LOGIN_REDIRECT_URL: Indica a qué URL redirigir al usuario después de iniciar sesión.
  • INICIO DE SESIÓN_URL: URL para redirigir al usuario para que inicie sesión (por ejemplo, usando un decorador Necesario iniciar sesión)
  • LOGUT_URL: URL para redirigir al usuario a salir

Ahora vamos a agregar enlaces de inicio y cierre de sesión a nuestra plantilla básica.

Para hacer esto, es necesario determinar si el usuario actual ha iniciado sesión o no para mostrar un enlace correspondiente al estado del usuario actual. El usuario actual se especifica en Solicitud HTTP objeto de la clase intermedia de autenticación. Se puede acceder usando solicitud.usuario. La solicitud encontrará un objeto de usuario, incluso si el usuario no está autenticado. Usuario no autenticado, especificado en la solicitud como instancia Usuario anónimo. La mejor manera de verificar el estado de autenticación del usuario actual es llamar solicitud.usuario.is_authenticado()

Editar en la plantilla base.html

con encabezado de identificación:

Como puede ver, el menú del sitio se muestra solo para usuarios autenticados. También revisamos la sección actual para agregar el atributo de clase seleccionado al elemento correspondiente

  • para resaltar la sección actual en el menú usando CSS. También muestra el nombre de usuario y un enlace para cerrar sesión si el usuario está autenticado, o un enlace para iniciar sesión.

    Abra http://127.0.0.1:8000/account/login/ en su navegador. Deberías ver una página de inicio de sesión. Ingrese un nombre de usuario y contraseña válidos. Verá lo siguiente:

    Puedes ver que la sección Mi panel está resaltada con CSS ya que tiene una clase. seleccionado. Dado que el usuario ha sido autenticado, el nombre de usuario se muestra en el lado derecho del encabezado. Haga clic en el enlace Cerrar sesión. Verá la siguiente página:

    En esta página puede ver que el usuario ha cerrado sesión y por lo tanto ya no se muestra el menú del sitio web. El enlace en el lado derecho del encabezado ahora muestra Acceso.

    Si ve la página de cierre de sesión del sitio de administración de Django en lugar de su propia página de cierre de sesión, verifique la configuración de INSTALLED_APPS y asegúrese de que django.contrib.admin es despues cuenta. Ambas plantillas están en la misma ruta relativa y el cargador de plantillas de Django utilizará la primera que encuentre.

    Muchas personas comienzan a escribir un proyecto para trabajar con una sola tarea, sin implicar que pueda convertirse en un sistema de gestión multiusuario, por ejemplo, contenido o, Dios no lo quiera, producción. Y todo parece genial y genial, todo funciona, hasta que empiezas a comprender que el código que se escribe consiste enteramente en muletas y código duro. El código se mezcla con diseño, consultas y muletas, a veces incluso ilegible. Surge un problema urgente: al agregar nuevas funciones, hay que jugar con este código durante mucho tiempo, recordando "¿qué estaba escrito allí?" y maldicete en el pasado.

    Es posible que incluso hayas oído hablar de patrones de diseño e incluso hayas hojeado estos maravillosos libros:

    • E. Gamma, R. Helm, R. Johnson, J. Vlissides “Técnicas de diseño orientada a objetos. Patrones de diseño";
    • M. Fowler "Arquitectura de aplicaciones de software empresarial".
    Y muchos, impertérritos ante los enormes manuales y documentación, intentaron estudiar cualquiera de los marcos modernos y, ante la complejidad de su comprensión (debido a la presencia de muchos conceptos arquitectónicos hábilmente vinculados entre sí), pospusieron el estudio y el uso de herramientas modernas “en un segundo plano”.

    Este artículo será útil principalmente para principiantes. En cualquier caso, espero que en un par de horas pueda hacerse una idea de la implementación del patrón MVC, que subyace a todos los marcos web modernos, y también obtener "alimento" para una mayor reflexión sobre "cómo hazlo." Al final del artículo hay una selección de enlaces útiles que también le ayudarán a comprender en qué consisten los frameworks web (además de MVC) y cómo funcionan.

    Es poco probable que los programadores PHP experimentados encuentren algo nuevo en este artículo, ¡pero sus comentarios y comentarios sobre el texto principal serán de gran ayuda! Porque Sin teoría la práctica es imposible, y sin práctica la teoría es inútil, luego primero habrá un poco de teoría y luego pasaremos a la práctica. Si ya está familiarizado con el concepto MVC, puede omitir la sección teórica e ir directamente a la práctica.

    1. Teoría

    El patrón MVC describe una forma sencilla de estructurar una aplicación, cuyo propósito es separar la lógica empresarial de la interfaz de usuario. Como resultado, la aplicación es más fácil de escalar, probar, mantener y, por supuesto, implementar.

    Veamos el diagrama conceptual del patrón MVC (en mi opinión, este es el diagrama más exitoso que he visto):

    En la arquitectura MVC, el modelo proporciona los datos y las reglas de lógica empresarial, la vista es responsable de la interfaz de usuario y el controlador proporciona la interacción entre el modelo y la vista.

    Un flujo típico de una aplicación MVC se puede describir de la siguiente manera:

    1. Cuando un usuario visita un recurso web, el script de inicialización crea una instancia de la aplicación y la inicia para su ejecución.
      Esto muestra una vista de, digamos, la página principal del sitio.
    2. La aplicación recibe una solicitud del usuario y determina el controlador y la acción solicitados. En el caso de la página principal, se realiza la acción predeterminada ( índice).
    3. La aplicación crea una instancia del controlador y ejecuta el método de acción,
      que, por ejemplo, contiene llamadas a modelos que leen información de la base de datos.
    4. Después de esto, la acción crea una vista con los datos obtenidos del modelo y muestra el resultado al usuario.
    Modelo- contiene la lógica empresarial de la aplicación e incluye métodos de muestreo (pueden ser métodos ORM), procesamiento (por ejemplo, reglas de validación) y suministro de datos específicos, lo que a menudo lo hace muy denso, lo cual es bastante normal.
    El modelo no debe interactuar directamente con el usuario. Todas las variables relacionadas con la solicitud del usuario deben procesarse en el controlador.
    El modelo no debe generar HTML u otro código de visualización que pueda cambiar según las necesidades del usuario. Dicho código debe procesarse en vistas.
    El mismo modelo, por ejemplo: el modelo de autenticación de usuario se puede utilizar tanto en la parte de usuario como en la parte administrativa de la aplicación. En este caso, puede mover el código general a una clase separada y heredar de él, definiendo métodos específicos de subaplicación en sus descendientes.

    Vista- se utiliza para configurar la visualización externa de los datos recibidos del controlador y del modelo.
    Las vistas contienen marcado HTML y pequeñas inserciones de código PHP para recorrer, formatear y mostrar datos.
    No debe acceder directamente a la base de datos. Esto es lo que deberían hacer los modelos.
    No debería funcionar con datos obtenidos a partir de una solicitud de usuario. Esta tarea debe ser realizada por el controlador.
    Puede acceder directamente a las propiedades y métodos de un controlador o modelos para obtener datos listos para la salida.
    Las vistas generalmente se dividen en una plantilla común, que contiene marcas comunes a todas las páginas (por ejemplo, un encabezado y pie de página) y partes de la plantilla que se utilizan para mostrar la salida de datos del modelo o mostrar formularios de entrada de datos.

    Controlador- el pegamento que conecta modelos, vistas y otros componentes en una aplicación funcional. El responsable del tratamiento es responsable de procesar las solicitudes de los usuarios. El controlador no debe contener consultas SQL. Es mejor mantenerlos en modelos. El controlador no debe contener HTML ni otro tipo de marcado. Vale la pena ponerlo a la vista.
    En una aplicación MVC bien diseñada, los controladores suelen ser muy delgados y contienen sólo unas pocas docenas de líneas de código. No se puede decir lo mismo de los Inspectores Gordos Estúpidos (SFC) en CMS Joomla. La lógica del controlador es bastante típica y la mayor parte se transfiere a clases base.
    Los modelos, por el contrario, son muy gruesos y contienen la mayor parte del código relacionado con el procesamiento de datos, porque La estructura de datos y la lógica empresarial que contiene suelen ser bastante específicas de una aplicación en particular.

    1.1. Controlador frontal y controlador de página

    En la mayoría de los casos, la interacción del usuario con una aplicación web se produce haciendo clic en enlaces. Mire ahora la barra de direcciones de su navegador: recibió este texto desde este enlace. Otros enlaces, como los que se encuentran en el lado derecho de esta página, le proporcionarán contenido diferente. Por tanto, el enlace representa un comando específico para la aplicación web.

    Espero que ya hayas notado que diferentes sitios pueden tener formatos completamente diferentes para construir la barra de direcciones. Cada formato puede mostrar la arquitectura de una aplicación web. Aunque no siempre es así, en la mayoría de los casos es un hecho claro.

    Consideremos dos opciones para la barra de direcciones, que muestran algo de texto y un perfil de usuario.

    Primera opción:

    1. www.ejemplo.com/article.php?id=3
    2. www.ejemplo.com/user.php?id=4
    Aquí, cada script es responsable de ejecutar un comando específico.

    Segunda opción:

    1. www.ejemplo.com/index.php?article=3
    2. www.ejemplo.com/index.php?user=4
    Y aquí todas las llamadas ocurren en un escenario. index.php.

    Puede ver el enfoque de múltiples puntos de contacto en los foros de phpBB. La navegación por el foro se realiza mediante un script. verforo.php, ver tema vía vertopic.php etc. El segundo enfoque, con acceso a través de un único archivo de script físico, se puede ver en mi CMS MODX favorito, donde todos los accesos pasan por index.php.

    Estos dos enfoques son completamente diferentes. El primero es típico del patrón Page Controller y el segundo enfoque lo implementa el patrón Front Controller. El controlador de página es bueno para sitios con una lógica bastante simple. A su vez, el controlador de solicitudes consolida todas las actividades de procesamiento de solicitudes en un solo lugar, lo que le brinda capacidades adicionales que pueden permitirle implementar tareas más complejas que las que normalmente resuelve el controlador de páginas. No entraré en detalles de la implementación del controlador de página, solo diré que en la parte práctica será el controlador de solicitudes (algo similar) el que se desarrollará.

    1.2. Enrutamiento de URL

    El enrutamiento de URL le permite configurar su aplicación para aceptar solicitudes de URL que no corresponden a archivos de aplicación reales, así como para utilizar CNC que son semánticamente significativos para los usuarios y preferidos para la optimización de motores de búsqueda.

    Por ejemplo, para una página normal que muestra un formulario de contacto, la URL podría verse así:
    http://www.example.com/contacts.php?action=feedback

    Código de procesamiento aproximado en este caso:
    cambiar ($_GET ["acción"]) (caso "acerca de": require_once ("acerca de.php"); // página "Acerca de nosotros" romper ; caso "contactos": require_once ("contactos.php");// página "Contactos" romper ; caso "comentarios": require_once ("comentarios.php");
    // página "Comentarios"

    romper ;
    predeterminado: require_once ("página404.php"); // salto de página "404"; )

    Creo que casi todo el mundo ha hecho esto antes.

    Con un motor de enrutamiento de URL, puede configurar su aplicación para aceptar solicitudes como esta para mostrar la misma información:
    http://www.example.com/contacts/feedback

    Aquí los contactos representan el controlador y los comentarios son el método del controlador de contactos que muestra el formulario de comentarios, etc. Volveremos a esta cuestión en la parte práctica.

    También vale la pena saber que los enrutadores de muchos marcos web le permiten crear rutas URL personalizadas (especifique qué significa cada parte de la URL) y reglas para procesarlas.

    Ahora tenemos suficientes conocimientos teóricos para pasar a la práctica.
    2. Practica index.php Primero, creemos la siguiente estructura de archivos y carpetas: De cara al futuro, diré que las clases principales Modelo, Vista y Controlador se almacenarán en la carpeta principal. Sus hijos se almacenarán en los directorios de controladores, modelos y vistas. Archivo

    Iremos de forma secuencial; Abramos el archivo index.php y rellénelo con el siguiente código:
    ini_set("display_errors", 1); require_once "aplicación/bootstrap.php";
    No debería haber ninguna pregunta aquí.

    A continuación, pasemos inmediatamente a la driza. De cara al futuro, diré que las clases principales Modelo, Vista y Controlador se almacenarán en la carpeta principal.:
    require_once "núcleo/model.php"; require_once "núcleo/view.php"; require_once "núcleo/controlador.php"; require_once "núcleo/ruta.php"; Ruta::inicio(); //iniciar el enrutador
    Las primeras tres líneas incluirán archivos del kernel que actualmente no existen. Las últimas líneas incluyen el archivo con la clase de enrutador y lo lanzan para su ejecución llamando al método de inicio estático.

    2.1. Implementación de un enrutador de URL

    Por ahora, desviémonos de la implementación del patrón MVC y pasemos al enrutamiento. El primer paso que debemos hacer es escribir el siguiente código en .htaccess:
    RewriteEngine en RewriteCond %(REQUEST_FILENAME) !-f RewriteCond %(REQUEST_FILENAME) !-d RewriteRule .* index.php [L]
    Este código redirigirá el procesamiento de todas las páginas a index.php, que es lo que necesitamos. ¿Recuerdas que en la primera parte hablamos del Front Controller?

    Colocaremos la ruta en un archivo separado. ruta.php al directorio principal. En este archivo describiremos la clase Ruta, que ejecutará métodos de controlador, que a su vez generarán la vista de página.

    Contenido del archivo route.php

    ruta de clase ( estático inicio de función() ( // controlador y acción predeterminada$controller_name = "Principal"; $nombre_acción = "índice"; $rutas = explotar("/" , $_SERVER ["REQUEST_URI" ]); //obtiene el nombre del controlador if (!empty ($rutas)) ( $nombre_controlador = $rutas ; ) //obtiene el nombre de la acción if (!empty ($rutas )) ( $nombre_acción = $rutas ; ) // agregar prefijos$nombre_modelo = "Modelo_".$nombre_controlador; $nombre_controlador = "Controlador_".$nombre_controlador; $nombre_acción = "acción_" .$nombre_acción ; // conecta el archivo con la clase de modelo (puede que no haya un archivo de modelo)$model_file = strtolower($model_name)..php"; $model_path = "aplicación/modelos/" .$model_file; if (file_exists($model_path)) (incluye "aplicación/modelos/".$model_file;) // conecta el archivo con la clase de controlador$controller_file = strtolower($controller_name )..php"; $controller_path = "aplicación/controladores/" .$controller_file; if (file_exists($controller_path)) (incluye "aplicación/controladores/".$controller_file;) else ( /* sería correcto lanzar una excepción aquí, pero para simplificarlo, redireccionaremos inmediatamente a la página 404 */ Ruta::ErrorPage404(); ) // crear un controlador$controlador = nuevo $nombre_controlador; $acción = $nombre_acción; si (method_exists($controlador, $acción)) ( // llama a la acción del controlador$controlador ->$acción(); ) demás ( // también sería más prudente lanzar una excepción aquí Ruta::ErrorPage404(); ) ) función PáginaError404() ($host = "http://" .$_SERVER ["HTTP_HOST" ]."/" ; encabezado("HTTP/1.1 404 no encontrado"); encabezado("Estado: 404 No encontrado"); encabezado("Ubicación:".$host. "404"); ) )


    Observo que la clase implementa una lógica muy simplificada (a pesar del voluminoso código) y puede incluso tener problemas de seguridad. Esto se hizo intencionalmente, porque... Escribir una clase de enrutamiento completa merece al menos un artículo aparte. Veamos los puntos principales...

    El elemento de matriz global $_SERVER["REQUEST_URI"] contiene la dirección completa a la que se comunicó el usuario.
    Por ejemplo: ejemplo.ru/contacts/feedback

    Usando la función explotar La dirección se divide en componentes. Como resultado, obtenemos el nombre del controlador, en el ejemplo dado, este es controlador contactos y el nombre de la acción, en nuestro caso - comentario.

    A continuación, se conectan el archivo del modelo (puede que falte el modelo) y el archivo del controlador, si lo hay, y finalmente, se crea una instancia del controlador y se llama a la acción, nuevamente, si se describió en la clase del controlador.

    Así, al dirigirse a, por ejemplo, la dirección:
    ejemplo.com/portfolio
    o
    ejemplo.com/portfolio/index
    El enrutador realizará las siguientes acciones:

    1. incluirá el archivo model_portfolio.php de la carpeta de modelos, que contiene la clase Model_Portfolio;
    2. incluirá el archivo controlador_portfolio.php de la carpeta de controladores, que contiene la clase Controlador_Portfolio;
    3. creará una instancia de la clase Controller_Portfolio y llamará a la acción predeterminada, action_index, descrita en ella.
    Si el usuario intenta acceder a la dirección de un controlador inexistente, por ejemplo:
    ejemplo.com/ufo
    luego será redirigido a la página "404":
    ejemplo.com/404
    Lo mismo ocurrirá si el usuario accede a una acción que no está descrita en el controlador.

    2.2. Volvamos a la implementación de MVC.

    Vayamos a la carpeta principal y agreguemos tres archivos más al archivo route.php: modelo.php, view.php y controlador.php

    Permítanme recordarles que contendrán clases base, que ahora comenzaremos a escribir.

    Contenido del archivo modelo.php
    modelo de clase ( público función obtener_datos() ( } }
    La clase modelo contiene un único método de recuperación de datos vacío, que se anulará en las clases descendientes. Cuando creemos clases descendientes todo quedará más claro.

    Contenido del archivo ver.php
    vista de clase ( //público $template_view; // aquí puede especificar la vista general predeterminada. función generar ( $content_view, $template_view, $datos = nulo) { /* if(is_array($data)) ( // convierte elementos de la matriz en variables extract($data); ) */ incluya "aplicación/vistas/".$template_view; ) )
    No es difícil adivinar que el método generar destinado a formar una vista. Se le pasan los siguientes parámetros:

    1. $content_file - vistas que muestran el contenido de la página;
    2. $template_file — plantilla común a todas las páginas;
    3. $data es una matriz que contiene elementos de contenido de la página. Generalmente se completa en el modelo.
    La función de inclusión conecta dinámicamente una plantilla general (vista) dentro de la cual se incrustará la vista.
    para mostrar el contenido de una página específica.

    En nuestro caso, la plantilla general contendrá encabezado, menú, barra lateral y pie de página, y el contenido de la página estará contenido en un formulario separado. Nuevamente, esto se hace por simplicidad.

    Contenido del archivo controlador.php
    controlador de clase ( modelo $ público; vista pública $; función __construcción() ($this ->vista = nueva Vista(); ) ) )
    Método índice_acción- esta es la acción llamada por defecto; la anularemos al implementar clases descendientes.

    2.3. Implementación de clases descendientes Modelo y Controlador, creación de Vistas

    ¡Ahora comienza la diversión! Nuestro sitio web de tarjetas de presentación constará de las siguientes páginas:
    1. hogar
    2. Servicios
    3. portafolio
    4. Contactos
    5. Y también - la página "404"
    Cada página tiene su propio controlador de la carpeta de controladores y una vista de la carpeta de vistas. Algunas páginas pueden utilizar un modelo o modelos de la carpeta de modelos.

    En la figura anterior, el archivo está resaltado por separado. plantilla_vista.php es una plantilla que contiene marcas comunes a todas las páginas. En el caso más sencillo podría verse así:
    <html lang="ru" > <cabeza > <metacharset="utf-8"> <título > hogartítulo > cabeza > <cuerpo > $vista_contenido; ?> cuerpo > HTML >
    Para darle al sitio un aspecto presentable, creamos una plantilla CSS y la integramos en nuestro sitio cambiando la estructura del marcado HTML y conectando archivos CSS y JavaScript:
    <enlace rel ="hoja de estilo" tipo ="text/css" href ="/css/style.css" /> <script src="/js/jquery-1.6.2.js" tipo="texto/javascript" >guión >

    Al final del artículo, en la sección “Resultado”, hay un enlace a un repositorio de GitHub con un proyecto en el que se han dado pasos para integrar una plantilla sencilla.

    2.3.1. Creando la página principal

    Empecemos con el controlador. controlador_principal.php, aquí está su código:
    clase Controller_Main extiende el controlador ( función índice_acción() ($this ->view->generate("main_view.php", "template_view.php"); ) )
    en método generar una instancia de la clase Vista, se pasan los nombres de los archivos de la plantilla general y la vista con el contenido de la página.
    Además de la acción de índice, el controlador puede, por supuesto, contener otras acciones.

    Revisamos el archivo de vista general anteriormente. Considere el archivo de contenido vista_principal.php:
    <h1 >¡Bienvenido!h1 > <p> <img src="/images/office-small.jpg" align="izquierda" > <un href = "/" > EQUIPO OLOLOSHAun >- un equipo de especialistas de primer nivel en el campo del desarrollo de sitios web con muchos años de experiencia en la colección de máscaras mexicanas, estatuas de bronce y piedra de la India y Ceilán, bajorrelieves y esculturas creadas por maestros de África Ecuatorial hace cinco o seis siglos. ..p>
    Contiene marcado simple sin llamadas PHP.
    Para mostrar la página principal, puede utilizar una de las siguientes direcciones:

    • métodos de bibliotecas que implementan la abstracción de datos. Por ejemplo, métodos de la biblioteca PEAR MDB2;
    • métodos ORM;
    • métodos para trabajar con NoSQL;
    • y etc.
    • Para simplificar, aquí no utilizaremos consultas SQL ni declaraciones ORM. En su lugar, emularemos datos reales y devolveremos inmediatamente una serie de resultados.
      Archivo de modelo modelo_portfolio.php Ponlo en la carpeta de modelos. Aquí tenéis su contenido:
      clase Model_Portfolio extiende el modelo ( público función obtener_datos() ( devolver matriz (matriz ("Año" => "2012", "Sitio" => "http://DunkelBeer.ru", "Descripción" => "Sitio promocional de la cerveza negra Dunkel del fabricante alemán Löwenbraü, producida en Rusia por la empresa cervecera SUN InBev."), matriz ("Año" => "2012" , "Sitio" => "http://ZopoMobile.ru" , "Descripción" => "Catálogo en ruso de teléfonos chinos de Zopo basados ​​en el sistema operativo Android y accesorios para ellos".), // hacer );

      ) ) La clase de controlador del modelo está contenida en el archivo, aquí está su código:
      controlador_cartera.php función __construcción() ( clase Controller_Portfolio extiende el controlador ( función índice_acción() ($this ->modelo = nuevo Model_Portfolio(); $this ->vista = nueva Vista(); )
      $datos = $this ->modelo->get_data(); $this ->view->generate("portfolio_view.php", "template_view.php", $datos); ) ) a una variable datos se escribe la matriz devuelta por el método obtener datos
      que vimos antes. generar Luego, esta variable se pasa como parámetro del método.

      , que también contiene: el nombre del archivo con la plantilla general y el nombre del archivo que contiene la vista con el contenido de la página. La vista que contiene el contenido de la página está en el archivo..

      portafolio

      portafolio_view.php " ; }


      Enlace de GitHub: https://github.com/vitalyswipe/tinymvc/zipball/v0.1

      Pero en esta versión esbocé las siguientes clases (y sus tipos correspondientes):

      • Controller_Login en el que se genera una vista con un formulario para ingresar nombre de usuario y contraseña, luego de completarlo se realiza el procedimiento de autenticación y, si tiene éxito, se redirige al usuario al panel de administración.
      • Contorller_Admin con una acción de índice que verifica si el usuario estaba previamente autorizado en el sitio como administrador (si es así, se muestra la vista del panel de administración) y una acción de cierre de sesión para cerrar sesión.
      La autenticación y la autorización son un tema diferente, por lo que no se analizan aquí, pero solo se proporciona el enlace que figura arriba para que tenga un punto de partida.

      4. Conclusión

      El patrón MVC se utiliza como base arquitectónica en muchos frameworks y CMS, que fueron creados para poder desarrollar soluciones cualitativamente más complejas en menos tiempo. Esto fue posible aumentando el nivel de abstracción, ya que existe un límite en la complejidad de las estructuras con las que puede operar el cerebro humano.

      Pero no siempre es recomendable utilizar frameworks web como Yii o Kohana, que constan de varios cientos de archivos, al desarrollar aplicaciones web simples (por ejemplo, sitios de tarjetas de presentación). Ahora podemos crear un hermoso modelo MVC para no mezclar código Php, Html, CSS y JavaScript en un solo archivo.

      Este artículo es más un punto de partida para aprender CMF que un ejemplo de algo realmente correcto que puede utilizar como base para su aplicación web. Quizás incluso te haya inspirado y ya estés pensando en escribir tu propio microframework o CMS basado en MVC. Pero, antes de reinventar la próxima rueda con “blackjack y putas”, piénselo de nuevo: ¡¿tal vez sería más razonable dirigir sus esfuerzos al desarrollo y ayuda a la comunidad de un proyecto ya existente?!

      P.D.: El artículo fue reescrito teniendo en cuenta algunos comentarios dejados en los comentarios. La crítica resultó muy útil. A juzgar por la respuesta: comentarios, MP y la cantidad de usuarios que agregaron la publicación a favoritos, la idea de escribir esta publicación resultó no ser tan mala. Desafortunadamente, no es posible tener en cuenta todos los deseos y escribir más y con más detalle debido a la falta de tiempo... pero tal vez esos misteriosos individuos que rechazaron la versión original lo hagan. Buena suerte con tus proyectos!

      5. Una selección de enlaces útiles sobre el tema.

      El artículo toca muy a menudo el tema de los frameworks web; este es un tema muy amplio, porque incluso los microframeworks constan de muchos componentes inteligentemente interconectados y se necesitaría más de un artículo para hablar de estos componentes. Sin embargo, decidí presentar aquí una pequeña selección de enlaces (que seguí mientras escribía este artículo) que de una forma u otra se relacionan con el tema de los marcos.

      Django viene con una gran cantidad de recursos integrados para los casos de uso más comunes de una aplicación web. La aplicación de registro es un muy buen ejemplo y lo bueno es que las funciones se pueden utilizar de inmediato.

      Con la aplicación de registro de Django puedes aprovechar las siguientes características:

      • Acceso
      • Cerrar sesión
      • Inscribirse
      • Restablecimiento de contraseña

      En este tutorial nos centraremos en las funciones de inicio de sesión y cierre de sesión. Para registrarse y restablecer la contraseña, consulte los tutoriales a continuación:

      Empezando

      Antes de comenzar, asegúrese de tener django.contrib.auth en sus INSTALLED_APPS y el middleware de autenticación configurado correctamente en la configuración de MIDDLEWARE_CLASSES.

      Ambos ya vienen configurados cuando inicias un nuevo proyecto Django usando el comando startproject. Entonces, si no eliminó las configuraciones iniciales, debería estar todo configurado.

      En caso de que esté iniciando un nuevo proyecto solo para seguir este tutorial, cree un usuario usando la línea de comando para que podamos probar las páginas de inicio y cierre de sesión.

      $ python administrar.py crear superusuario

      Al final de este artículo proporcionaré el código fuente del ejemplo con la configuración mínima.

      Configurar las rutas URL

      Primero importe el módulo django.contrib.auth.views y agregue una ruta URL para las vistas de inicio y cierre de sesión:

      desde django.conf.urls importar URL desde django.contrib importar administrador desde django.contrib.auth importar vistas como auth_views urlpatterns = [url (r"^login/$", auth_views. login, nombre = "login"), url ( r"^cerrar sesión/$" , auth_views . cerrar sesión , nombre = "cerrar sesión" ), url (r"^admin/" , administrador . sitio . URL ), ]

      Crear una plantilla de inicio de sesión

      De forma predeterminada, la vista django.contrib.auth.views.login intentará representar la plantilla de registro/login.html. Entonces, la configuración básica sería crear una carpeta llamada registro y colocar una plantilla login.html dentro.

      Siguiendo una plantilla de inicio de sesión mínima:

      (% extiende "base.html" %) (% título del bloque %) Iniciar sesión (% endblock %) (% contenido del bloque %)

      Acceso

      (% csrf_token %) (( formulario.as_p )) (%bloque final%)

      Este sencillo ejemplo ya valida el nombre de usuario y la contraseña y autentica correctamente al usuario.

      Personalizando la vista de inicio de sesión

      Hay algunos parámetros que puede pasar a la vista de inicio de sesión para que se ajuste a su proyecto. Por ejemplo, si desea almacenar su plantilla de inicio de sesión en otro lugar que no sea registro/login.html, puede pasar el nombre de la plantilla como parámetro:

      URL (r"^login/$", auth_views. login, ("template_name": "core/login.html"), nombre = "login"),

      También puede pasar un formulario de autenticación personalizado utilizando el parámetro authentic_form, en caso de que haya implementado un modelo de usuario personalizado.

      Ahora, se realiza una configuración muy importante en el archivo settings.py, que es la URL que Django redirigirá al usuario después de una autenticación exitosa.

      Dentro del archivo settings.py agregue:

      LOGIN_REDIRECT_URL = "casa"

      El valor puede ser una URL codificada o un nombre de URL. El valor predeterminado para LOGIN_REDIRECT_URL es /accounts/profile/ .

      También es importante tener en cuenta que Django intentará redirigir al usuario al siguiente parámetro GET.

      Configurar la vista de cierre de sesión

      Después de acceder a la vista django.contrib.auth.views.logout, Django representará la plantilla de registro/logged_out.html. De manera similar a como lo hicimos en la vista de inicio de sesión, puede pasar una plantilla diferente como esta:

      url (r"^logout/$" , auth_views . cerrar sesión , ("template_name": "logged_out.html") , nombre = "cerrar sesión" ),

      Por lo general, prefiero usar el parámetro next_page y redirigir a la página de inicio de mi proyecto o a la página de inicio de sesión cuando tenga sentido.





      Todos los proyectos de la siguiente tabla son ficticios, así que ni siquiera intentes seguir los enlaces proporcionados.AñoProyecto
      " .$fila ["Año" ]."" .$fila ["Sitio" ]."" .$fila ["Descripción" ]."