Melihat Kuesioner Web Meduza: Panduan Langkah-demi-Langkah untuk Pemula

Nama saya Egor, saya adalah pengembang tumpukan penuh di Leader-ID. Pada artikel ini, saya ingin berbagi resep sederhana untuk membuat kuesioner berbasis web yang indah dan nyaman seperti yang dibuat oleh Meduza. Dia tahu bagaimana menunjukkan statistik setelah menjawab pertanyaan individu, menghitung skor total, mengeluarkan komentar, mengunggah data untuk analisis dan meraba-raba hasil di jejaring sosial. Untuk mencapai ini, saya memilih Django, DRF, Python, dan database PostgreSQL.



Semua detail ada di bawah potongan.

Setelah satu jam melihat batu bata (pelajaran lengket, namun) , hasil pertama muncul dalam bentuk model siap pakai, yang dijelaskan di Dzhang setelah sepuluh menit.

Jika Anda seorang pemula, saya sarankan Anda membaca tutorial Djnago , ini menjelaskan cara membuat survei langkah demi langkah. Dan setelah tutorial DRF , untuk akhirnya terjun ke topik.

Jadi, dalam proyek ini, saya menggunakan:

  • Django 3.0.3. Untuk backend;
  • django-rest-framework. Untuk membuat rest-api;
  • Python
  • PostgreSQL sebagai basis data;
  • Front-end - Nuxt.js, Axios, Element-UI.

Sekarang langkah-langkahnya


pip install Django - instal perpustakaan.

django-admin startproject core - buat proyek djang.

cd core - pergi ke direktori dengan proyek.

python manage.py startapp pools - tambahkan aplikasi polling.

Selanjutnya, kami menjelaskan model dalam models.py dalam jajak pendapat dan membuat serializer untuk 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


Kode teks di sini
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()


Lalu kami menulis dua tampilan DRF di views.py, yang memberikan semua pertanyaan dengan opsi dan menerima semua jawaban dari pengguna.


Kode teks di sini
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'})


Sekarang kami jelaskan tautannya di urls.py:

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

Tambahkan model ke admin.py:


Kode teks di sini
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)


Langkah selanjutnya adalah menambahkan aplikasi jajak pendapat kami ke settings.py (di direktori inti) di INSTALLED_APPS. Dan jalankan perintah peluncuran:

  • makemigrations python manage.py - buat migrasi untuk model yang dibuat
  • python manage.py migrate - melakukan migrasi ke database
  • python manage.py createuperuser - buat superuser (admin)
  • python manage.py runserver - mulai server

Untuk menghitung skor total untuk pertanyaan, kami menambahkan ke metode fungsi penghitungan sederhana, sesuai dengan poin mana yang dihitung. Saya tidak akan memposting kode fungsi, karena dapat digunakan untuk memecahkan kuesioner kami. Sekarang setiap jawaban memiliki "bobot" sendiri.

Kami pergi ke panel admin melalui browser menggunakan tautan yang disediakan di konsol ( http://127.0.0.1:8000 / admin secara default), dan membuat pertanyaan dan jawaban untuk mereka, meletakkan poin.



Penting bagi saya untuk memberikan daftar mitra kepada orang-orang kami yang menyelesaikan survei dan jawaban mereka. Tetapi untuk ini, tidak cukup hanya dengan menghubungkan jawaban untuk pertanyaan. Oleh karena itu, saya menambahkan tabel lain - “Opsi”. Jadi koneksi terbentuk antara jawaban pengguna atas pertanyaan dengan beberapa pilihan jawaban. Ini memungkinkan kami untuk mengunggah data dalam bentuk di mana mitra dapat dengan mudah menafsirkannya.

Akibatnya, struktur database berubah menjadi seperti ini:


Sekarang hubungkan bagian depan.

Di dalamnya kita menghilangkan daftar pertanyaan dan jawaban, kita membahas setiap elemen sampai yang terakhir. Bergantung pada jenis pertanyaan, kami mengubah komponen dengan logika dan gayanya sendiri. Dengan demikian, ketika tidak ada pertanyaan yang tersisa dalam daftar, kami mengirim hasilnya ke belakang dan mendapatkan jawaban dengan jumlah poin. Setelah menerima jumlah poin, kami membuka halaman hasil, jika ada poin, kami tidak lagi menampilkan pertanyaan.

Pada tahap ini, kami telah menyiapkan kuesioner yang dapat melakukan semua yang dibutuhkan: mengajukan pertanyaan, menerima dan mengumpulkan jawaban, memberikan hasilnya dalam bentuk poin dan komentar.

Tambahkan roti


Pertama, saya perlu mengunggah data secara berkala. Untuk ini, saya baru saja menambahkan perintah manajemen.

Kedua, alangkah baiknya untuk menerapkan pembagian hasil survei di jejaring sosial. BAIK. Fungsi gergaji yang akan memungkinkan Anda untuk berbagi gambar dengan poin VKontakte dan Facebook.

Kami menghasilkan seratus varian gambar yang mencerminkan poin untuk VK dan Facebook secara terpisah (resolusi berbeda). Sekarang kita menghubungkan transfer tautan ke gambar di komponen sosial bagian front-end. Dengan VKontakte, semuanya ternyata sederhana: kami meneruskan parameter gambar dengan URL langsung ke yang diinginkan. Tapi saya harus mengotak-atik Facebook. Ternyata mereka tidak menerima media dengan API, dan jika saya mentransfer gambar atau gambar dari URL gambar, maka bidang kosong besar ditampilkan di pos. Ternyata kemudian, ia mengambil gambar dari metainf (og: image) dari situs itu sendiri, yang ia bagikan (kami melewatkan parameter u di tautan). Dan dia, antara lain, harus diubah secara dinamis. Saya tidak ingin melakukan pengalihan yang tidak perlu dan mekanik di belakang, dan saya memutuskan untuk mengubah SPA (aplikasi satu halaman) menjadi SSR (render sisi-server) di bagian depan,sehingga tergantung pada permintaan, url gambar dengan skor di head-meta berubah sebelum JavaScript diluncurkan di browser. Untungnya, kerangka kerja Nuxt.js yang diambil sebagai dasar memungkinkan ini dilakukan hanya dengan beralih mode. Sekarang tinggal membuat sketsa tag khusus klien dan menambahkan logika untuk mengubah kepala dari keberadaan skor kueri.



Selain itu, di server, perlu untuk memulai layanan daemon untuk memberikan halaman yang dihasilkan, dan membiarkan statika ke nginx juga. Semua untung!



Kami menghidupkan kembali kuesioner


Untuk menjaga tingkat ketertarikan peserta dalam proses mengisi survei, saya menambahkan tampilan statistik yang dinamis untuk setiap pertanyaan. Setelah menjawab pertanyaan, pengguna melihat bagaimana orang lain menjawab. Terkadang tidak jelas bagi seseorang mengapa mereka ditanyai pertanyaan-pertanyaan ini. Karena itu, saya melengkapi setiap pertanyaan dengan penjelasan lucu. Nah, trik paling penting untuk merevitalisasi kuesioner saya dilakukan oleh para desainer perusahaan kami.



Ringkasan


Survei media semacam itu cukup sederhana untuk diterapkan dan, yang paling penting, pengguna sangat menyukainya. Mereka dapat digunakan baik di ekor dan surai: untuk penelitian sosiologis, menginformasikan / menguji pengetahuan atau membuat elemen interaktif di situs dan layanan. Saya mencoba menjelaskan secara rinci proses penciptaan mereka, tetapi jika Anda memiliki pertanyaan, selamat datang untuk berkomentar. Contoh survei pada mesin ini dapat dilihat pada dua link ini: healthcare.leader-id.ru dan covid.leader-id.ru .

All Articles