نشر استبيان الويب Meduza: دليل خطوة بخطوة للمبتدئين

اسمي إيجور ، وأنا مطور مكدس في Leader-ID. في هذه المقالة ، أرغب في مشاركة وصفة بسيطة لإنشاء استبيان جميل ومريح قائم على الويب مماثل لتلك التي قدمتها Meduza. إنه يعرف كيفية عرض الإحصائيات بعد الإجابة على الأسئلة الفردية ، وحساب النتيجة الإجمالية ، وإصدار التعليقات ، وتحميل البيانات للتحليل والنتائج المتعثرة على الشبكات الاجتماعية. لتحقيق ذلك ، اخترت Django و DRF و Python وقاعدة بيانات PostgreSQL.



جميع التفاصيل تحت القطع.

بعد ساعة من النظر إلى أعمال الطوب (الدرس اللزج) ، ظهرت النتيجة الأولى في شكل نماذج جاهزة ، والتي تم وصفها في دزانغ بعد عشر دقائق.

إذا كنت مبتدئًا ، أنصحك بالذهاب إلى البرنامج التعليمي Djnago ، فهو يصف كيفية إنشاء استبيان خطوة بخطوة. وبعد البرنامج التعليمي لـ DRF ، يمكنك الخوض في الموضوع أخيرًا.

لذلك ، في المشروع ، استخدمت:

  • جانغو 3.0.3. للواجهة الخلفية ؛
  • جانغو بقية الإطار. لإنشاء بقية api.
  • بيثون
  • PostgreSQL كقاعدة بيانات ؛
  • الواجهة الأمامية - Nuxt.js و Axios و Element-UI.

الآن الخطوات


نقطة تثبيت Django - تثبيت المكتبة.

django-admin startproject core - إنشاء مشروع djang.

قرص مضغوط الأساسية - انتقل إلى الدليل مع المشروع.

python Manage.py تجمعات startapp - أضف تطبيق اقتراع.

بعد ذلك ، نصف النماذج في models.py في استطلاعات الرأي وننشئ مُسلسلاً لـ 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


نص التعليمات البرمجية هنا
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()


ثم نكتب ملفين لعرض DRF في views.py ، والتي تقدم جميع الأسئلة مع الخيارات وتقبل جميع الإجابات من المستخدم.


نص التعليمات البرمجية هنا
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'})


الآن وصفنا الروابط في urls.py:

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

أضف نماذج إلى admin.py:


نص التعليمات البرمجية هنا
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)


الخطوة التالية هي إضافة تطبيق الاستطلاعات إلى settings.py (في الدليل الأساسي) في INSTALLED_APPS. ونفذ أمر الإطلاق:

  • python Manage.py makemigrations - إنشاء ترحيل للنماذج التي تم إنشاؤها
  • python manager.py ترحيل - إجراء الترحيل إلى قاعدة البيانات
  • python manager.py createuperuser - إنشاء مستخدم خارق (مشرف)
  • python Manage.py runserver - ابدأ الخادم

لحساب النتيجة الإجمالية للأسئلة ، نضيف إلى الطريقة وظيفة حسابية بسيطة ، والتي يتم بموجبها حساب النقاط. لن أنشر رمز الوظيفة ، لأنه يمكن استخدامه لكسر استبياننا. الآن كل إجابة لها "وزنها".

ننتقل إلى لوحة المشرف من خلال المتصفح باستخدام الرابط الموجود في وحدة التحكم ( http://127.0.0.1:8000 / admin افتراضيًا) ، وننشئ أسئلة وأجوبة لها ، ونضع النقاط.



كان من المهم بالنسبة لي أن أقدم لشركائنا قوائم بالأشخاص الذين أكملوا الاستبيان وإجاباتهم. ولكن لهذا ، لا يكفي ربط الإجابات بالأسئلة. لذلك ، أضفت جدولاً آخر - "الخيارات". لذلك تم تشكيل اتصال بين إجابات المستخدم على الأسئلة مع العديد من خيارات الإجابة. يتيح لنا ذلك تحميل البيانات بالشكل الذي يمكن للشركاء تفسيرها بسهولة.

ونتيجة لذلك ، تحول هيكل قاعدة البيانات على النحو التالي:


الآن وصل الجبهة.

نأخذ فيها قائمة الأسئلة والأجوبة ، وننتقل من خلال كل عنصر إلى آخر. بناءً على نوع السؤال ، نغير المكون بمنطقه وأسلوبه. وفقًا لذلك ، عندما لا تبقى هناك أسئلة في القائمة ، نرسل النتيجة إلى الخلف ونحصل على إجابة بعدد النقاط. بعد تلقي عدد النقاط ، نفتح صفحة النتائج ، إذا كانت هناك نقاط ، لم نعد نعرض الأسئلة.

في هذه المرحلة ، لدينا بالفعل استبيان جاهز يمكنه القيام بكل ما يحتاجه: طرح الأسئلة ، وتلقي الإجابات وجمعها ، وإعطاء النتيجة في شكل نقاط وتعليقات.

أضف كعك


أولاً ، كنت بحاجة إلى تحميل البيانات بشكل دوري. لهذا ، أضفت للتو أمر الإدارة.

ثانياً ، سيكون من الجيد تنفيذ مشاركة نتائج المسح في الشبكات الاجتماعية. حسنا. وظيفة النشر التي تسمح لك بمشاركة صورة مع نقاط فكونتاكتي وفيسبوك.

نحن نولد مائة متغير من الصور التي تعكس نقاط لـ VK و Facebook بشكل منفصل (دقة مختلفة). الآن نربط نقل الرابط إلى الصورة في المكون الاجتماعي للجزء الأمامي. مع VKontakte ، تبين أن كل شيء بسيط: نقوم بتمرير معلمة الصورة بعنوان URL المباشر إلى العنوان المطلوب. ولكن كان علي أن العبث مع Facebook. اتضح أنهم لا يقبلون الوسائط بواسطة واجهة برمجة التطبيقات ، وإذا قمت بنقل صورة أو صورة من عنوان URL الخاص بالصورة ، فسيتم عرض حقل فارغ كبير في المنشور. كما اتضح لاحقًا ، يلتقط صورة من metainf (og: image) للموقع نفسه ، والذي شاركه (نمرر المعلمة u في الرابط). وكان عليها ، من بين أمور أخرى ، أن تتغير ديناميكيًا. لم أكن أرغب في إجراء عمليات إعادة توجيه غير ضرورية وميكانيكي في الخلف ، وقررت تحويل SPA (تطبيق من صفحة واحدة) إلى SSR (عرض من جانب الخادم) في المقدمة ،لذلك ، بناءً على الطلب ، يتغير عنوان URL للصورة التي تحتوي على درجة في رأس التعريف قبل بدء تشغيل JavaScript في المستعرض. لحسن الحظ ، يسمح إطار Nuxt.js المأخوذ كأساس بذلك عن طريق تبديل الأوضاع. الآن يبقى رسم علامات العميل فقط وإضافة المنطق لتغيير الرأس من وجود نتيجة الاستعلام.



بالإضافة إلى ذلك ، على الخادم ، كان من الضروري بدء خدمة الخفي لإعطاء الصفحات التي تم إنشاؤها ، وترك الإحصائيات إلى nginx أيضًا. كل الربح!



نجدد الاستبيان


للحفاظ على مستوى اهتمام المشاركين في عملية ملء الاستبيان ، أضفت عرضًا ديناميكيًا للإحصاءات لكل سؤال فردي. بعد الإجابة على السؤال ، يرى المستخدم كيف أجاب الآخرون. في بعض الأحيان لا يكون واضحًا للشخص سبب طرح هذه الأسئلة عليه. لذلك ، استكملت كل سؤال بتفسيرات مضحكة. حسنًا ، تم تنفيذ أهم خدعة لتنشيط استبياني من قبل مصممي شركتنا.



ملخص


هذه الاستطلاعات الإعلامية سهلة التنفيذ ، والأهم من ذلك ، أن المستخدمين يحبونها حقًا. يمكن استخدامها في الذيل واللباس: للبحث الاجتماعي ، وإعلام / اختبار المعرفة أو إنشاء عناصر تفاعلية على المواقع والخدمات. لقد حاولت أن أصف بالتفصيل عملية إنشائها ، ولكن إذا كان لديك أي أسئلة ، فمرحبًا بالتعليق. يمكن الاطلاع على أمثلة للمسوحات على هذا المحرك على الرابطين التاليين: healthcare.leader-id.ru و covid.leader-id.ru .

All Articles