emartinm / lsql

Aplicación web para el aprendizaje de las bases de datos
MIT License
4 stars 4 forks source link

Tarea sistema de logros (complejidad media) #39

Closed emartinm closed 3 years ago

emartinm commented 3 years ago

Tarea para @Dashito14

Incorporar un sistema de logros para aumentar la competitividad, p. ej. realiza 3 ejercicios de una colección. Es necesario pensar:

Dashito14 commented 3 years ago

Buenas, estoy esperando feedback de la otra tarea. Para no estar parado mientras, he realizado la documentación de la tarea y de paso un Mock Up para mostraros más o menos mi idea con esto. Me gustaría que lo vierais los dos (@jcorreas ) y me dijerais si habíais pensado otra cosa.

He pensado en hacer una pestaña nueva para llegar fácilmente a nuestros Logros, que estuviera en la cabecera. En esta vista se mostrarían dos tablas con los Logros Completados y Logros Bloqueados (las cabeceras hay que revisarlas, fecha de desbloqueo no me suena bien). Todo esto con la explicación de los logros para que cada usuario sepa qué debe realizar para conseguirlo.

MockUp-TFG-Logros

En cuanto a logros soportados había pensado que fueran, "Consigue resolver X ejercicios de Procedimientos", "Consigue resolver X ejercicios de DML"... También habría que mirar si podría ser factible algo del estilo, "Consigue ser el primero en enviar un ejercicio concreto correctamente", "Consigue alcanzar el podio en X ocasiones"... No sé si estos datos se almacenan en algún lado para poder realizarlo.

Una duda que me ha surgido pensando la tarea. Tendré que realizar un model nuevo que se llame Logro y tenga distintos atributos ¿no? Para así cada vez que vaya a la vista cargar los logros los cuales estarán relacionados a cada usuario.

emartinm commented 3 years ago

Yo el mock lo veo muy bien, me convence la presentación. "Fecha de desbloqueo" podría ser "Fecha de obtención" o simplemente "Fecha".

Todos los logros que mencionas se pueden calcular a partir de los envíos realizados, que sí están almacenados. Estaría bien tener unos nombres "simpáticos" como "Experto en DML" (>= 10 problemas DML resueltos), "Maestro de SELECT" (>= 20 problemas SELECT resueltos), "Pionero" (ser oro en algún problema), "Podio-lover" (estar en 3 o más podios). Seguramente se te ocurren nombres mucho mejores :-) Creo que lo mejor es que los logros sean globales, es decir, independientes de los grupos de clase, porque eso simplificará las cosas.

Una cosa que he pensado: ¿es interesante notificar al usuario en el momento en el que consigue un logro? Estaría bien, habría que realizar la comprobación con cada envío aceptado aunque no sé cómo de costoso será.

Desde el punto de vista del código, sería posible crear un modelo Achievement y relacionar usuarios con una lista de Achievements (y la fecha de consecución). Se podría usar una función (posiblemente un método de clase de Achievement) que recibe el último envío aceptado de un usuario y comprueba y almacena si ha ganado un logro. Me gustaría que añadir nuevos logros fuera algo bastante modular y centrado en una única clase. Y tendría que ser capaz de detectar los logros que le faltan a un usuario

jcorreas commented 3 years ago

Me parece también muy bien la propuesta. También los comentarios de Enrique sobre "Fecha de desbloqueo" --> "Fecha". Respecto a los "Logros Bloqueados", yo lo cambiaría por "Logros Pendientes" (este es el significado, no?).

Supongo que el cálculo de los logros como tal estará programado directamente en la aplicación. Se podría plantear hacer los logros configurables, para que el profesor pueda ajustar qué se considera el valor a partir del que se considera un "Experto en DML", por ejemplo. Pero depende de cuánto nos queramos complicar la vida con ello. O incluso tener logros por cada colección: Habría que almacenar en una tabla la colección, el nombre/id del logro y el valor a partir del cual se consigue. Por ejemplo:

Colección DML, especialista, 5 Colección DML, experto, 10 Colección DML, maestro, 15

Habría que hacer una página para que el profesor pueda mantener esta tabla. No sé si os parece demasiado complicado o no.

Con este enfoque habría que pensar cómo se configuran los logros que combinan varias colecciones o que corresponden a información de podio.

emartinm commented 3 years ago

Detalle: a lo mejor el enlace de "logros" debía ir en el menú desplegable del usuario, ya que es algo de su perfil personal.

Tener logros configurables que no estén codificados en la aplicación sería perfecto, pero me temo que aumentaría demasiado la complejidad de la tarea. Como el primer paso para incorporar logros lleva varias incorporaciones podríamos considerar inicialmente logros "cableados" y dejar los logros configurables como una segunda tarea de dificultad media por si alguien la quiere hacer. Y para esta considerar únicamente:

  1. La detección de logros en el momento del envío, junto con su almacenamiento
  2. Generar la página de logros de cada usuario
  3. Avisar del logro en el momento del envío
  4. Añadir medallas en el ranking según los logros conseguidos por cada usuario, y que si otro usuario pincha pueda ver esos logros (para picarse)

De hecho, incluso para esta primera versión me olvidaría de colecciones, grupos y tipos de problema. Es decir, que los logros serían generales:

jcorreas commented 3 years ago

Estoy de acuerdo, me he venido arriba :-). Me parecen bien los logros que planteas, y muy buena idea el enlace en el ranking a los logros de otro usuario.

En otra tarea de dificultad media podemos añadir otras opciones.

emartinm commented 3 years ago

Creo que tener logros configurables sería muy bueno, pero si lo consideramos en esta tarea creo que quedaría bastante sobrecargada. Y dividir en dos siempre viene bien.

Lo de ver los logros de los demás sería no restringir del todo la visualización de logros al usuario actual sino a cualquier usuario autenticado. Y luego enlazarlo en el ranking sería tan sencillo como poner una medalla por cada logro y un enlace a la URL de los logros de ese usuario. La URL sería /achievements/<user> o algo así.

Dashito14 commented 3 years ago

Sí, más o menos lo que habéis dicho me parece todo perfecto. ¿Entonces desde el perfil pongo un botón que lleve a la vista de los logros?

Podemos empezar como ha dicho Enrique con unos logros más sencillos, como los primeros que dijimos, y después si va bien se puede hacer como otra tarea añadir que sean configurables y más cosas así.

En cuanto a las medallas en el ranking podemos poner unos números al lado de cada medallita para que ponga cuantos tiene, o algo del estilo de rangos, por ejemplo una medalla azul si tienes mas de 3 logros, una marrón si solo tienes 1 o algo así (no sé si sería posible).

En cuanto consiga el merge de la otra (espero hoy) me meto de lleno con esto.

emartinm commented 3 years ago

¿Entonces desde el perfil pongo un botón que lleve a la vista de los logros?

Creo que ese menú desplegable puede ser un buen lugar, sí.

En cuanto a las medallas en el ranking podemos poner unos números al lado de cada medallita para que ponga cuantos tiene, o algo del estilo de rangos, por ejemplo una medalla azul si tienes mas de 3 logros, una marrón si solo tienes 1 o algo así (no sé si sería posible).

Yo había pensado más en poner un chorro de medallas, como los militares, porque visualmente es más llamativo ver 5 medallas que medalla x 5. ¿Y quizá motive más? Pero es un detalle menor, así que usa la opción que más te guste que si hubiera que cambiarlo será una línea.

Dashito14 commented 3 years ago

Os dejo una imagen para que veáis más o menos lo que había pensado. Si creéis que hay algo que cambiar avisadme.

image

En cuanto a la parte técnica, estaba mirando y lo que se me ha ocurrido es tener una lista con todos los logros disponibles. Y que cada vez que un usuario complete uno se el agregue a su perfil. Pero User al ser un Model de Django no sé como agregarle campos nuevos, que sería esta lista de logros conseguidos. Tampoco sé como crear esta lista con todos los logros, no sé como hacer que se cargue esta lista cada vez que se inicie la página o como almacenarla.

Dashito14 commented 3 years ago

Quería añadir la página donde estaba mirando lo de agregar nuevos campos a User https://codigofacilito.com/articulos/django-user-model. Aquí sale como extender creando una clase nueva, no sé si hay alguna forma de simplemente agregar atributo, o tengo que crear una clase que extienda de User.

emartinm commented 3 years ago

Por prudencia, sería partidario de no modificar User porque no sé cómo de complejo será aplicar esas migraciones en el sistema que ya tiene 60 usuarios y hasta julio deberían ser capaces de usarlo sin perder nada. Creo que para almacenar la consecución de logros sería más sencillo crear una clase Achievement tal que un objeto de esa clase almacene la información de que un usuario ha conseguido un cierto logro en una fecha concreta. Es decir, que el logro contenga al usuario y que para obtener los logros obtenidos por un usuario recorras los logros que "contienen" a ese usuario.

Tampoco sé como crear esta lista con todos los logros, no sé como hacer que se cargue esta lista cada vez que se inicie la página o como almacenarla.

¡Bienvenido a nuestro mundo! La opción sencilla sería tener la información de qué logros existen (especialista, experto, rey de los podios...), su explicación y la lógica para detectar cuándo un usuario consigue uno directamente en código "atornillado". Esta componente podría ser un módulo Python separado (para no poblar views.py en exceso) y tendría funciones para:

Claramente este es un enfoque bastante limitado pero permite tener ciertos logros funcionando sin demasiado dolor. ¿Véis algo que pueda llegar a ser problemático? Seguramente hay un patrón de diseño que encaja en este problema de tener "lógica de obtención de logros configurable y encufable sobre la marcha" pero a mi al menos no me viene ninguno a la cabeza.

Dashito14 commented 3 years ago

A ver si he entendido bien. Un atributo en Achievement que sea un diccionario o un map o algo por el estilo, que almacene el usuario con la fecha en la que consiguió el Logro. Y así tener una lista con todos los usuarios.

Después crear todas su funcionalidades en un módulo .py separado de views para no recargar.

También pensé (Iker ayudó) ayer, porque no veía claro lo de editar User, en crear una especie de Model separado en el que se almacenase el id de un logro, el id del usuario que ha conseguido el logro y un atributo para la fechas. Así para resolver los casos de la vista de Logros y de las medallas habría que recorrer esa lista, y con los id de los logros ir sacando toda la información.

Puede que tu solución sea más visible y nos ahorramos un model. Mañana me pongo a probar esto.

jcorreas commented 3 years ago

Respecto al último mensaje de Enrique, los puntos 3 y 4 que ha mencionado Enrique son claramente los que requieren pensarlo un poco más despacio. Por una parte, estaría bien separar el código de cada logro para poder añadir nuevos tipos de logros más fácilmente en el futuro (aunque sean "atornillados" en el código). Por otra parte, los puntos 3 y 4 parece que son realmente el mismo: cada vez que se acepta un envío, debería recalcular si se ha obtenido alguno de los logros no conseguidos hasta el momento. Enrique, ¿son necesarios los dos métodos?

Dashito14 commented 3 years ago

Yo he entendido el punto 4 como una especie de "Refrescar" en el que se comprueben todos los logros de todos los usuarios. Lo he entendido como un método que no se va a invocar cada vez que se consigue un logro o un envío, si no una especie de botón o algo por el estilo que sirva para refrescar todos los logros de todos los usuarios. Si no era esto que Enrique me corrija por favor.

Por otra parte el punto 3 sí que lo he entendido como un método que se va a llamar todas las veces que un usuario haga un envío y que compruebe si gracias a ese envío se ha conseguido un nuevo logro, llamar al método que compruebe todos los envíos en este caso cada vez yo creo que sería sobrecargar la página.

emartinm commented 3 years ago

Sí, yo tenía en mente lo que mencionaba @Dashito14 : un método que recibe un envío y comprueba si ese envío es merecedor de logro, y otro que no recibe nada y recorre todos los envíos de todos los usuarios comprobando que los logros están actualizados con la definición de logro actual (sería como borrar todos y recalcular, por si hemos cambiado la definición de algún logro).

Pensando en la idea de tener una lista de logros, le he dado una vuelta y creo que he madurado una organización del código que permite tener logros configurables por el profesor (hasta cierto punto) sin dejar de ser una "lista de logros" recorrible fácilmente. Para ellos tenemos dos clases, una que define cómo se consigue un logro (AchievementDefinition) y otra que almacena la consecución de un logro por un usuario en un momento dado (ObtainedAchievement):

  1. AchievementDefinition: clase abstracta que representa la definición de un logro. Contendrá atributos para almacenar su nombre y descripción, y además tendrá métodos a definir en las clases hijas para:
    • check(submission): comprobar si el envío concreto es merecedor de este logro, almacenando un objeto ObtainedAchievement en caso afirmativo
    • check_user(user): True/False indicando si el usuario indicado tiene ese logro (mirando los objetos ObtainedAchievement para que sea rápido)
    • refresh(): revisa todos los envíos hasta el momento para revisar si alguno de ellos era merecedor de este logro (la idea de borrar y crear de nuevo)
  2. ObtainedAchievement: simplemente almacena la información de un logro conseguido. Contiene la fecha, el usuario y la definición del logro conseguido (objeto AchievementDefinition)

Para añadir logros concretos en el sistema hay que crear clases hijas de AchievementDefinition. Por ejemplo:

(Las descripciones podrían ser opcionales y que si no se las pasas las genere automáticamente a partir de los parámetros)

Creo que esta organización tiene varios puntos positivos.

Seguramente no sea lo más eficiente, pero creo que es lo más flexible y sencillo. ¿Podéis ver algún problema de esta organización?

Siento el mensaje tan largo :-s

Dashito14 commented 3 years ago

Tiene buena pìnta, pero creo que las cosas que defines como "sencillas" quizás se me compliquen un poco. Voy a ir avanzando a lo largo de la semana y a ver si no tengo problema con todo esto. No sé si me dará tiempo en una semana a realizarlo todo para seguir con el planning.

La función para recomprobar todos los logros, ¿sigue habiendo que incluirla no? Y para esto, ¿implemento un botón al profesor o como lo hago?

emartinm commented 3 years ago

Tiene buena pìnta, pero creo que las cosas que defines como "sencillas" quizás se me compliquen un poco.

Me refiero a "conceptualmente sencillas", es decir, que las conexiones entre componentes son claras. Eso no quita que alguna sentencia o recorrido se complique.

Voy a ir avanzando a lo largo de la semana y a ver si no tengo problema con todo esto. No sé si me dará tiempo en una semana a realizarlo todo para seguir con el planning.

Bueno, vé avanzando y si encuentras dificultades que no sabes resolver avísanos.

La función para recomprobar todos los logros, ¿sigue habiendo que incluirla no? Y para esto, ¿implemento un botón al profesor o como lo hago?

Según la idea de mi largo mensaje, se debe hacer de manera automáticamente cada vez que se almacena un AchievementDefinition en la base de datos a través de la interfaz de admin, porque realmente es el único momento en el que es necesaria, ¿no? Para hacer eso de manera automática puedes invocarlo dentro del método clean() del modelo (https://docs.djangoproject.com/en/3.1/ref/models/instances/#django.db.models.Model.clean). Hay ejemplos de clean() en otros modelos del juez.

Dashito14 commented 3 years ago

Buenas, estaba empezando a probar un poco el funcionamiento de lo que he ido haciendo, como era de esperar hay errores, pero uno de ellos no soy capaz de solucionarlo. Tengo un error de importaciones circulares, ya que en models.py estoy importando dos funciones de views.py y en views.py estamos utilizando models.py. ¿Cómo hago para utilizar estas funciones de view.py en models.py?

image image

Dashito14 commented 3 years ago

Ya lo he solucionado, de hecho he simplificado mucho el código.

jcorreas commented 3 years ago

No concozco mucho Python, pero he echado un vistazo y he visto este mensaje en stackoverflow:

https://stackoverflow.com/questions/894864/circular-dependency-in-python

Remiten a un artículo antiguo (https://web.archive.org/web/20150113060057/http://effbot.org/zone/import-confusion.htm) en el que dan como solución mover uno de los imports al final del archivo. Creo que es un poco chapu.

Creo que en Python 3.7 hay una solución un poco más elegante. Prueba esto:

from future import annotations

También mencionan otro artículo interesante, más moderno: https://www.stefaanlippens.net/circular-imports-type-hints-python.html

emartinm commented 3 years ago

¿Exactamente por qué models.py importa views? Me resulta extraño. La otra dirección sí que tiene sentido, pero está no me cuadra.

Dashito14 commented 3 years ago

Ahora ya lo he solucionado. Pero en su momento lo había importado por que en mi función check() (A la cual he tenido que cambiar el nombre porque Django tiene un método check() por defecto y se sobreescribía), utilizaba una función que Iker había creado en views. Ahora ya lo he simplicado utilizando filter.

emartinm commented 3 years ago

Ahora ya lo he solucionado. Pero en su momento lo había importado por que en mi función check() (A la cual he tenido que cambiar el nombre porque Django tiene un método check() por defecto y se sobreescribía), utilizaba una función que Iker había creado en views. Ahora ya lo he simplicado utilizando filter.

Ah, claro, es verdad, para reutilizar código que calculaba número de problemas resueltos y cosas así. Como el código de Iker hacía eso y más cosas, si has podido extraer justo lo que necesitabas y representarlo como una consulta ORM seguro que ha quedado más simple y compacto.

Dashito14 commented 3 years ago

Sí, de hecho ha quedado reducido incluso en 3 o 4 líneas.

Vengo con otra duda. Ya he creado un logro para empezar a probar el código, y también he conseguido que el primer logro se almacene cuando se consigue, adjunto fotos.

image image

Yo creo que en la segunda imagen, en Achievement Definition debería salir otra cosa pero me ha almacenado ese objeto que no enlaza con el logro que ha conseguido.

En la siguiente imagen muestro como estoy guardando este objeto.

image

Después de esto, he intentado comprobar si me funcionaba bien otra función, la que comprueba si el usuario ya tiene el logro. y aquí es donde me ha saltado el problema que ya no sé resolver.

image image

Yo creo que tiene algo que ver con que se me almacene ese tipo de objeto que he mostrado en la segunda imagen. Viendo páginas he visto que posiblemente sea debido a que estoy intentando desempaquetar un objeto nulo. Pero en la base de datos sí que está almacenado, así que no sé por donde puedo tirar.

emartinm commented 3 years ago

Yo creo que lo que te sale en la segunda imagen está bien, es un logro conseguido que contiene el objeto AchievementDefinition asociado. Lo que pasa es que por defecto la representación textual de los objetos modelo es poco informativa, en este caso AchievementDefinition object(1). Para que lo represente de una manera más entendible en admin, por ejemplo incluyendo el nombre del logro, debes definir la función __str__ de AchievementDefinition, que es el toString() de Python. Puedes ver ejemplos en otro modelos como Submission.

Con respecto al segundo fallo, all_objets es un iterable de objetos ObtainedAchievement, no de tuplas ni de listas. No puedes desmpaquetar un objeto, debes acceder a sus atributos:

for achievement in all_objects:
    if achievement.user == ....

Aprovecho para recomendar cambiar el nombre all_objects por algo más específico, y usar un filter en lugar de un all y luego recorrer logros que son de otros usuarios. De hecho lo ideal es conseguir una consulta ORM que te devuelva directamente los logros de usr asociados a self.

Dashito14 commented 3 years ago

Estoy intentando pasar un usuario por la URL, ya que no siempre voy a llegar a esa vista para ver mis logros personales y tengo que saber de que usuario quiero los logros. He intentado hacerlo de la siguiente forma y me da error, esta forma es la que he visto en las guías, se me debe estar pasando algo por alto.

urls.py path('achievements/<int:user_id>', views.show_achievements, name='achievements')

_basemenu.html <a class="dropdown-item" href="{% url 'judge:achievements' '{{ request.user.pk }}' %}">Mis logros</a>

views.py

@login_required
def show_achievements(request, user_id):
    return render(request, 'achievements.html', {'user': user_id})

El error image

Dashito14 commented 3 years ago

Ya está solucionado lo de arriba.

He hablado con los compañeros y hemos pensado que la mejor forma para mostrar el número de logros en el ranking es de la siguiente forma:

image

Había probado a poner las medallas estilo militar como decías, pero si se agregan muchos logros y un usuario consigue, por ejemplo, 10, esa columna queda muy deforme y no queda bien a la vista.

Dashito14 commented 3 years ago

Al hacer el clean(), llamo a la función refresh(), la cual sí que funciona, pero el clean() se hace antes de crear el objeto, por tanto no llega a ver si algún usuario tiene este logro porque aún no está en la base de datos.

emartinm commented 3 years ago

image Había probado a poner las medallas estilo militar como decías, pero si se agregan muchos logros y un usuario consigue, por ejemplo, 10, esa columna queda muy deforme y no queda bien a la vista.

El problema visual que le veo a la columna de logros es que no resalta, es decir, todo usuario tiene algo en la columna "Logros" aunque sea un 0. Y no llamaría tanto la atención como tener un icono al lado cuando los demás no lo tienen. Se me ocurren dos maneras de mantener el icono, a ver qué te parecen:

  1. Ponerlos del menor tamaño posible y debajo del nombre del usuario en lugar de a su lado, para que ocupen menos aunque tengan 10.
  2. Poner un único icono más grande junto al nombre seguido de un "x3" o "x5.

Además, sería interesante poder pinchar en el nombre del usuario (o sus logros) y acceder a su página de logros para conocer los detalles.

Al hacer el clean(), llamo a la función refresh(), la cual sí que funciona, pero el clean() se hace antes de crear el objeto, por tanto no llega a ver si algún usuario tiene este logro porque aún no está en la base de datos.

Tienes toda la razón, pensaba que clean iba a ser suficiente pero no. Entonces habrá que utilizar señales (https://docs.djangoproject.com/en/3.1/topics/signals/#connecting-to-signals-sent-by-specific-senders) de tal manera que después de que se salve un objeto de tipo AchievementDefinition (esa señal creo que se llama post_save https://docs.djangoproject.com/en/3.1/ref/signals/#post-save) se invoque a refresh. Como el refresh borra los logros almacenados antiguos y los recalcula de nuevo, funcionará si un profesor edita un AchievementDefinition y pasa de necesitar 5 aceptados a 3, por ejemplo.

Por separación, define la conexión de estas señales en un módulo aparte signals.py.

Dashito14 commented 3 years ago

image ¿Así mejor?

Dashito14 commented 3 years ago

He hecho esta función, supongo que le faltará alkguna cosa wue debuguear. Pero lo importante es que directamente no me entra aquí. Por eso está el print('HOLA'), nunca llega a mostrármelo. Viendo ejemplos por la web estoy viendo que lo único que hay que poner es lo que he puesto antes de la función, pero ni así...

image

Dashito14 commented 3 years ago

Lo he hecho sin signal y me funciona bien. He creado una función save() que sobreescribe el save() de Django. Bueno, más que sobreescribir, llama primero al save() y acto seguido hace los cambios necesarios.

Dashito14 commented 3 years ago

Viendo que test_views tiene 1000 líneas he pensado en hacer un módulo aparte con los tests para los logros. Así es más fácil controlar todos los tests, que empiezan a acumularse.

emartinm commented 3 years ago

image ¿Así mejor?

A mi me gusta más así. Podemos pensar entre todos si el color azul es mejor que un dorado para el trofeo. Y para diferenciar más a los alumnos con logros de los que no, a los que tengan cero no les pondrían nada más que su nombre, para que los demás destaquen.

He hecho esta función, supongo que le faltará alkguna cosa wue debuguear. Pero lo importante es que directamente no me entra aquí.

Quizá sea porque los callbacks deben tener únicamente 2 parámetros y el tuyo tiene 3, como se ve en el ejemplo de la documentación:

def my_callback(sender, **kwargs):

Entiendo que el resto de parámetros de post_save (https://docs.djangoproject.com/en/3.1/ref/signals/#django.db.models.signals.post_save) salvo sender los tienes que sacar del diccionario kwargs. ¿No te aparecía algún warninng al ejecutar un save con las señales? Haz una prueba cambiando los parámetros, a ver si así funciona. El caso es que me interesa esto de las señales, voy a ver si hago pruebas.

Viendo que test_views tiene 1000 líneas he pensado en hacer un módulo aparte con los tests para los logros. Así es más fácil controlar todos los tests, que empiezan a acumularse.

Me parece sensatísimo :-) De hecho incluso te puedes llevar a ese nuevo módulo test_rankings.py los tests que haya en test_views que tengan que ver con el ranking, ya que están todos conectados. @Tamiflu9 coordina con @Dashito14 para que tus tests de descargar el ranking acaben también en este nuevo módulo

emartinm commented 3 years ago

Con respecto a las señales, estoy seguro que no se ejecutaban por la aridad de tu callback. Acabo de hacer un ejemplo mínimo sobre Submission y sí que se ejecuta el código:

from django.db.models.signals import post_save
from django.dispatch import receiver

@receiver(post_save, sender=Submission)
def my_handler(sender, **kwargs):
    print('Se ha salvado una submission')
    print(kwargs['instance'])
Dashito14 commented 3 years ago

Vaya, vale. Es que he estado viendo muchos ejemplos (este uno de ellos por ejemplo https://es.stackoverflow.com/questions/1878/c%C3%B3mo-trabajar-con-signals-post-save) y en él pasan más argumentos, dependiendo de lo que quisieras. Ahora vuelvo a probar a cambiar todo eso.

En cuanto al color lo puedo cambiar sin mayor problema, el azul se ha puesto por el enlace.

Ahora cambio también lo de que no salga trofeo.

emartinm commented 3 years ago

Vaya, vale. Es que he estado viendo muchos ejemplos (este uno de ellos por ejemplo https://es.stackoverflow.com/questions/1878/c%C3%B3mo-trabajar-con-signals-post-save) y en él pasan más argumentos, dependiendo de lo que quisieras. Ahora vuelvo a probar a cambiar todo eso.

Para todos: @Dashito14 , @ivarui01 y @Tamiflu9

Tened cuidado cuando encontréis ayuda en posts antiguos (ese tiene 5 años) porque Django ha evolucionado bastante desde entonces. Por ejemplo, en 2017 salía la versión 1.11 y ahora estamos usando la 3.11. Cuando encontréis algo que no mencione expresamente la versión de Django utilizada, acudir a la documentación de Django (https://docs.djangoproject.com/en/3.1/) para confirmar que siguen funcionando.

emartinm commented 3 years ago

En cuanto al color lo puedo cambiar sin mayor problema, el azul se ha puesto por el enlace.

Probemos entonces el mismo dorado que definió Iván para las medallas, a ver qué tal queda.

Dashito14 commented 3 years ago

No hay forma de que me funcione...

image

Dashito14 commented 3 years ago

El problema es al crearlo en otro archivo, si lo creo en el mismo en el que está el modelo NumSolvedAchievementDefinition sí que lo hace bien.

Dashito14 commented 3 years ago

He encontrado esto pero no sé si lo habías hecho tú así para que funcionase.

Además no encuentro ni la función ready() ni algo donde ponerlo en __init__.py, y al ser algo que habías hecho tú `prefiero esperar a que me digas qué tocar ahí.

jcorreas commented 3 years ago

En cuanto al color lo puedo cambiar sin mayor problema, el azul se ha puesto por el enlace.

Probemos entonces el mismo dorado que definió Iván para las medallas, a ver qué tal queda.

Respecto a las medallas, estoy de acuerdo en que sean en dorado (o incluso en amarillo fuerte) y solo para los que multiplican por algo positivo, para que se distingan algo del resto.

emartinm commented 3 years ago

Pues yo lo que había hecho era meterlo dentro de models.py para la prueba rápida, era trampa :-|

Ese método ready() (ver ejemplo en https://docs.djangoproject.com/en/3.1/ref/applications/#django.apps.AppConfig.ready) lo tienes que definir en https://github.com/emartinm/lsql/blob/8d5bea30f5d367f91d6877227f4834f70e8b9bb8/lsql/judge/apps.py#L4

De hecho, como estás usando el decorador receiver en tu callback del módulo signals, en esa función ready() únicamente tendrás que incluir un import judge.signals (o import .signals, no sé cuál es mejor).

Dashito14 commented 3 years ago

Esto es lo que había hecho pero sale así

image

También intenté esto por si acaso pero da error igualmente: image

Si le quitas el judge se queda como en la primera imagen.

emartinm commented 3 years ago

¿Exactamente qué error te da en tiempo de ejecución? ¿O es únicamente PyCharm el que no encuentra los módulos?

Otra opción es registrar las señales con connect (ver https://docs.djangoproject.com/en/3.1/topics/signals/#connecting-receiver-functions y https://docs.djangoproject.com/en/3.1/topics/signals/#django.dispatch.Signal.connect) dentro de ready y quitarse el decorador.

Dashito14 commented 3 years ago

No me lo puedo creer, llevo toda la tarde con esto y era un error de PyCharm, literalmente estaba bien y por verlo mal no llegué a ejecutarlo. Mañana sigo haciendo pruebas a ver si es cierto que ya funciona.