Aserrar el cuestionario web Meduza: una gu铆a paso a paso para principiantes

Mi nombre es Egor, soy un desarrollador Full-stack en Leader-ID. En este art铆culo, quiero compartir una receta simple para crear un cuestionario bello y conveniente basado en la web similar a los realizados por Meduza. 脡l sabe c贸mo mostrar estad铆sticas despu茅s de responder preguntas individuales, calcular la puntuaci贸n total, emitir comentarios, cargar datos para su an谩lisis y buscar resultados en redes sociales. Para lograr esto, eleg铆 Django, DRF, Python y la base de datos PostgreSQL.



Todos los detalles est谩n debajo del corte.

Despu茅s de una hora de mirar el ladrillo (sin embargo, una lecci贸n dif铆cil ) , el primer resultado apareci贸 en forma de modelos confeccionados, que se describieron en Dzhang despu茅s de diez minutos.

Si es un principiante, le aconsejo que siga el tutorial de Djnago , que describe c贸mo crear una encuesta paso a paso. Y despu茅s del tutorial DRF , para finalmente sumergirnos en el tema.

Entonces, en el proyecto, us茅:

  • Django 3.0.3. Para el backend;
  • django-rest-framework. Para crear rest-api;
  • Pit贸n
  • PostgreSQL como una base de datos;
  • Front-end: Nuxt.js, Axios, Element-UI.

Ahora los pasos


pip install Django: instala la biblioteca.

django-admin startproject core: crea un proyecto djang.

cd core: vaya al directorio con el proyecto.

grupos de startapp python manage.py: agregue una aplicaci贸n de sondeo.

A continuaci贸n, describimos los modelos en models.py en encuestas y creamos un serializador para DRF.

class Question(models.Model):
    title = models.CharField(max_length=4096)
    visible = models.BooleanField(default=False)
    max_points = models.FloatField()

    def __str__(self):
           return self.title

class Choice(models.Model):
    question = models.ForeignKey(Question, on_delete=models.DO_NOTHING)
    title = models.CharField(max_length=4096)
    points = models.FloatField()
    lock_other = models.BooleanField(default=False)

    def __str__(self):
        return self.title

class Answer(models.Model):
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.DO_NOTHING)
    question = models.ForeignKey(Question, on_delete=models.DO_NOTHING)
    choice = models.ForeignKey(Choice, on_delete=models.DO_NOTHING)
    created = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.choice.title


Texto del c贸digo aqu铆
from rest_framework import serializers
from .models import Answer, Question, Choice


class ChoiceSerializer(serializers.ModelSerializer):
    percent = serializers.SerializerMethodField()

    class Meta:
        model = Choice
        fields = ['pk', 'title', 'points', 'percent', 'lock_other', ]

    def get_percent(self, obj):
        total = Answer.objects.filter(question=obj.question).count()
        current = Answer.objects.filter(question=obj.question, choice=obj).count()
        if total != 0:
            return float(current * 100 / total)
        else:
            return float(0)


class QuestionSerializer(serializers.ModelSerializer):
    choices = ChoiceSerializer(many=True, source='choice_set', )

    class Meta:
        model = Question
        fields = ['pk', 'title', 'choices', 'max_points', ]


class AnswerSerializer(serializers.Serializer):
    answers = serializers.JSONField()

    def validate_answers(self, answers):
        if not answers:
            raise serializers.Validationerror("Answers must be not null.")
        return answers

    def save(self):
        answers = self.data['answers']
        user = self.context.user
        for question_id, in answers:  #     ,    
            question = Question.objects.get(pk=question_id)
            choices = answers[question_id]
            for choice_id in choices:
                choice = Choice.objects.get(pk=choice_id)
                Answer(user=user, question=question, choice=choice).save()
                user.is_answer = True
                user.save()


Luego escribimos dos vistas DRF en views.py, que dan todas las preguntas con opciones y aceptan todas las respuestas del usuario.


Texto del c贸digo aqu铆
from .serializers import QuestionSerializer, AnswerSerializer
from rest_framework.permissions import IsAuthenticated
from rest_framework.generics import GenericAPIView
from rest_framework.response import Response
from .models import Question


class GetQuestion(GenericAPIView):
    permission_classes = (IsAuthenticated,)
    serializer_class = QuestionSerializer

    def get(self, request, format=None):
        questions = Question.objects.filter(visible=True, )
        last_point = QuestionSerializer(questions, many=True)
        return Response(last_point.data)


class QuestionAnswer(GenericAPIView):
    permission_classes = (IsAuthenticated,)
    serializer_class = AnswerSerializer

    def post(self, request, format=None):
        answer = AnswerSerializer(data=request.data, context=request)
        if answer.is_valid(raise_exception=True):
            answer.save()
            return Response({'result': 'OK'})


Ahora describimos los enlaces en urls.py:

urlpatterns = [
    path('', GetQuestion.as_view()),
    path('answer/', QuestionAnswer.as_view()),
]

Agregue modelos a admin.py:


Texto del c贸digo aqu铆
from django.contrib import admin
from .models import Question, Answer, Choice


class QuestionAdmin(admin.ModelAdmin):
    list_display = (
        'title',
        'visible',
        'max_points',
    )


class ChoiceAdmin(admin.ModelAdmin):
    list_display = (
        'title',
        'question',
        'points',
        'lock_other',
    )
    list_filter = ('question',)


class AnswerAdmin(admin.ModelAdmin):
    list_display = (
        'user',
        'question',
        'choice',
    )
    list_filter = ('user',)


admin.site.register(Question, QuestionAdmin)
admin.site.register(Choice, ChoiceAdmin)
admin.site.register(Answer, AnswerAdmin)


El siguiente paso es agregar nuestra aplicaci贸n de encuestas a settings.py (en el directorio principal) en INSTALLED_APPS. Y ejecute el comando de lanzamiento:

  • python manage.py makemigrations: crea una migraci贸n para los modelos creados
  • python manage.py migrate: realiza una migraci贸n a la base de datos
  • python manage.py createduperuser - crea un superusuario (admin)
  • python manage.py runserver - inicia el servidor

Para calcular el puntaje total de las preguntas, agregamos al m茅todo una funci贸n de c谩lculo simple, de acuerdo con los puntos que se calculan. No publicar茅 el c贸digo de funci贸n, porque puede usarse para descifrar nuestro cuestionario. Ahora cada respuesta tiene su propio "peso".

Accedemos al panel de administraci贸n a trav茅s del navegador usando el enlace provisto en la consola ( http://127.0.0.1:8000 / admin por defecto), y creamos preguntas y respuestas a ellos, colocamos puntos.



Era importante para m铆 darles a nuestros socios listas de personas que completaron la encuesta y sus respuestas. Pero para esto, no es suficiente simplemente vincular las respuestas a las preguntas. Por lo tanto, agregu茅 otra tabla: "Opciones". Entonces se form贸 una conexi贸n entre las respuestas del usuario a las preguntas con varias opciones de respuesta. Esto nos permite cargar datos en la forma en que los socios pueden interpretarlos f谩cilmente.

Como resultado, la estructura de la base de datos result贸 as铆:


Ahora conecta el frente.

En 茅l eliminamos la lista de preguntas y respuestas, pasamos por cada elemento hasta el 煤ltimo. Dependiendo del tipo de pregunta, cambiamos el componente con su propia l贸gica y estilo. En consecuencia, cuando no quedan preguntas en la lista, enviamos el resultado al final y obtenemos una respuesta con el n煤mero de puntos. Despu茅s de recibir el n煤mero de puntos, abrimos la p谩gina de resultados, si hay puntos, ya no mostramos preguntas.

En esta etapa, ya tenemos un cuestionario listo que puede hacer todo lo necesario: hacer preguntas, recibir y recopilar respuestas, dar resultados en forma de puntos y comentarios.

Agregar bollos


En primer lugar, necesitaba cargar peri贸dicamente los datos. Para esto, acabo de agregar el comando de administraci贸n.

En segundo lugar, ser铆a bueno implementar el intercambio de resultados de la encuesta en las redes sociales. OKAY. Funcionalidad de corte que le permitir谩 compartir una imagen con puntos VKontakte y Facebook.

Generamos cien variantes de im谩genes que reflejan puntos para VK y Facebook por separado (diferentes resoluciones). Ahora conectamos la transferencia del enlace a la imagen en el componente social de la parte frontal. Con VKontakte, todo result贸 ser simple: pasamos el par谩metro de imagen con la URL directa a la deseada. Pero tuve que jugar con Facebook. Result贸 que no aceptan medios por API, y si transfir铆 una imagen o una imagen desde la URL de la imagen, se mostr贸 un gran campo vac铆o en la publicaci贸n. Como result贸 m谩s tarde, toma una imagen del metainf (og: imagen) del sitio en s铆, que comparti贸 (pasamos el par谩metro u en el enlace). Y ella, entre otras cosas, tuvo que ser cambiada din谩micamente. No quer铆a hacer redirecciones innecesarias y una mec谩nica en la parte posterior, y decid铆 convertir SPA (aplicaci贸n de una sola p谩gina) a SSR (renderizado del lado del servidor) en la parte delantera,de modo que, seg煤n la solicitud, la url de la imagen con una puntuaci贸n en head-meta cambia antes de que se inicie JavaScript en el navegador. Afortunadamente, el marco Nuxt.js tomado como base permite que esto se haga simplemente cambiando de modo. Ahora queda por dibujar etiquetas solo para clientes y agregar la l贸gica para cambiar la cabeza de la presencia de una puntuaci贸n de consulta.



Adem谩s, en el servidor, era necesario iniciar el servicio de daemon para proporcionar las p谩ginas generadas, y dejar las estad铆sticas tambi茅n en nginx. Todo beneficio!



Revivimos el cuestionario


Para mantener el nivel de inter茅s de los participantes en el proceso de completar la encuesta, agregu茅 una visualizaci贸n din谩mica de estad铆sticas a cada pregunta individual. Despu茅s de responder la pregunta, el usuario ve c贸mo respondieron los dem谩s. A veces no est谩 claro para una persona por qu茅 se le hacen estas preguntas. Por lo tanto, complet茅 cada pregunta con explicaciones divertidas. Bueno, el truco m谩s importante para revitalizar mi cuestionario fue realizado por los dise帽adores de nuestra empresa.



Resumen


Tales encuestas de medios son bastante simples de implementar y, lo m谩s importante, a los usuarios realmente les gustan. Se pueden usar tanto en la cola como en la melena: para investigaci贸n sociol贸gica, informar / probar conocimiento o crear elementos interactivos en sitios y servicios. Trat茅 de describir en detalle el proceso de su creaci贸n, pero si tiene alguna pregunta, bienvenido a comentar. Se pueden ver ejemplos de encuestas en este motor en estos dos enlaces: healthcare.leader-id.ru y covid.leader-id.ru .

All Articles