Spaces:
Sleeping
Sleeping
Creando controlador para api rating, renombrando campo en tecnica
Browse files- tecnicas/controllers/__init__.py +2 -1
- tecnicas/controllers/models_controller/calificacion_controller.py +28 -1
- tecnicas/controllers/models_controller/dato_controller.py +21 -4
- tecnicas/controllers/views_controller/api_rating_controller.py +8 -0
- tecnicas/migrations/0019_rename_repecion_tecnica_repeticion_and_more.py +24 -0
- tecnicas/models/tecnica.py +2 -2
- tecnicas/static/js/created-scale.js +11 -1
- tecnicas/templates/tecnicas/forms_tester/convencional.html +5 -39
- tecnicas/utils/__init__.py +1 -0
- tecnicas/utils/general_controllers.py +9 -0
- tecnicas/views/apis/rating_word.py +41 -4
tecnicas/controllers/__init__.py
CHANGED
|
@@ -14,4 +14,5 @@ from .models_controller.dato_controller import DatoController
|
|
| 14 |
|
| 15 |
from .views_controller.detalles_sesion_controller import DetallesSesionController
|
| 16 |
from .views_controller.login_tester_controller import LoginTesterController
|
| 17 |
-
from .views_controller.main_tester_form_controller import MainTesterFormController
|
|
|
|
|
|
| 14 |
|
| 15 |
from .views_controller.detalles_sesion_controller import DetallesSesionController
|
| 16 |
from .views_controller.login_tester_controller import LoginTesterController
|
| 17 |
+
from .views_controller.main_tester_form_controller import MainTesterFormController
|
| 18 |
+
from .views_controller.api_rating_controller import ApiRatingController
|
tecnicas/controllers/models_controller/calificacion_controller.py
CHANGED
|
@@ -1,9 +1,36 @@
|
|
| 1 |
from ...models import Calificacion, Tecnica, Posicion, Producto, Catador
|
| 2 |
-
from ...utils import controller_error
|
|
|
|
| 3 |
from collections import defaultdict
|
| 4 |
|
| 5 |
|
| 6 |
class CalificacionController():
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7 |
@staticmethod
|
| 8 |
def getRatingsByTechnique(technique: Tecnica):
|
| 9 |
repetition = technique.repecion
|
|
|
|
| 1 |
from ...models import Calificacion, Tecnica, Posicion, Producto, Catador
|
| 2 |
+
from ...utils import controller_error, getId
|
| 3 |
+
from django.core.exceptions import ValidationError
|
| 4 |
from collections import defaultdict
|
| 5 |
|
| 6 |
|
| 7 |
class CalificacionController():
|
| 8 |
+
def __init__(self, product: Producto | int, technique: Tecnica | int, tester: Catador | int):
|
| 9 |
+
atributes = {
|
| 10 |
+
"num_repeticion": 0,
|
| 11 |
+
"id_tecnica_id": getId(technique),
|
| 12 |
+
"id_producto_id": getId(product),
|
| 13 |
+
"id_catador_id": getId(tester),
|
| 14 |
+
}
|
| 15 |
+
|
| 16 |
+
self.rating = Calificacion(**atributes)
|
| 17 |
+
|
| 18 |
+
def setRepetition(self, repetition):
|
| 19 |
+
try:
|
| 20 |
+
self.rating.full_clean()
|
| 21 |
+
if not repetition:
|
| 22 |
+
self.rating.num_repeticion = self.rating.id_tecnica.repecion
|
| 23 |
+
except ValidationError as e:
|
| 24 |
+
return controller_error(e.message)
|
| 25 |
+
|
| 26 |
+
def saveRating(self):
|
| 27 |
+
try:
|
| 28 |
+
self.rating.full_clean()
|
| 29 |
+
self.rating.save()
|
| 30 |
+
return self.rating
|
| 31 |
+
except ValidationError as e:
|
| 32 |
+
return controller_error(e.message)
|
| 33 |
+
|
| 34 |
@staticmethod
|
| 35 |
def getRatingsByTechnique(technique: Tecnica):
|
| 36 |
repetition = technique.repecion
|
tecnicas/controllers/models_controller/dato_controller.py
CHANGED
|
@@ -1,16 +1,33 @@
|
|
| 1 |
-
from ...models import Calificacion, Dato
|
| 2 |
-
from ...utils import controller_error
|
|
|
|
| 3 |
|
| 4 |
|
| 5 |
class DatoController():
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6 |
@staticmethod
|
| 7 |
def getRerecordedData(ratings: list[Calificacion]):
|
| 8 |
if not ratings:
|
| 9 |
return []
|
| 10 |
-
|
| 11 |
ids_ratings = [rat.id for rat in ratings]
|
| 12 |
|
| 13 |
recoreded_data = list(Dato.objects.filter(
|
| 14 |
id_calificacion_id__in=ids_ratings))
|
| 15 |
-
|
| 16 |
return recoreded_data
|
|
|
|
| 1 |
+
from ...models import Calificacion, Dato, Palabra
|
| 2 |
+
from ...utils import controller_error, getId
|
| 3 |
+
from django.core.exceptions import ValidationError
|
| 4 |
|
| 5 |
|
| 6 |
class DatoController():
|
| 7 |
+
def __init__(self, word: Palabra | int, rating: Calificacion | int):
|
| 8 |
+
atributes = {
|
| 9 |
+
"id_palabra_id": getId(word),
|
| 10 |
+
"id_calificacion_id": getId(rating)
|
| 11 |
+
}
|
| 12 |
+
|
| 13 |
+
self.data = Dato(**atributes)
|
| 14 |
+
|
| 15 |
+
def saveData(self):
|
| 16 |
+
try:
|
| 17 |
+
self.data.full_clean()
|
| 18 |
+
self.data.save()
|
| 19 |
+
return self.data
|
| 20 |
+
except ValidationError as e:
|
| 21 |
+
return controller_error(e.message)
|
| 22 |
+
|
| 23 |
@staticmethod
|
| 24 |
def getRerecordedData(ratings: list[Calificacion]):
|
| 25 |
if not ratings:
|
| 26 |
return []
|
| 27 |
+
|
| 28 |
ids_ratings = [rat.id for rat in ratings]
|
| 29 |
|
| 30 |
recoreded_data = list(Dato.objects.filter(
|
| 31 |
id_calificacion_id__in=ids_ratings))
|
| 32 |
+
|
| 33 |
return recoreded_data
|
tecnicas/controllers/views_controller/api_rating_controller.py
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from ...models import Calificacion
|
| 2 |
+
from ...controllers import CalificacionController, DatoController
|
| 3 |
+
|
| 4 |
+
|
| 5 |
+
class ApiRatingController():
|
| 6 |
+
def __init__(self, _rating_controller: CalificacionController, _data_controller: DatoController):
|
| 7 |
+
self.rating_controller = _rating_controller
|
| 8 |
+
self.data_controller = _data_controller
|
tecnicas/migrations/0019_rename_repecion_tecnica_repeticion_and_more.py
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Generated by Django 5.2.1 on 2025-09-28 15:18
|
| 2 |
+
|
| 3 |
+
import shortuuid.main
|
| 4 |
+
from django.db import migrations, models
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
class Migration(migrations.Migration):
|
| 8 |
+
|
| 9 |
+
dependencies = [
|
| 10 |
+
('tecnicas', '0018_alter_sesionsensorial_codigo_sesion_participacion'),
|
| 11 |
+
]
|
| 12 |
+
|
| 13 |
+
operations = [
|
| 14 |
+
migrations.RenameField(
|
| 15 |
+
model_name='tecnica',
|
| 16 |
+
old_name='repecion',
|
| 17 |
+
new_name='repeticion',
|
| 18 |
+
),
|
| 19 |
+
migrations.AlterField(
|
| 20 |
+
model_name='sesionsensorial',
|
| 21 |
+
name='codigo_sesion',
|
| 22 |
+
field=models.CharField(default=shortuuid.main.ShortUUID.uuid, editable=False, max_length=22, primary_key=True, serialize=False),
|
| 23 |
+
),
|
| 24 |
+
]
|
tecnicas/models/tecnica.py
CHANGED
|
@@ -8,7 +8,7 @@ class Tecnica(models.Model):
|
|
| 8 |
tipo_tecnica = models.ForeignKey(
|
| 9 |
TipoTecnica, on_delete=models.CASCADE, related_name="tecnica_tipo_tecnica")
|
| 10 |
repeticiones_max = models.IntegerField(default=0)
|
| 11 |
-
|
| 12 |
limite_catadores = models.IntegerField()
|
| 13 |
instrucciones = models.CharField(max_length=255)
|
| 14 |
id_estilo = models.ForeignKey(
|
|
@@ -21,7 +21,7 @@ class Tecnica(models.Model):
|
|
| 21 |
return {
|
| 22 |
"tipo_tecnica": self.tipo_tecnica,
|
| 23 |
"repeticiones_max": self.repeticiones_max,
|
| 24 |
-
"
|
| 25 |
"limite_catadores": self.limite_catadores,
|
| 26 |
"instrucciones": self.instrucciones,
|
| 27 |
"id_estilo": self.id_estilo,
|
|
|
|
| 8 |
tipo_tecnica = models.ForeignKey(
|
| 9 |
TipoTecnica, on_delete=models.CASCADE, related_name="tecnica_tipo_tecnica")
|
| 10 |
repeticiones_max = models.IntegerField(default=0)
|
| 11 |
+
repeticion = models.IntegerField(default=0)
|
| 12 |
limite_catadores = models.IntegerField()
|
| 13 |
instrucciones = models.CharField(max_length=255)
|
| 14 |
id_estilo = models.ForeignKey(
|
|
|
|
| 21 |
return {
|
| 22 |
"tipo_tecnica": self.tipo_tecnica,
|
| 23 |
"repeticiones_max": self.repeticiones_max,
|
| 24 |
+
"repeticion": self.repeticion,
|
| 25 |
"limite_catadores": self.limite_catadores,
|
| 26 |
"instrucciones": self.instrucciones,
|
| 27 |
"id_estilo": self.id_estilo,
|
tecnicas/static/js/created-scale.js
CHANGED
|
@@ -46,7 +46,17 @@ async function sendRating(word) {
|
|
| 46 |
const dataForm = new FormData(formRatingWord);
|
| 47 |
const url = "/cata/testers/api/ratingword";
|
| 48 |
|
| 49 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 50 |
|
| 51 |
try {
|
| 52 |
const respone = await fetch(url, {
|
|
|
|
| 46 |
const dataForm = new FormData(formRatingWord);
|
| 47 |
const url = "/cata/testers/api/ratingword";
|
| 48 |
|
| 49 |
+
const codeProduct = document
|
| 50 |
+
.querySelector(".ct-product-rating")
|
| 51 |
+
.querySelector(".code-product").textContent;
|
| 52 |
+
const idProduct = document
|
| 53 |
+
.querySelector(".ct-product-rating")
|
| 54 |
+
.querySelector(".id-product").textContent;
|
| 55 |
+
|
| 56 |
+
const idWord = formRatingWord.querySelector(".id-word").textContent;
|
| 57 |
+
|
| 58 |
+
dataForm.set("info-product", { code: codeProduct, id: idProduct });
|
| 59 |
+
dataForm.set("info-word", { name: word, id: idWord });
|
| 60 |
|
| 61 |
try {
|
| 62 |
const respone = await fetch(url, {
|
tecnicas/templates/tecnicas/forms_tester/convencional.html
CHANGED
|
@@ -44,43 +44,6 @@
|
|
| 44 |
</article>
|
| 45 |
{% endif %}
|
| 46 |
|
| 47 |
-
<article class="hidden">
|
| 48 |
-
<ul class="list-words">
|
| 49 |
-
{% for word in words %}
|
| 50 |
-
<li class="item-word">
|
| 51 |
-
<p class="word-id">
|
| 52 |
-
{{ word.id }}
|
| 53 |
-
</p>
|
| 54 |
-
<p class="word-name">
|
| 55 |
-
{{ word.nombre_palabra }}
|
| 56 |
-
</p>
|
| 57 |
-
</li>
|
| 58 |
-
{% endfor %}
|
| 59 |
-
</ul>
|
| 60 |
-
|
| 61 |
-
<ul class="list-tags">
|
| 62 |
-
{% for tag in tags %}
|
| 63 |
-
<li class="item-tag">
|
| 64 |
-
<p class="tag-id">
|
| 65 |
-
{{ tag.posicion }}
|
| 66 |
-
</p>
|
| 67 |
-
<p class="tag-name">
|
| 68 |
-
{{ tag.id_etiqueta }}
|
| 69 |
-
</p>
|
| 70 |
-
</li>
|
| 71 |
-
{% endfor %}
|
| 72 |
-
</ul>
|
| 73 |
-
|
| 74 |
-
<div class="scale-data">
|
| 75 |
-
<p class="scale-type">
|
| 76 |
-
{{ scale.id_tipo_escala }}
|
| 77 |
-
</p>
|
| 78 |
-
<p class="scale-size">
|
| 79 |
-
{{ scale.longitud }}
|
| 80 |
-
</p>
|
| 81 |
-
</div>
|
| 82 |
-
</article>
|
| 83 |
-
|
| 84 |
<article class="rounded flex flex-col gap-4">
|
| 85 |
<section class="flex items-center justify-center bg-gray-200 p-2 rounded-lg">
|
| 86 |
<p class="text-lg font-medium text-center">
|
|
@@ -92,8 +55,9 @@
|
|
| 92 |
<p class="text-lg font-bold text-center">
|
| 93 |
Producto:
|
| 94 |
</p>
|
| 95 |
-
<p class="text-2xl font-bold text-center">
|
| 96 |
-
{{ product }}
|
|
|
|
| 97 |
</p>
|
| 98 |
</div>
|
| 99 |
<div class="bg-gray-200 p-2 rounded-lg flex-1">
|
|
@@ -115,6 +79,8 @@
|
|
| 115 |
<article class="bg-gray-200 p-6 rounded-lg mb-3 w-fit">
|
| 116 |
<label for="id-range-word-{{word}}"
|
| 117 |
class="text-xl font-bold tracking-wide block mb-6 first-letter:uppercase">{{ word }}</label>
|
|
|
|
|
|
|
| 118 |
|
| 119 |
<section class="block">
|
| 120 |
<div class="relative">
|
|
|
|
| 44 |
</article>
|
| 45 |
{% endif %}
|
| 46 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 47 |
<article class="rounded flex flex-col gap-4">
|
| 48 |
<section class="flex items-center justify-center bg-gray-200 p-2 rounded-lg">
|
| 49 |
<p class="text-lg font-medium text-center">
|
|
|
|
| 55 |
<p class="text-lg font-bold text-center">
|
| 56 |
Producto:
|
| 57 |
</p>
|
| 58 |
+
<p class="text-2xl font-bold text-center ct-product-rating">
|
| 59 |
+
<span class="code-product">{{ product }}</span>
|
| 60 |
+
<span class="hidden id-product">{{ product.id }}</span>
|
| 61 |
</p>
|
| 62 |
</div>
|
| 63 |
<div class="bg-gray-200 p-2 rounded-lg flex-1">
|
|
|
|
| 79 |
<article class="bg-gray-200 p-6 rounded-lg mb-3 w-fit">
|
| 80 |
<label for="id-range-word-{{word}}"
|
| 81 |
class="text-xl font-bold tracking-wide block mb-6 first-letter:uppercase">{{ word }}</label>
|
| 82 |
+
|
| 83 |
+
<span class="hidden id-word" >{{ word.id }}</span>
|
| 84 |
|
| 85 |
<section class="block">
|
| 86 |
<div class="relative">
|
tecnicas/utils/__init__.py
CHANGED
|
@@ -2,3 +2,4 @@ from .code_generate import generarCodigo
|
|
| 2 |
from .code_generate import generarCodigos
|
| 3 |
from .personal_errors import general_error, controller_error
|
| 4 |
from .shuffle_arrays import shuffleArray
|
|
|
|
|
|
| 2 |
from .code_generate import generarCodigos
|
| 3 |
from .personal_errors import general_error, controller_error
|
| 4 |
from .shuffle_arrays import shuffleArray
|
| 5 |
+
from .general_controllers import getId
|
tecnicas/utils/general_controllers.py
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
def getId(value: object | int) -> int | None:
|
| 2 |
+
if isinstance(value, int):
|
| 3 |
+
return value
|
| 4 |
+
elif hasattr(value, "id"):
|
| 5 |
+
return value.id
|
| 6 |
+
elif hasattr(value, "pk"):
|
| 7 |
+
return value.pk
|
| 8 |
+
|
| 9 |
+
return None
|
tecnicas/views/apis/rating_word.py
CHANGED
|
@@ -1,12 +1,49 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
from django.http import HttpRequest, JsonResponse
|
|
|
|
| 2 |
|
| 3 |
|
| 4 |
def reatingWord(req: HttpRequest):
|
| 5 |
if req.method == "POST":
|
| 6 |
-
if not req.POST["rating-word"]:
|
| 7 |
-
return JsonResponse({"error": "No se
|
| 8 |
-
|
| 9 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
return JsonResponse({
|
| 11 |
"message": "Ok",
|
| 12 |
"data": {
|
|
|
|
| 1 |
+
'''
|
| 2 |
+
**** Para este endpoint es necesario:
|
| 3 |
+
**** ****
|
| 4 |
+
|
| 5 |
+
* Manejar el metodo POST
|
| 6 |
+
* Recibir los siguientes datos
|
| 7 |
+
- ID y Codigo del producto calificando
|
| 8 |
+
- ID y nombre de la palabra que se califico
|
| 9 |
+
- Valor de calificacion que se dio
|
| 10 |
+
- Valor numerico asociado a escalas de rango
|
| 11 |
+
- Valor booleano asociado a escalas esctructuradas
|
| 12 |
+
* Dentro de la sesion se debe tener
|
| 13 |
+
- ID del catador
|
| 14 |
+
- ID de la sesion, para acceder a la tecnica
|
| 15 |
+
* Crear una instancia de la calificacion a partir de
|
| 16 |
+
- Numero de repeticion
|
| 17 |
+
- Producto calificado
|
| 18 |
+
- Catodor
|
| 19 |
+
- Tecnica
|
| 20 |
+
* Cuando la instancia calificacion se haya creado, hacer otra instancia para dato con
|
| 21 |
+
- La palabra calificada
|
| 22 |
+
- La calificacion creada previamente
|
| 23 |
+
* Dependiendo de la escala o tecnica usada
|
| 24 |
+
- Guardar dato como valor decimal
|
| 25 |
+
- Guardar el dato como valor booleano
|
| 26 |
+
* Retornar un json con el mensaje de exito
|
| 27 |
+
* En caso de haber un error se manda un json con el error
|
| 28 |
+
* Calquier otro metodo que se maneje mandar un error
|
| 29 |
+
'''
|
| 30 |
from django.http import HttpRequest, JsonResponse
|
| 31 |
+
from ...controllers import ApiRatingController, CalificacionController, DatoController
|
| 32 |
|
| 33 |
|
| 34 |
def reatingWord(req: HttpRequest):
|
| 35 |
if req.method == "POST":
|
| 36 |
+
if not req.POST["rating-word"] or not req.POST["info-product"] or not req.POST["info-word"]:
|
| 37 |
+
return JsonResponse({"error": "No se mandó información necesaria para la calificación"})
|
| 38 |
+
|
| 39 |
+
received_rating = req.POST["rating-word"]
|
| 40 |
+
received_word = req.POST["info-word"]
|
| 41 |
+
received_product = req.POST["info-word"]
|
| 42 |
+
|
| 43 |
+
view_controller = ApiRatingController(
|
| 44 |
+
CalificacionController(technique=req.session["id_techniqe"], product=received_product.id)
|
| 45 |
+
)
|
| 46 |
+
|
| 47 |
return JsonResponse({
|
| 48 |
"message": "Ok",
|
| 49 |
"data": {
|