Sägen des Meduza-Web-Fragebogens: Eine Schritt-für-Schritt-Anleitung für Anfänger

Mein Name ist Egor, ich bin ein Full-Stack-Entwickler in Leader-ID. In diesem Artikel möchte ich ein einfaches Rezept für die Erstellung eines schönen und praktischen webbasierten Fragebogens vorstellen, der dem von Meduza ähnelt. Er weiß, wie man Statistiken nach Beantwortung einzelner Fragen anzeigt, die Gesamtpunktzahl berechnet, Kommentare abgibt, Daten zur Analyse hochlädt und Ergebnisse in sozialen Netzwerken fummelt. Um dies zu erreichen, habe ich Django, DRF, Python und die PostgreSQL-Datenbank ausgewählt.



Alle Details sind unter dem Schnitt.

Nach einer Stunde des Betrachtens des Mauerwerks (klebrige Lektion jedoch) erschien das erste Ergebnis in Form von vorgefertigten Modellen, die nach zehn Minuten in Dzhang beschrieben wurden.

Wenn Sie ein Anfänger sind, empfehle ich Ihnen, das Djnago-Tutorial durchzuarbeiten . Es beschreibt, wie Sie Schritt für Schritt eine Umfrage erstellen. Und nach dem DRF-Tutorial , um endlich in das Thema einzutauchen.

Also habe ich im Projekt Folgendes verwendet:

  • Django 3.0.3. Für das Backend;
  • Django-Rest-Framework. Rest-API erstellen;
  • Python
  • PostgreSQL als Datenbank;
  • Frontend - Nuxt.js, Axios, Element-UI.

Nun die Schritte


pip install Django - installiere die Bibliothek.

django-admin startproject core - erstelle ein djang-projekt.

cd core - gehe in das Verzeichnis mit dem Projekt.

python manage.py startapp pools - füge eine Polling-Anwendung hinzu.

Als Nächstes beschreiben wir die Modelle in models.py in Umfragen und erstellen einen Serializer für 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


Codetext hier
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()


Dann schreiben wir zwei DRF-Ansichten in views.py, die alle Fragen mit Optionen angeben und alle Antworten des Benutzers akzeptieren.


Codetext hier
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'})


Jetzt beschreiben wir die Links in urls.py:

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

Fügen Sie admin.py Modelle hinzu:


Codetext hier
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)


Der nächste Schritt ist das Hinzufügen unserer Polls-Anwendung zu settings.py (im Kernverzeichnis) in INSTALLED_APPS. Führen Sie den Startbefehl aus:

  • python manage.py makemigrations - Erstellen Sie eine Migration für die erstellten Modelle
  • python manage.py migrate - Führen Sie eine Migration in die Datenbank durch
  • python manage.py createuperuser - Erstelle einen Superuser (admin)
  • python manage.py runserver - Starten Sie den Server

Um die Gesamtpunktzahl für Fragen zu berechnen, fügen wir der Methode eine einfache Berechnungsfunktion hinzu, nach der Punkte berechnet werden. Ich werde den Funktionscode nicht veröffentlichen, da er zum Knacken unseres Fragebogens verwendet werden kann. Jetzt hat jede Antwort ihr eigenes „Gewicht“.

Wir gehen über den Browser über den in der Konsole angegebenen Link ( standardmäßig http://127.0.0.1:8000 / admin) zum Admin-Bereich und erstellen Fragen und Antworten, setzen Punkte.



Für mich war es wichtig, unseren Partnern Listen mit Personen, die an der Umfrage teilgenommen haben, und deren Antworten zu geben. Dafür reicht es jedoch nicht aus, die Antworten einfach mit den Fragen zu verknüpfen. Deshalb habe ich eine weitere Tabelle hinzugefügt - "Optionen". So wurde eine Verbindung zwischen den Antworten des Benutzers auf Fragen mit mehreren Antwortoptionen hergestellt. Auf diese Weise können wir Daten in der Form hochladen, in der Partner sie leicht interpretieren können.

Infolgedessen stellte sich die Datenbankstruktur folgendermaßen heraus:


Verbinden Sie nun die Front.

Darin nehmen wir die Liste der Fragen und Antworten weg, wir gehen jedes Element bis zum letzten durch. Je nach Art der Frage ändern wir die Komponente mit ihrer eigenen Logik und ihrem eigenen Stil. Wenn die Liste keine Fragen mehr enthält, senden wir das Ergebnis nach hinten und erhalten eine Antwort mit der Anzahl der Punkte. Nachdem wir die Anzahl der Punkte erhalten haben, öffnen wir die Ergebnisseite. Wenn es Punkte gibt, werden keine Fragen mehr angezeigt.

Zu diesem Zeitpunkt haben wir bereits einen Fragebogen parat, der alles Notwendige tun kann: Fragen stellen, Antworten erhalten und sammeln, Ergebnisse in Form von Punkten und Kommentaren liefern.

Brötchen hinzufügen


Erstens musste ich die Daten regelmäßig hochladen. Dafür habe ich gerade einen Verwaltungsbefehl hinzugefügt.

Zweitens wäre es schön, den Austausch von Umfrageergebnissen in sozialen Netzwerken zu implementieren. OK. Sägefunktion, mit der Sie ein Bild mit VKontakte- und Facebook-Punkten teilen können.

Wir generieren einhundert Varianten von Bildern, die Punkte für VK und Facebook getrennt widerspiegeln (unterschiedliche Auflösungen). Jetzt verbinden wir die Übertragung des Links mit dem Bild in der sozialen Komponente des Frontend-Teils. Mit VKontakte stellte sich heraus, dass alles einfach war: Wir übergeben den Bildparameter mit der direkten URL an die gewünschte. Aber ich musste an Facebook basteln. Es stellte sich heraus, dass sie keine Medien per API akzeptieren. Wenn ich ein Bild oder ein Bild von der URL des Bildes übertragen habe, wurde im Beitrag ein großes leeres Feld angezeigt. Wie sich später herausstellte, macht er ein Bild aus dem Metainf (og: image) der Site selbst, das er geteilt hat (wir übergeben den Parameter u im Link). Und sie musste unter anderem dynamisch verändert werden. Ich wollte keine unnötigen Weiterleitungen und keinen Mechaniker auf der Rückseite durchführen und entschied mich, SPA (Single-Page-App) auf der Vorderseite in SSR (Server-Side-Rendering) umzuwandeln.Je nach Anforderung ändert sich die URL des Bildes mit einer Punktzahl in Kopf-Meta, bevor JavaScript im Browser gestartet wird. Glücklicherweise ermöglicht das Nuxt.js-Framework, das als Grundlage dient, dies einfach durch Umschalten der Modi. Jetzt müssen nur noch Client-Tags skizziert und die Logik zum Ändern des Kopfes nach Vorhandensein einer Abfragebewertung hinzugefügt werden.



Darüber hinaus war es auf dem Server erforderlich, den Daemon-Dienst zu starten, um die generierten Seiten bereitzustellen, und die Statik auch nginx zu überlassen. Alles Profit!



Wir beleben den Fragebogen wieder


Um das Interesse der Teilnehmer am Ausfüllen der Umfrage aufrechtzuerhalten, habe ich jeder einzelnen Frage eine dynamische Statistikanzeige hinzugefügt. Nach Beantwortung der Frage sieht der Benutzer, wie andere geantwortet haben. Manchmal ist einer Person nicht klar, warum ihnen diese Fragen gestellt werden. Deshalb habe ich jede Frage mit lustigen Erklärungen ergänzt. Der wichtigste Trick zur Wiederbelebung meines Fragebogens wurde von den Designern unseres Unternehmens ausgeführt.



Zusammenfassung


Solche Medienumfragen sind recht einfach zu implementieren und vor allem mögen die Benutzer sie wirklich. Sie können sowohl im Schwanz als auch in der Mähne verwendet werden: für soziologische Forschung, zum Informieren / Testen von Wissen oder zum Erstellen interaktiver Elemente auf Websites und Diensten. Ich habe versucht, den Entstehungsprozess detailliert zu beschreiben, aber wenn Sie Fragen haben, können Sie diese gerne kommentieren. Beispiele für Umfragen zu dieser Engine finden Sie unter diesen beiden Links: Healthcare.leader-id.ru und covid.leader-id.ru .

All Articles