Streamlining Student Interaction with Tutor Views

In this lesson, we will focus on how to manage student interactions in our personal tutor service using function-based views. In the previous lesson, we built the TutorService class, which connects session management with the DeepSeek model to process student queries. Now, we will see how to orchestrate the flow of data between the frontend and backend using views. These views act as request handlers, receiving HTTP requests from the frontend, interacting with the service layer, and returning JSON responses. This approach ensures that student interactions are processed efficiently and according to the conventions of our web framework.

Implementing Tutor Views

Instead of using a controller class, we define function-based views that handle specific actions, such as creating a tutoring session or processing a student query. Each view receives an HTTP request, interacts with the TutorService, and returns a JSON response.

Let's look at how to set up these views in our application:

from django.shortcuts import render
import uuid
from django.views.decorators.csrf import csrf_exempt
from django.http import JsonResponse
from .services import TutorService
import json

tutor_service = TutorService()

Here, we import the necessary modules and initialize the TutorService. The views will use this service to manage sessions and process queries.

Ensuring Student Session

Before handling any tutoring session, we need to ensure that a student session exists. In our web framework, session data is managed using the request object. We can access and set session data using request.session, which is a dictionary-like object tied to each user's session.

def ensure_student_session(request):
    if 'student_id' not in request.session:
        request.session['student_id'] = str(uuid.uuid4())
    return request.session['student_id']

This function checks if a student_id is present in the session. If not, it generates a new unique ID and stores it in the session. This ensures that each student has a unique identifier for their interactions.

Creating a New Tutoring Session

To create a new tutoring session, we define a function-based view that handles HTTP POST requests. This view validates the session and returns a JSON response with the new session ID.

@csrf_exempt
def create_session_view(request):
    student_id = ensure_student_session(request)
    session_id = tutor_service.create_session(student_id)
    return JsonResponse({"session_id": session_id, "message": "Tutoring session created successfully"})

In this view:

  1. We ensure the student session exists and retrieve the student_id.
  2. We call the create_session method of the TutorService to create a new tutoring session.
  3. We return a JSON response containing the new session ID and a success message.
Handling Student Queries

To process student queries, we define another function-based view. This view receives the session ID and query from the request body, processes the query using the service layer, and returns the tutor's response or an error message as JSON.

@csrf_exempt
def send_query_view(request):
    student_id = ensure_student_session(request)
    data = json.loads(request.body.decode("utf-8"))
    session_id = data.get("session_id")
    student_query = data.get("query")
    try:
        reply = tutor_service.process_query(student_id, session_id, student_query)
        return JsonResponse({"message": reply})
    except ValueError as e:
        return JsonResponse({"error": str(e)}, status=404)
    except Exception as e:
        return JsonResponse({"error": str(e)}, status=500)

In this view:

  1. We ensure the student session exists and retrieve the student_id.
  2. We parse the request body to get the session_id and student_query.
  3. We process the query using the process_query method of the TutorService.
  4. If successful, we return the tutor's response as JSON.
  5. If an error occurs (such as an invalid session ID), we return an error message with the appropriate HTTP status code.
Integrating Tutor Views in the Main Application

To use these views, we define URL patterns that map HTTP endpoints to the corresponding view functions. This allows the frontend to interact with the backend by sending HTTP requests to these endpoints.

from django.urls import path
from .views import index, create_session_view, send_query_view

urlpatterns = [
    path('', index, name='index'),
    path('api/create_session/', create_session_view, name='create_session'),
    path('api/send_query/', send_query_view, name='send_query'),
]

Now, let's see how to interact with these endpoints using HTTP requests. The following example demonstrates how to create a tutoring session and send a query to the tutor:

import requests
import uuid

# Start a session to persist cookies (including sessionid)
session = requests.Session()

# Base URL for the Django app
BASE_URL = "http://localhost:3000"

# Step 1: Hit the index page to establish a session (optional, but can trigger session middleware)
index_response = session.get(f"{BASE_URL}/")
print(f"Visited index: {index_response.status_code}")

# Step 2: Create a new tutoring session
create_session_response = session.post(f"{BASE_URL}/api/create_session/")
if create_session_response.status_code != 200:
    print(f"Error {create_session_response.status_code}: {create_session_response.text}")
else:
    session_data = create_session_response.json()
    session_id = session_data['session_id']
    print(f"Tutoring session created with session_id: {session_id}")

    # Step 3: Send a query to the tutor
    student_query = "What are the key differences between mitosis and meiosis?"
    query_payload = {
        "session_id": session_id,
        "query": student_query
    }

    send_query_response = session.post(f"{BASE_URL}/api/send_query/", json=query_payload)

    if send_query_response.status_code != 200:
        print(f"Error {send_query_response.status_code}: {send_query_response.text}")
    else:
        data = send_query_response.json()
        if isinstance(data, dict) and data.get('status') == 'error':
            error_data = data['error']
            print(f"Error {error_data['code']}: {error_data['message']}")
        else:
            print(f"Tutor Response: {data['data']['message']}")

In this example:

  1. We establish a session with the backend.
  2. We create a new tutoring session by sending a POST request to the /api/create_session/ endpoint.
  3. If successful, we send a student query to the /api/send_query/ endpoint.
  4. We handle and print the tutor's response or any error messages.
Summary and Next Steps

In this lesson, we learned how to manage student interactions using function-based views. We saw how to ensure student sessions, create new tutoring sessions, and process student queries by interacting with the service layer. These views act as the bridge between the frontend and backend, handling HTTP requests and returning JSON responses. As you move on to the practice exercises, try experimenting with these views and endpoints to reinforce your understanding of how data flows through the application. Great job, and keep building your skills!

Sign up
Join the 1M+ learners on CodeSignal
Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal