* Vietnamese translation incomplete

Tour operator forms

Tour operator forms (English fallback)

Aug. 17, 2025

Posted by admin

Nhom

Notes

 

Tour Operators Forms System - Detailed Analysis

File Overview

Purpose: Django form definitions for tour operators management system Locationforms.py Function: User interface forms for data input, validation, and processing Framework: Django Forms with Bootstrap styling integration

Import Dependencies Analysis

from django import forms

from django.core.exceptions import ValidationError

from django.utils import timezone

from django.db import models

from decimal import Decimal

from .models import (

    TourOperator, Tour, TourBooking, TourSchedule, TourGuide, TourCategory,

    TourItinerary, TourInclusion, TourParticipant

)

Key Components:

  • forms: Django forms framework
  • ValidationError: Custom validation error handling
  • timezone: Date/time utilities for scheduling
  • Decimal: Precise monetary calculations
  • Model imports: All tour operator related models

 

 

Forms Detailed Breakdown

 

 

1. TourOperatorForm - Operator Registration/Management

class TourOperatorForm(forms.ModelForm):

    class Meta:

        model = TourOperator

        fields = [

            'name', 'name_vi', 'description', 'description_vi', 'operator_type',

            'email', 'phone', 'website', 'address', 'city', 'country',

            'license_number', 'certification', 'established_year',

            'api_endpoint', 'api_key', 'commission_rate'

        ]

Purpose: Tour operator profile creation and management Field Categories:

Basic Information:

  • name / name_vi: English and Vietnamese business names
  • description / description_vi: Multilingual business descriptions
  • operator_type: Business classification (local, international, specialty)

Contact & Location:

  • email, phone, website: Communication channels
  • address, city, country: Geographic information

Legal & Business:

  • license_number: Government licensing
  • certification: Industry certifications (IATA, etc.)
  • established_year: Business history

API Integration:

  • api_endpoint, api_key: External system connections
  • commission_rate: Revenue sharing percentage

Widget Customizations:

widgets = {

    'description': forms.Textarea(attrs={'rows': 4}),

    'description_vi': forms.Textarea(attrs={'rows': 4}),

    'address': forms.Textarea(attrs={'rows': 3}),

    'operator_type': forms.Select(attrs={'class': 'form-select'}),

    'certification': forms.Select(attrs={'class': 'form-select'}),

    'commission_rate': forms.NumberInput(attrs={'step': '0.01', 'min': '0', 'max': '100'}),

}

Business Use: Operator onboarding, profile updates, partnership management

 

 

2. TourForm - Comprehensive Tour Creation

class TourForm(forms.ModelForm):

    class Meta:

        model = Tour

        fields = [

            'title', 'title_vi', 'slug', 'short_description', 'short_description_vi',

            'description', 'description_vi', 'tour_operator', 'categories',

            'tour_type', 'difficulty', 'duration_days', 'duration_hours',

            'start_location', 'end_location', 'destinations',

            'min_participants', 'max_participants', 'min_age', 'max_age',

            'base_price', 'price_currency', 'child_price', 'senior_price',

            'includes_accommodation', 'includes_meals', 'includes_transport',

            'includes_guide', 'includes_tickets', 'fitness_level_required',

            'special_requirements', 'what_to_bring', 'main_image', 'video_url'

        ]

Purpose: Complete tour creation and editing interface Field Groups:

Content Management:

  • title / title_vi: Multilingual tour names
  • slug: URL-friendly identifier
  • short_description / short_description_vi: Brief summaries
  • description / description_vi: Detailed descriptions

Tour Classification:

  • tour_operator: Associated operator
  • categories: Multiple category associations
  • tour_type: Type classification (group, private, custom)
  • difficulty: Difficulty rating

Logistics:

  • duration_days / duration_hours: Time requirements
  • start_location / end_location: Geographic points
  • destinations: Multiple destination support

Capacity & Demographics:

  • min_participants / max_participants: Group size limits
  • min_age / max_age: Age restrictions

Pricing Structure:

  • base_price, price_currency: Standard pricing
  • child_price, senior_price: Demographic pricing

Inclusions:

  • Boolean flags for accommodation, meals, transport, guide, tickets
  • fitness_level_required: Physical requirements

Advanced Features:

User Permission Control:

def __init__(self, *args, **kwargs):

    self.user = kwargs.pop('user', None)

    super().__init__(*args, **kwargs)

    

    # Limit tour operator choices to user's operators

    if self.user and not self.user.is_staff:

        user_operators = TourOperator.objects.filter(

            models.Q(user=self.user) | models.Q(managers=self.user)

        )

        self.fields['tour_operator'].queryset = user_operators

Custom Validation:

def clean_slug(self):

    slug = self.cleaned_data['slug']

    qs = Tour.objects.filter(slug=slug)

    if self.instance:

        qs = qs.exclude(pk=self.instance.pk)

    if qs.exists():

        raise ValidationError('This slug is already taken.')

    return slug

def clean(self):

    cleaned_data = super().clean()

    min_age = cleaned_data.get('min_age')

    max_age = cleaned_data.get('max_age')

    

    if min_age and max_age and min_age >= max_age:

        raise ValidationError('Maximum age must be greater than minimum age.')

 

 

3. TourBookingForm - Advanced Booking System

class TourBookingForm(forms.ModelForm):

    # Participant details

    adult_count = forms.IntegerField(min_value=1, initial=1)

    child_count = forms.IntegerField(min_value=0, initial=0)

    senior_count = forms.IntegerField(min_value=0, initial=0)

    

    # Lead traveler details

    lead_traveler_name = forms.CharField(max_length=200)

    lead_traveler_email = forms.EmailField()

    lead_traveler_phone = forms.CharField(max_length=20)

Purpose: Customer booking creation with complex validation Key Features:

Dynamic Schedule Filtering:

def __init__(self, *args, **kwargs):

    self.tour = kwargs.pop('tour', None)

    self.user = kwargs.pop('user', None)

    super().__init__(*args, **kwargs)

    

    if self.tour:

        # Filter schedules for this tour

        today = timezone.now().date()

        self.fields['schedule'].queryset = TourSchedule.objects.filter(

            tour=self.tour,

            is_active=True,

            start_date__gte=today

        ).order_by('start_date', 'start_time')

User Auto-Population:

# Pre-fill user details if available

if self.user:

    self.fields['lead_traveler_name'].initial = self.user.get_full_name()

    self.fields['lead_traveler_email'].initial = self.user.email

Complex Business Validation:

def clean(self):

    cleaned_data = super().clean()

    adult_count = cleaned_data.get('adult_count', 0)

    child_count = cleaned_data.get('child_count', 0)

    senior_count = cleaned_data.get('senior_count', 0)

    schedule = cleaned_data.get('schedule')

    

    total_participants = adult_count + child_count + senior_count

    

    if total_participants == 0:

        raise ValidationError('At least one participant is required.')

    

    if schedule and self.tour:

        if total_participants < self.tour.min_participants:

            raise ValidationError(f'Minimum {self.tour.min_participants} participants required.')

        

        if total_participants > self.tour.max_participants:

            raise ValidationError(f'Maximum {self.tour.max_participants} participants allowed.')

        

        if total_participants > schedule.remaining_spots:

            raise ValidationError(f'Only {schedule.remaining_spots} spots available for this schedule.')

Advanced Save Method with Pricing Logic:

def save(self, commit=True):

    booking = super().save(commit=False)

    

    # Calculate pricing

    adult_count = self.cleaned_data['adult_count']

    child_count = self.cleaned_data['child_count']

    senior_count = self.cleaned_data['senior_count']

    

    schedule = self.cleaned_data['schedule']

    base_price = schedule.price_override or self.tour.base_price

    

    # Calculate total price

    adult_price = base_price * adult_count

    child_price = (self.tour.child_price or base_price * Decimal('0.7')) * child_count

    senior_price = (self.tour.senior_price or base_price * Decimal('0.9')) * senior_count

    

    booking.base_price = base_price

    booking.total_price = adult_price + child_price + senior_price

    booking.total_participants = self.cleaned_data['total_participants']

    

    if commit:

        booking.save()

        

        # Update schedule booked spots

        schedule.booked_spots += booking.total_participants

        schedule.save()

    

    return booking

 

 

4. TourScheduleForm - Schedule Management

class TourScheduleForm(forms.ModelForm):

    class Meta:

        model = TourSchedule

        fields = [

            'schedule_type', 'start_date', 'end_date', 'start_time',

            'days_of_week', 'available_spots', 'price_override', 'notes'

        ]

Purpose: Tour schedule creation and management Features:

  • Date/time picking with HTML5 widgets
  • Schedule type validation (fixed vs recurring)
  • Price override capabilities
  • Capacity management

Business Logic Validation:

def clean(self):

    cleaned_data = super().clean()

    start_date = cleaned_data.get('start_date')

    end_date = cleaned_data.get('end_date')

    schedule_type = cleaned_data.get('schedule_type')

    

    if schedule_type == 'fixed' and not start_date:

        raise ValidationError('Start date is required for fixed schedules.')

    

    if start_date and end_date and start_date > end_date:

        raise ValidationError('End date must be after start date.')

 

 

5. TourSearchForm - Advanced Search Interface

class TourSearchForm(forms.Form):

    SORT_CHOICES = [

        ('featured', 'Featured'),

        ('price_low', 'Price: Low to High'),

        ('price_high', 'Price: High to Low'),

        ('rating', 'Highest Rated'),

        ('duration', 'Duration'),

        ('alphabetical', 'Alphabetical'),

    ]

Purpose: Comprehensive tour search and filtering Search Capabilities:

Text Search:

search = forms.CharField(

    required=False,

    widget=forms.TextInput(attrs={

        'class': 'form-control',

        'placeholder': 'Search tours...'

    })

)

Category Filtering:

category = forms.ModelChoiceField(

    queryset=TourCategory.objects.filter(is_active=True),

    required=False,

    empty_label='All Categories',

    widget=forms.Select(attrs={'class': 'form-select'})

)

Price Range Filtering:

min_price = forms.DecimalField(

    required=False,

    widget=forms.NumberInput(attrs={

        'class': 'form-control',

        'step': '0.01',

        'min': '0'

    })

)

max_price = forms.DecimalField(

    required=False,

    widget=forms.NumberInput(attrs={

        'class': 'form-control',

        'step': '0.01',

        'min': '0'

    })

)

 

 

6. TourParticipantForm - International Travel Support

class TourParticipantForm(forms.ModelForm):

    """Form for collecting individual participant details including passport upload"""

    

    class Meta:

        model = TourParticipant

        fields = [

            'participant_type', 'first_name', 'last_name', 'date_of_birth',

            'nationality', 'passport_number', 'passport_expiry', 'passport_image',

            'dietary_requirements', 'medical_conditions', 

            'emergency_contact_name', 'emergency_contact_phone'

        ]

Purpose: International tour participant data collection Key Features:

Document Upload Validation:

def clean_passport_image(self):

    passport_image = self.cleaned_data.get('passport_image')

    

    if passport_image:

        # Validate file size (max 5MB)

        if passport_image.size > 5 * 1024 * 1024:

            raise ValidationError('Passport image must be smaller than 5MB.')

        

        # Validate file type

        valid_extensions = ['.jpg', '.jpeg', '.png', '.pdf']

        file_extension = passport_image.name.lower().split('.')[-1]

        if f'.{file_extension}' not in valid_extensions:

            raise ValidationError('Please upload a valid image file (JPG, PNG) or PDF.')

    

    return passport_image

Required Field Management:

def __init__(self, *args, **kwargs):

    super().__init__(*args, **kwargs)

    

    # Mark required fields

    required_fields = ['first_name', 'last_name', 'nationality']

    for field_name in required_fields:

        if field_name in self.fields:

            self.fields[field_name].required = True

            self.fields[field_name].widget.attrs['required'] = True

 

 

7. TourGuideForm - Professional Guide Management

class TourGuideForm(forms.ModelForm):

    """Form for tour guides to update their profile and upload documents"""

    

    class Meta:

        model = TourGuide

        fields = [

            'bio', 'bio_vi', 'specializations', 'languages',

            'years_experience', 'certifications', 'license_number',

            'certification_document', 'license_document', 'photo_id_document',

            'is_available', 'hourly_rate', 'daily_rate', 'base_location'

        ]

Purpose: Tour guide profile and document management Features:

Professional Information:

  • Multilingual biographical information
  • Specialization tracking
  • Experience and certification management

Document Upload System:

def _validate_document_file(self, file, file_type):

    """Validate uploaded document files"""

    if file:

        # Validate file size (max 10MB)

        if file.size > 10 * 1024 * 1024:

            raise ValidationError(f'{file_type.title()} must be smaller than 10MB.')

        

        # Validate file type

        valid_extensions = ['.pdf', '.doc', '.docx', '.jpg', '.jpeg', '.png']

        file_extension = file.name.lower().split('.')[-1]

        if f'.{file_extension}' not in valid_extensions:

            raise ValidationError(

                f'Please upload a valid {file_type} (PDF, DOC, DOCX, JPG, PNG).'

            )

    

    return file

Rate Management:

  • Hourly and daily rate setting
  • Availability status management
  • Location-based service areas

 

 

8. Additional Supporting Forms

TourItineraryForm: Day-by-day tour planning

  • Daily activity descriptions
  • Accommodation and meal tracking
  • Location-specific information

TourInclusionForm: Tour inclusion/exclusion management

  • What's included vs additional costs
  • Multilingual item descriptions
  • Cost transparency

TourGuideVerificationForm: Admin verification system

  • Guide verification status management
  • Admin notes and feedback
  • Quality control processes

Form System Architecture

Bootstrap Integration

All forms include Bootstrap CSS classes:

def __init__(self, *args, **kwargs):

    super().__init__(*args, **kwargs)

    # Add CSS classes

    for field_name, field in self.fields.items():

        if field_name not in ['operator_type', 'certification']:

            field.widget.attrs['class'] = 'form-control'

 

 

Multilingual Support

Consistent Vietnamese/English field pairs:

  • name / name_vi
  • description / description_vi
  • title / title_vi

Business Rule Enforcement

  • Age range validation
  • Participant count limits
  • Schedule availability checking
  • Price calculation automation
  • Document upload validation

User Experience Features

  • Auto-population of user data
  • Dynamic field filtering
  • Real-time validation
  • File upload progress
  • Responsive design support

 

 

Security & Validation

File Upload Security:

  • File size limits (5MB for images, 10MB for documents)
  • File type validation
  • Secure file handling

Business Logic Validation:

  • Capacity checking before booking
  • Age requirement enforcement
  • Schedule date validation
  • Price range validation

User Permission Control:

  • Operator-specific data filtering
  • Role-based field access
  • Secure form submission

This comprehensive form system provides a robust, user-friendly interface for all tour operators business processes, from operator registration through customer booking and guide management, with strong validation and security measures throughout.

 

Vietnamese translation is not available for this article. Showing English content:

Nhom

Notes

 

Tour Operators Forms System - Detailed Analysis

File Overview

Purpose: Django form definitions for tour operators management system Locationforms.py Function: User interface forms for data input, validation, and processing Framework: Django Forms with Bootstrap styling integration

Import Dependencies Analysis

from django import forms

from django.core.exceptions import ValidationError

from django.utils import timezone

from django.db import models

from decimal import Decimal

from .models import (

    TourOperator, Tour, TourBooking, TourSchedule, TourGuide, TourCategory,

    TourItinerary, TourInclusion, TourParticipant

)

Key Components:

  • forms: Django forms framework
  • ValidationError: Custom validation error handling
  • timezone: Date/time utilities for scheduling
  • Decimal: Precise monetary calculations
  • Model imports: All tour operator related models

 

 

Forms Detailed Breakdown

 

 

1. TourOperatorForm - Operator Registration/Management

class TourOperatorForm(forms.ModelForm):

    class Meta:

        model = TourOperator

        fields = [

            'name', 'name_vi', 'description', 'description_vi', 'operator_type',

            'email', 'phone', 'website', 'address', 'city', 'country',

            'license_number', 'certification', 'established_year',

            'api_endpoint', 'api_key', 'commission_rate'

        ]

Purpose: Tour operator profile creation and management Field Categories:

Basic Information:

  • name / name_vi: English and Vietnamese business names
  • description / description_vi: Multilingual business descriptions
  • operator_type: Business classification (local, international, specialty)

Contact & Location:

  • email, phone, website: Communication channels
  • address, city, country: Geographic information

Legal & Business:

  • license_number: Government licensing
  • certification: Industry certifications (IATA, etc.)
  • established_year: Business history

API Integration:

  • api_endpoint, api_key: External system connections
  • commission_rate: Revenue sharing percentage

Widget Customizations:

widgets = {

    'description': forms.Textarea(attrs={'rows': 4}),

    'description_vi': forms.Textarea(attrs={'rows': 4}),

    'address': forms.Textarea(attrs={'rows': 3}),

    'operator_type': forms.Select(attrs={'class': 'form-select'}),

    'certification': forms.Select(attrs={'class': 'form-select'}),

    'commission_rate': forms.NumberInput(attrs={'step': '0.01', 'min': '0', 'max': '100'}),

}

Business Use: Operator onboarding, profile updates, partnership management

 

 

2. TourForm - Comprehensive Tour Creation

class TourForm(forms.ModelForm):

    class Meta:

        model = Tour

        fields = [

            'title', 'title_vi', 'slug', 'short_description', 'short_description_vi',

            'description', 'description_vi', 'tour_operator', 'categories',

            'tour_type', 'difficulty', 'duration_days', 'duration_hours',

            'start_location', 'end_location', 'destinations',

            'min_participants', 'max_participants', 'min_age', 'max_age',

            'base_price', 'price_currency', 'child_price', 'senior_price',

            'includes_accommodation', 'includes_meals', 'includes_transport',

            'includes_guide', 'includes_tickets', 'fitness_level_required',

            'special_requirements', 'what_to_bring', 'main_image', 'video_url'

        ]

Purpose: Complete tour creation and editing interface Field Groups:

Content Management:

  • title / title_vi: Multilingual tour names
  • slug: URL-friendly identifier
  • short_description / short_description_vi: Brief summaries
  • description / description_vi: Detailed descriptions

Tour Classification:

  • tour_operator: Associated operator
  • categories: Multiple category associations
  • tour_type: Type classification (group, private, custom)
  • difficulty: Difficulty rating

Logistics:

  • duration_days / duration_hours: Time requirements
  • start_location / end_location: Geographic points
  • destinations: Multiple destination support

Capacity & Demographics:

  • min_participants / max_participants: Group size limits
  • min_age / max_age: Age restrictions

Pricing Structure:

  • base_price, price_currency: Standard pricing
  • child_price, senior_price: Demographic pricing

Inclusions:

  • Boolean flags for accommodation, meals, transport, guide, tickets
  • fitness_level_required: Physical requirements

Advanced Features:

User Permission Control:

def __init__(self, *args, **kwargs):

    self.user = kwargs.pop('user', None)

    super().__init__(*args, **kwargs)

    

    # Limit tour operator choices to user's operators

    if self.user and not self.user.is_staff:

        user_operators = TourOperator.objects.filter(

            models.Q(user=self.user) | models.Q(managers=self.user)

        )

        self.fields['tour_operator'].queryset = user_operators

Custom Validation:

def clean_slug(self):

    slug = self.cleaned_data['slug']

    qs = Tour.objects.filter(slug=slug)

    if self.instance:

        qs = qs.exclude(pk=self.instance.pk)

    if qs.exists():

        raise ValidationError('This slug is already taken.')

    return slug

def clean(self):

    cleaned_data = super().clean()

    min_age = cleaned_data.get('min_age')

    max_age = cleaned_data.get('max_age')

    

    if min_age and max_age and min_age >= max_age:

        raise ValidationError('Maximum age must be greater than minimum age.')

 

 

3. TourBookingForm - Advanced Booking System

class TourBookingForm(forms.ModelForm):

    # Participant details

    adult_count = forms.IntegerField(min_value=1, initial=1)

    child_count = forms.IntegerField(min_value=0, initial=0)

    senior_count = forms.IntegerField(min_value=0, initial=0)

    

    # Lead traveler details

    lead_traveler_name = forms.CharField(max_length=200)

    lead_traveler_email = forms.EmailField()

    lead_traveler_phone = forms.CharField(max_length=20)

Purpose: Customer booking creation with complex validation Key Features:

Dynamic Schedule Filtering:

def __init__(self, *args, **kwargs):

    self.tour = kwargs.pop('tour', None)

    self.user = kwargs.pop('user', None)

    super().__init__(*args, **kwargs)

    

    if self.tour:

        # Filter schedules for this tour

        today = timezone.now().date()

        self.fields['schedule'].queryset = TourSchedule.objects.filter(

            tour=self.tour,

            is_active=True,

            start_date__gte=today

        ).order_by('start_date', 'start_time')

User Auto-Population:

# Pre-fill user details if available

if self.user:

    self.fields['lead_traveler_name'].initial = self.user.get_full_name()

    self.fields['lead_traveler_email'].initial = self.user.email

Complex Business Validation:

def clean(self):

    cleaned_data = super().clean()

    adult_count = cleaned_data.get('adult_count', 0)

    child_count = cleaned_data.get('child_count', 0)

    senior_count = cleaned_data.get('senior_count', 0)

    schedule = cleaned_data.get('schedule')

    

    total_participants = adult_count + child_count + senior_count

    

    if total_participants == 0:

        raise ValidationError('At least one participant is required.')

    

    if schedule and self.tour:

        if total_participants < self.tour.min_participants:

            raise ValidationError(f'Minimum {self.tour.min_participants} participants required.')

        

        if total_participants > self.tour.max_participants:

            raise ValidationError(f'Maximum {self.tour.max_participants} participants allowed.')

        

        if total_participants > schedule.remaining_spots:

            raise ValidationError(f'Only {schedule.remaining_spots} spots available for this schedule.')

Advanced Save Method with Pricing Logic:

def save(self, commit=True):

    booking = super().save(commit=False)

    

    # Calculate pricing

    adult_count = self.cleaned_data['adult_count']

    child_count = self.cleaned_data['child_count']

    senior_count = self.cleaned_data['senior_count']

    

    schedule = self.cleaned_data['schedule']

    base_price = schedule.price_override or self.tour.base_price

    

    # Calculate total price

    adult_price = base_price * adult_count

    child_price = (self.tour.child_price or base_price * Decimal('0.7')) * child_count

    senior_price = (self.tour.senior_price or base_price * Decimal('0.9')) * senior_count

    

    booking.base_price = base_price

    booking.total_price = adult_price + child_price + senior_price

    booking.total_participants = self.cleaned_data['total_participants']

    

    if commit:

        booking.save()

        

        # Update schedule booked spots

        schedule.booked_spots += booking.total_participants

        schedule.save()

    

    return booking

 

 

4. TourScheduleForm - Schedule Management

class TourScheduleForm(forms.ModelForm):

    class Meta:

        model = TourSchedule

        fields = [

            'schedule_type', 'start_date', 'end_date', 'start_time',

            'days_of_week', 'available_spots', 'price_override', 'notes'

        ]

Purpose: Tour schedule creation and management Features:

  • Date/time picking with HTML5 widgets
  • Schedule type validation (fixed vs recurring)
  • Price override capabilities
  • Capacity management

Business Logic Validation:

def clean(self):

    cleaned_data = super().clean()

    start_date = cleaned_data.get('start_date')

    end_date = cleaned_data.get('end_date')

    schedule_type = cleaned_data.get('schedule_type')

    

    if schedule_type == 'fixed' and not start_date:

        raise ValidationError('Start date is required for fixed schedules.')

    

    if start_date and end_date and start_date > end_date:

        raise ValidationError('End date must be after start date.')

 

 

5. TourSearchForm - Advanced Search Interface

class TourSearchForm(forms.Form):

    SORT_CHOICES = [

        ('featured', 'Featured'),

        ('price_low', 'Price: Low to High'),

        ('price_high', 'Price: High to Low'),

        ('rating', 'Highest Rated'),

        ('duration', 'Duration'),

        ('alphabetical', 'Alphabetical'),

    ]

Purpose: Comprehensive tour search and filtering Search Capabilities:

Text Search:

search = forms.CharField(

    required=False,

    widget=forms.TextInput(attrs={

        'class': 'form-control',

        'placeholder': 'Search tours...'

    })

)

Category Filtering:

category = forms.ModelChoiceField(

    queryset=TourCategory.objects.filter(is_active=True),

    required=False,

    empty_label='All Categories',

    widget=forms.Select(attrs={'class': 'form-select'})

)

Price Range Filtering:

min_price = forms.DecimalField(

    required=False,

    widget=forms.NumberInput(attrs={

        'class': 'form-control',

        'step': '0.01',

        'min': '0'

    })

)

max_price = forms.DecimalField(

    required=False,

    widget=forms.NumberInput(attrs={

        'class': 'form-control',

        'step': '0.01',

        'min': '0'

    })

)

 

 

6. TourParticipantForm - International Travel Support

class TourParticipantForm(forms.ModelForm):

    """Form for collecting individual participant details including passport upload"""

    

    class Meta:

        model = TourParticipant

        fields = [

            'participant_type', 'first_name', 'last_name', 'date_of_birth',

            'nationality', 'passport_number', 'passport_expiry', 'passport_image',

            'dietary_requirements', 'medical_conditions', 

            'emergency_contact_name', 'emergency_contact_phone'

        ]

Purpose: International tour participant data collection Key Features:

Document Upload Validation:

def clean_passport_image(self):

    passport_image = self.cleaned_data.get('passport_image')

    

    if passport_image:

        # Validate file size (max 5MB)

        if passport_image.size > 5 * 1024 * 1024:

            raise ValidationError('Passport image must be smaller than 5MB.')

        

        # Validate file type

        valid_extensions = ['.jpg', '.jpeg', '.png', '.pdf']

        file_extension = passport_image.name.lower().split('.')[-1]

        if f'.{file_extension}' not in valid_extensions:

            raise ValidationError('Please upload a valid image file (JPG, PNG) or PDF.')

    

    return passport_image

Required Field Management:

def __init__(self, *args, **kwargs):

    super().__init__(*args, **kwargs)

    

    # Mark required fields

    required_fields = ['first_name', 'last_name', 'nationality']

    for field_name in required_fields:

        if field_name in self.fields:

            self.fields[field_name].required = True

            self.fields[field_name].widget.attrs['required'] = True

 

 

7. TourGuideForm - Professional Guide Management

class TourGuideForm(forms.ModelForm):

    """Form for tour guides to update their profile and upload documents"""

    

    class Meta:

        model = TourGuide

        fields = [

            'bio', 'bio_vi', 'specializations', 'languages',

            'years_experience', 'certifications', 'license_number',

            'certification_document', 'license_document', 'photo_id_document',

            'is_available', 'hourly_rate', 'daily_rate', 'base_location'

        ]

Purpose: Tour guide profile and document management Features:

Professional Information:

  • Multilingual biographical information
  • Specialization tracking
  • Experience and certification management

Document Upload System:

def _validate_document_file(self, file, file_type):

    """Validate uploaded document files"""

    if file:

        # Validate file size (max 10MB)

        if file.size > 10 * 1024 * 1024:

            raise ValidationError(f'{file_type.title()} must be smaller than 10MB.')

        

        # Validate file type

        valid_extensions = ['.pdf', '.doc', '.docx', '.jpg', '.jpeg', '.png']

        file_extension = file.name.lower().split('.')[-1]

        if f'.{file_extension}' not in valid_extensions:

            raise ValidationError(

                f'Please upload a valid {file_type} (PDF, DOC, DOCX, JPG, PNG).'

            )

    

    return file

Rate Management:

  • Hourly and daily rate setting
  • Availability status management
  • Location-based service areas

 

 

8. Additional Supporting Forms

TourItineraryForm: Day-by-day tour planning

  • Daily activity descriptions
  • Accommodation and meal tracking
  • Location-specific information

TourInclusionForm: Tour inclusion/exclusion management

  • What's included vs additional costs
  • Multilingual item descriptions
  • Cost transparency

TourGuideVerificationForm: Admin verification system

  • Guide verification status management
  • Admin notes and feedback
  • Quality control processes

Form System Architecture

Bootstrap Integration

All forms include Bootstrap CSS classes:

def __init__(self, *args, **kwargs):

    super().__init__(*args, **kwargs)

    # Add CSS classes

    for field_name, field in self.fields.items():

        if field_name not in ['operator_type', 'certification']:

            field.widget.attrs['class'] = 'form-control'

 

 

Multilingual Support

Consistent Vietnamese/English field pairs:

  • name / name_vi
  • description / description_vi
  • title / title_vi

Business Rule Enforcement

  • Age range validation
  • Participant count limits
  • Schedule availability checking
  • Price calculation automation
  • Document upload validation

User Experience Features

  • Auto-population of user data
  • Dynamic field filtering
  • Real-time validation
  • File upload progress
  • Responsive design support

 

 

Security & Validation

File Upload Security:

  • File size limits (5MB for images, 10MB for documents)
  • File type validation
  • Secure file handling

Business Logic Validation:

  • Capacity checking before booking
  • Age requirement enforcement
  • Schedule date validation
  • Price range validation

User Permission Control:

  • Operator-specific data filtering
  • Role-based field access
  • Secure form submission

This comprehensive form system provides a robust, user-friendly interface for all tour operators business processes, from operator registration through customer booking and guide management, with strong validation and security measures throughout.

 

Attached Files

0 files found.

You are viewing this article in public mode. Some features may be limited.