django-vue3.2-online-exam

repository·master·Indexed 41 days ago

https://github.com/xingxingzaixian/django-vue3.2-online-exam

A full-stack online examination system featuring a Django backend with Django Rest Framework and a Vue 3.2 frontend with TypeScript and Element-Plus. It supports role-based access control for Students, Teachers, and Admins, and handles multiple question types including single choice, multiple choice, and true/false. Key technical implementations include JWT authentication, custom UserInfo models, multi-database routing, and Loguru for structured logging.

Tokens
11.1K
Snippets
45
Records
56
Agent score
52%

What's inside django-vue3.2-online-exam

  1. Overview of the Online Exam System

    master

    The django-vue3.2-online-exam is an online examination system built with a decoupled architecture:

    • Backend: Django + Django Rest Framework + CoreApi + JWT authentication. It provides different data based on user permissions.
    • Frontend: Vue 3.2 + Element-Plus + TypeScript. It uses a component-based architecture for easy maintenance and secondary development.

    Supported Question Types

    • Single choice (单选题)
    • Multiple choice (多选题)
    • True/False (判断题)

    User Roles and Permissions

    • Student (student): Can participate in exams and view their own exam results.
    • Teacher (teacher): Inherits all student permissions, plus the ability to create and edit questions and exams.
    • Administrator (admin): Inherits all teacher permissions, plus the ability to manage users.
  2. Install and Setup the Online Exam System

    master

    Follow these steps to set up the full stack environment (Django backend and Vue 3 frontend).

    1. Clone the Repository

    git clone git@github.com:xingxingzaixian/django-vue3.2-online-exam.git

    2. Database Configuration

    1. Install MySQL.
    2. Create a database named exam.
    3. Configure your database credentials in the Django backend/settings.py file.

    3. Backend Setup (Django)

    This project uses pipenv for dependency management. Ensure you have pipenv installed via pip.

    # Enter the backend directory
    cd backend
    
    # Install project dependencies
    pipenv install
    
    # Generate database migration files
    pipenv run makemigrations
    
    # Execute migrations to create all tables
    pipenv run migrate
    
    # Start the backend server
    pipenv run dev

    Once started, you can view the API documentation at http://localhost:9527/docs.

    4. Frontend Setup (Vue 3)

    # Enter the frontend directory
    cd frontend
    
    # Install dependencies
    yarn install
    
    # Start the frontend development server
    yarn run dev

    5. Access the Application

    After both servers are running, access the application at http://localhost:8000.

    # Backend setup sequence
    cd backend
    pipenv install
    pipenv run makemigrations
    pipenv run migrate
    pipenv run dev
    
    # Frontend setup sequence
    cd frontend
    yarn install
    yarn run dev
  3. Initialize and structure the Django project

    master

    Start the project using django-admin startproject backend.

    To maintain a clean root directory, the project uses a custom structure:

    1. Create an apps/ directory to house all Django applications.
    2. Create a settings/ directory to house configuration files.
    3. Move settings.py into the settings/ directory.
    4. Create dev.py (development) and pro.py (production) within settings/ to manage environment-specific database and DEBUG configurations.
    5. Add the apps directory to the Python path in settings.py so apps can be imported easily.
    django-admin startproject backend
  4. Implement JWT authentication

    master

    The project uses JSON Web Tokens (JWT) for REST API authentication.

    1. Authentication Logic

    Create utils/authentication.py with a JwtAuthentication class that inherits from BaseAuthentication. It extracts the HTTP_ACCESS_TOKEN from request headers, validates it using JwtUtil, and retrieves the user.

    2. JWT Utilities

    Create utils/jwt_util.py with a JwtUtil class containing static methods gen_jwt_token(user) to create tokens and check_jwt_token(value) to decode them.

    3. DRF Configuration

    In settings.py, configure REST_FRAMEWORK to use your custom authentication class:

    REST_FRAMEWORK = {
        'DEFAULT_AUTHENTICATION_CLASSES': [
            'utils.authentications.JwtAuthentication'
        ],
        'DATETIME_FORMAT': '%Y-%m-%d %H:%M:%S',
        'DATETIME_INPUT_FORMATS': '%Y-%m-%d %H:%M:%S'
    }
    REST_FRAMEWORK = {
        'DEFAULT_AUTHENTICATION_CLASSES': [
            'utils.authentications.JwtAuthentication'
        ],
        'DATETIME_FORMAT': '%Y-%m-%d %H:%M:%S',
        'DATETIME_INPUT_FORMATS': '%Y-%m-%d %H:%M:%S'
    }
  5. Configure and use Loguru for logging

    master

    The project uses loguru for structured logging.

    1. Setup

    Create utils/logger.py to configure log rotation, encoding, and file separation by level (INFO, WARNING, ERROR). Logs are stored in a logs/ directory at the project root.

    2. Usage

    Import the configured logger instance in any file where logging is needed:

    from utils.logger import logger
    
    logger.info('Message: %s', variable)
    logger.error('Error: %s', error_msg)
    from utils.logger import logger
    
    class RegisterView(APIView):
        def post(self, request):
            # ... logic
            logger.info('用户: %s 注册成功', username)
  6. Enable full type support for .vue imports in TypeScript

    master

    By default, TypeScript treats .vue imports as generic Vue component types, which may hide specific prop type information. To enable actual prop type validation (useful for manual h(...) calls or strict prop checking), use the Volar plugin by following these steps:

    1. Open the VSCode Command Palette.
    2. Run the command: Volar: Switch TS Plugin on/off.
  7. Use custom UserBackend for JWT login

    master

    To integrate JWT generation into the standard Django authentication flow, create a custom backend:

    1. Create utils/user_backend.py with a UserBackend class inheriting from backends.ModelBackend. Override the authenticate method to verify credentials and return the user with a generated token attached.
    2. In settings.py, set AUTHENTICATION_BACKENDS = ['utils.user_backend.UserBackend'].
    class UserBackend(backends.ModelBackend):
        def authenticate(self, request, username=None, password=None, **kwargs):
            user = UserInfo.objects.get(Q(username=username) | Q(telephone=username))
            if user.check_password(password):
                jwt = JwtUtil()
                token = jwt.gen_jwt_token(user)
                user.token = token
                return user
            raise UserInfo.DoesNotExist("UserInfo matching query does not exist.")
  8. Set up a custom User model

    master

    The project uses a custom user model named UserInfo inheriting from AbstractUser.

    1. Create a users app in the apps/ directory.
    2. Define UserInfo in users/models.py with additional fields like uid (UUID primary key), nickname, and telephone.
    3. In settings.py, add 'users' to INSTALLED_APPS and set AUTH_USER_MODEL = 'users.UserInfo'.
    class UserInfo(AbstractUser):
        uid = models.CharField(max_length=36, default=uuid4, primary_key=True)
        nickname = models.CharField(max_length=32, verbose_name='昵称')
        telephone = models.CharField(max_length=11, blank=True, null=True, unique=True, verbose_name='手机号码')
        create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
    
        class Meta:
            db_table = 'tbl_user'
  9. Configure multi-database routing

    master

    To support multiple databases, implement a custom router class. The router uses a mapping defined in settings.DATABASE_APPS_MAPPING to decide which database to use based on the app_label of the model.

    1. Create backend/router.py with a CustomRouter class implementing db_for_read, db_for_write, allow_relation, allow_syncdb, and allow_migrate.
    2. Register the router in settings.py using the DATABASE_ROUTERS key.
    # In settings.py
    DATABASE_ROUTERS = ['backend.router.CustomRouter']
    
    # Example router logic in backend/router.py
    class CustomRouter:
        def db_for_read(self, model, **hints):
            if model._meta.app_label in settings.DATABASE_APPS_MAPPING:
                return settings.DATABASE_APPS_MAPPING[model._meta.app_label]
        # ... other methods