* Vietnamese translation incomplete

Tour operator signals

Tour operator signals (English fallback)

Aug. 17, 2025

Posted by admin

Nhom

Notes

 

I'll explain the tour operators signals.py file in detail, including its purpose, functionality, and how it maintains data consistency across the system.

Tour Operators Signals System - Detailed Analysis

File Overview

Purpose: Automatic data consistency maintenance and statistics updates Locationsignals.py Pattern: Django signals with receivers for real-time data synchronization

Imports and Dependencies

from django.db.models.signals import post_save, post_delete

from django.dispatch import receiver

from django.db.models import Avg, Count

from .models import TourBooking, Tour, TourOperator

Signal Types Used:

  • post_save: Triggered after a model instance is saved (create/update)
  • post_delete: Triggered after a model instance is deleted

Models Involved:

  • TourBooking: Individual tour reservations
  • Tour: Tour offerings from operators
  • TourOperator: Companies providing tours

 

 

Signal Handlers Detailed Analysis

 

 

1. Booking Statistics Handler (post_save)

@receiver(post_save, sender=TourBooking)

def update_tour_booking_stats(sender, instance, created, **kwargs):

    """Update tour booking statistics when a booking is created or updated"""

    tour = instance.tour

    

    # Update total bookings count

    tour.total_bookings = TourBooking.objects.filter(

        tour=tour,

        booking_status__in=['confirmed', 'paid', 'completed']

    ).count()

    

    tour.save(update_fields=['total_bookings'])

    

    # Update tour operator statistics

    operator = tour.tour_operator

    operator.total_tours = Tour.objects.filter(tour_operator=operator, is_active=True).count()

    operator.save(update_fields=['total_tours'])

Trigger Conditions:

  • When a new TourBooking is created
  • When an existing TourBooking is updated (status changes, modifications)

Functionality Breakdown:

  1. Tour Booking Count Update:
    • Counts only bookings with valid statuses: 'confirmed', 'paid', 'completed'
    • Excludes cancelled, pending, or failed bookings
    • Updates the total_bookings field on the related Tour model
  2. Operator Statistics Update:
    • Counts active tours (is_active=True) for the tour operator
    • Updates the total_tours field on the TourOperator model
    • Maintains consistency between operator and tour data

Business Impact:

  • Real-time statistics for tour popularity
  • Accurate booking counts for business analytics
  • Automatic maintenance of aggregate data

 

 

2. Booking Deletion Handler (post_delete)

@receiver(post_delete, sender=TourBooking)

def update_tour_booking_stats_on_delete(sender, instance, **kwargs):

    """Update tour booking statistics when a booking is deleted"""

    tour = instance.tour

    

    # Update total bookings count

    tour.total_bookings = TourBooking.objects.filter(

        tour=tour,

        booking_status__in=['confirmed', 'paid', 'completed']

    ).count()

    

    tour.save(update_fields=['total_bookings'])

Trigger Conditions:

  • When a TourBooking instance is permanently deleted from the database

Functionality:

  • Recalculates the total booking count for the affected tour
  • Ensures statistics remain accurate after booking deletions
  • Uses the same filtering logic (confirmed/paid/completed statuses)

Use Cases:

  • Administrative booking removals
  • Data cleanup operations
  • Cancelled booking permanent deletion

 

 

3. Tour Count Handler (post_save)

@receiver(post_save, sender=Tour)

def update_operator_tour_count(sender, instance, created, **kwargs):

    """Update tour operator's total tours count when a tour is created/updated"""

    operator = instance.tour_operator

    operator.total_tours = Tour.objects.filter(tour_operator=operator, is_active=True).count()

    operator.save(update_fields=['total_tours'])

Trigger Conditions:

  • When a new Tour is created
  • When an existing Tour is updated (including status changes)

Functionality:

  • Recalculates active tour count for the tour operator
  • Updates operator's total_tours field
  • Only counts tours with is_active=True

Business Scenarios:

  • New tour launches
  • Tour activation/deactivation
  • Tour status changes
  • Operator profile updates

 

 

4. Tour Deletion Handler (post_delete)

@receiver(post_delete, sender=Tour)

def update_operator_tour_count_on_delete(sender, instance, **kwargs):

    """Update tour operator's total tours count when a tour is deleted"""

    operator = instance.tour_operator

    operator.total_tours = Tour.objects.filter(tour_operator=operator, is_active=True).count()

    operator.save(update_fields=['total_tours'])

Trigger Conditions:

  • When a Tour instance is permanently deleted

Functionality:

  • Decrements the operator's tour count automatically
  • Maintains data consistency after tour removal
  • Prevents orphaned statistics

Signal System Architecture Benefits

Data Consistency

  • Automatic Updates: No manual intervention required for statistics
  • Real-time Accuracy: Statistics update immediately with data changes
  • Referential Integrity: Maintains relationships between models

Performance Optimization

  • Efficient Queries: Uses update_fields to minimize database writes
  • Targeted Updates: Only updates specific fields that changed
  • Avoiding N+1 Queries: Direct count queries instead of iteration

Business Intelligence

  • Live Metrics: Tour popularity and operator performance tracking
  • Booking Analytics: Real-time booking success rates
  • Operator Rankings: Accurate tour counts for comparison

 

 

Data Flow Example

Scenario: Customer books a tour

  1. TourBooking Created:

TourBooking.objects.create(

    tour=tour_instance,

    booking_status='confirmed',

    customer=user

)

  1. Signal Triggered: update_tour_booking_stats fires
  2. Cascade Updates:
    • Tour's total_bookings increments
    • Operator's total_tours recalculated (if tour status changed)
  3. UI Updates:
    • Tour detail page shows updated booking count
    • Operator profile displays current statistics

Error Handling Considerations

Potential Issues:

  • Database transaction failures during signal processing
  • Circular signal triggering (avoided by using update_fields)
  • High-frequency updates causing performance issues

Current Protections:

  • update_fields parameter prevents unnecessary field updates
  • Specific field targeting reduces database load
  • Status filtering ensures only valid bookings are counted

Integration with Business Logic

Template Usage:

Admin Interface:

  • Real-time statistics visible in Django admin
  • No manual calculation required for aggregate fields

API Endpoints:

  • REST API can return accurate statistics without additional queries
  • Real-time data for dashboard components

 

 

Recommendations for Enhancement

  1. Add Error Logging:

import logging

logger = logging.getLogger(__name__)

try:

    tour.save(update_fields=['total_bookings'])

except Exception as e:

    logger.error(f"Failed to update tour stats: {e}")

  1. Consider Celery for Heavy Operations:
    • Move complex calculations to background tasks
    • Prevent blocking request processing
  2. Add Rating Calculations:

# Add to booking stats handler

tour.average_rating = TourBooking.objects.filter(

    tour=tour, rating__isnull=False

).aggregate(avg_rating=Avg('rating'))['avg_rating'] or 0

  1. Implement Caching Strategy:
    • Cache frequently accessed statistics
    • Invalidate cache when signals fire

This signals system provides robust, automatic data consistency maintenance that's essential for a professional tour booking platform, ensuring accurate statistics and seamless user experience

 

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

Nhom

Notes

 

I'll explain the tour operators signals.py file in detail, including its purpose, functionality, and how it maintains data consistency across the system.

Tour Operators Signals System - Detailed Analysis

File Overview

Purpose: Automatic data consistency maintenance and statistics updates Locationsignals.py Pattern: Django signals with receivers for real-time data synchronization

Imports and Dependencies

from django.db.models.signals import post_save, post_delete

from django.dispatch import receiver

from django.db.models import Avg, Count

from .models import TourBooking, Tour, TourOperator

Signal Types Used:

  • post_save: Triggered after a model instance is saved (create/update)
  • post_delete: Triggered after a model instance is deleted

Models Involved:

  • TourBooking: Individual tour reservations
  • Tour: Tour offerings from operators
  • TourOperator: Companies providing tours

 

 

Signal Handlers Detailed Analysis

 

 

1. Booking Statistics Handler (post_save)

@receiver(post_save, sender=TourBooking)

def update_tour_booking_stats(sender, instance, created, **kwargs):

    """Update tour booking statistics when a booking is created or updated"""

    tour = instance.tour

    

    # Update total bookings count

    tour.total_bookings = TourBooking.objects.filter(

        tour=tour,

        booking_status__in=['confirmed', 'paid', 'completed']

    ).count()

    

    tour.save(update_fields=['total_bookings'])

    

    # Update tour operator statistics

    operator = tour.tour_operator

    operator.total_tours = Tour.objects.filter(tour_operator=operator, is_active=True).count()

    operator.save(update_fields=['total_tours'])

Trigger Conditions:

  • When a new TourBooking is created
  • When an existing TourBooking is updated (status changes, modifications)

Functionality Breakdown:

  1. Tour Booking Count Update:
    • Counts only bookings with valid statuses: 'confirmed', 'paid', 'completed'
    • Excludes cancelled, pending, or failed bookings
    • Updates the total_bookings field on the related Tour model
  2. Operator Statistics Update:
    • Counts active tours (is_active=True) for the tour operator
    • Updates the total_tours field on the TourOperator model
    • Maintains consistency between operator and tour data

Business Impact:

  • Real-time statistics for tour popularity
  • Accurate booking counts for business analytics
  • Automatic maintenance of aggregate data

 

 

2. Booking Deletion Handler (post_delete)

@receiver(post_delete, sender=TourBooking)

def update_tour_booking_stats_on_delete(sender, instance, **kwargs):

    """Update tour booking statistics when a booking is deleted"""

    tour = instance.tour

    

    # Update total bookings count

    tour.total_bookings = TourBooking.objects.filter(

        tour=tour,

        booking_status__in=['confirmed', 'paid', 'completed']

    ).count()

    

    tour.save(update_fields=['total_bookings'])

Trigger Conditions:

  • When a TourBooking instance is permanently deleted from the database

Functionality:

  • Recalculates the total booking count for the affected tour
  • Ensures statistics remain accurate after booking deletions
  • Uses the same filtering logic (confirmed/paid/completed statuses)

Use Cases:

  • Administrative booking removals
  • Data cleanup operations
  • Cancelled booking permanent deletion

 

 

3. Tour Count Handler (post_save)

@receiver(post_save, sender=Tour)

def update_operator_tour_count(sender, instance, created, **kwargs):

    """Update tour operator's total tours count when a tour is created/updated"""

    operator = instance.tour_operator

    operator.total_tours = Tour.objects.filter(tour_operator=operator, is_active=True).count()

    operator.save(update_fields=['total_tours'])

Trigger Conditions:

  • When a new Tour is created
  • When an existing Tour is updated (including status changes)

Functionality:

  • Recalculates active tour count for the tour operator
  • Updates operator's total_tours field
  • Only counts tours with is_active=True

Business Scenarios:

  • New tour launches
  • Tour activation/deactivation
  • Tour status changes
  • Operator profile updates

 

 

4. Tour Deletion Handler (post_delete)

@receiver(post_delete, sender=Tour)

def update_operator_tour_count_on_delete(sender, instance, **kwargs):

    """Update tour operator's total tours count when a tour is deleted"""

    operator = instance.tour_operator

    operator.total_tours = Tour.objects.filter(tour_operator=operator, is_active=True).count()

    operator.save(update_fields=['total_tours'])

Trigger Conditions:

  • When a Tour instance is permanently deleted

Functionality:

  • Decrements the operator's tour count automatically
  • Maintains data consistency after tour removal
  • Prevents orphaned statistics

Signal System Architecture Benefits

Data Consistency

  • Automatic Updates: No manual intervention required for statistics
  • Real-time Accuracy: Statistics update immediately with data changes
  • Referential Integrity: Maintains relationships between models

Performance Optimization

  • Efficient Queries: Uses update_fields to minimize database writes
  • Targeted Updates: Only updates specific fields that changed
  • Avoiding N+1 Queries: Direct count queries instead of iteration

Business Intelligence

  • Live Metrics: Tour popularity and operator performance tracking
  • Booking Analytics: Real-time booking success rates
  • Operator Rankings: Accurate tour counts for comparison

 

 

Data Flow Example

Scenario: Customer books a tour

  1. TourBooking Created:

TourBooking.objects.create(

    tour=tour_instance,

    booking_status='confirmed',

    customer=user

)

  1. Signal Triggered: update_tour_booking_stats fires
  2. Cascade Updates:
    • Tour's total_bookings increments
    • Operator's total_tours recalculated (if tour status changed)
  3. UI Updates:
    • Tour detail page shows updated booking count
    • Operator profile displays current statistics

Error Handling Considerations

Potential Issues:

  • Database transaction failures during signal processing
  • Circular signal triggering (avoided by using update_fields)
  • High-frequency updates causing performance issues

Current Protections:

  • update_fields parameter prevents unnecessary field updates
  • Specific field targeting reduces database load
  • Status filtering ensures only valid bookings are counted

Integration with Business Logic

Template Usage:

Admin Interface:

  • Real-time statistics visible in Django admin
  • No manual calculation required for aggregate fields

API Endpoints:

  • REST API can return accurate statistics without additional queries
  • Real-time data for dashboard components

 

 

Recommendations for Enhancement

  1. Add Error Logging:

import logging

logger = logging.getLogger(__name__)

try:

    tour.save(update_fields=['total_bookings'])

except Exception as e:

    logger.error(f"Failed to update tour stats: {e}")

  1. Consider Celery for Heavy Operations:
    • Move complex calculations to background tasks
    • Prevent blocking request processing
  2. Add Rating Calculations:

# Add to booking stats handler

tour.average_rating = TourBooking.objects.filter(

    tour=tour, rating__isnull=False

).aggregate(avg_rating=Avg('rating'))['avg_rating'] or 0

  1. Implement Caching Strategy:
    • Cache frequently accessed statistics
    • Invalidate cache when signals fire

This signals system provides robust, automatic data consistency maintenance that's essential for a professional tour booking platform, ensuring accurate statistics and seamless user experience

 

Attached Files

0 files found.

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