Business Directory Models explain
Business Directory Models explain (English fallback)
Aug. 16, 2025
Posted by admin
Nhom |
Notes |
|
The Business Directory models provide a comprehensive foundation for managing travel-related businesses in Vietnam, with full multilingual support, subscription management, customer reviews, and business verification systems suitable for a professional travel platform .
|
|
I'll provide a comprehensive explanation of the Business Directory models and their fields, showing how they work together to create a complete business listing platform for the DichVuHowTo travel website. 🏢 Business Directory Models Overview The business directory system consists of four main models that work together to create a comprehensive business listing platform with multilingual support, reviews, and business verification.
|
|
|
Listing |
🏪 BusinessListing Model - Core Business Information 📋 Basic Business Information business_name = models.CharField(max_length=200) business_name_vi = models.CharField(max_length=200, blank=True, verbose_name="Vietnamese Business Name") slug = models.SlugField(max_length=200, unique=True) category = models.ForeignKey(BusinessCategory, on_delete=models.CASCADE, related_name='businesses') owner = models.ForeignKey(User, on_delete=models.CASCADE, related_name='businesses') Core Identity:
Example Usage: saigon_hotel = BusinessListing.objects.create( business_name="Saigon Grand Hotel", business_name_vi="Khách sạn Sài Gòn Grand", slug="saigon-grand-hotel", category=luxury_hotels_category, owner=hotel_manager_user ) 📝 Description Fields description = models.TextField() description_vi = models.TextField(blank=True, verbose_name="Vietnamese Description") short_description = models.CharField(max_length=300, help_text="Brief description for listings") short_description_vi = models.CharField(max_length=300, blank=True, verbose_name="Vietnamese Short Description") Content Strategy:
Template Usage: <!-- Listing card --> <div class="business-card"> <h3>{{ business.get_display_name:request.LANGUAGE_CODE }}</h3> <p>{{ business.get_display_short_description:request.LANGUAGE_CODE }}</p> </div> <!-- Detail page --> <div class="business-detail"> {{ business.get_display_description:request.LANGUAGE_CODE|safe }} </div> 📞 Contact Information phone = models.CharField(max_length=20) email = models.EmailField() website = models.URLField(blank=True) Customer Communication:
Template Implementation: <div class="contact-info"> <a href="tel:{{ business.phone }}" class="btn btn-primary"> <i class="fas fa-phone"></i> Call Now </a> <a href="mailto:{{ business.email }}" class="btn btn-secondary"> <i class="fas fa-envelope"></i> Email </a> {% if business.website %} <a href="{{ business.website }}" target="_blank" class="btn btn-info"> <i class="fas fa-globe"></i> Website </a> {% endif %} </div> 📍 Location & Mapping street_address = models.CharField(max_length=200) city = models.CharField(max_length=100) state = models.CharField(max_length=100) postal_code = models.CharField(max_length=20) country = models.CharField(max_length=100, default='Vietnam') latitude = models.DecimalField(max_digits=10, decimal_places=8, null=True, blank=True) longitude = models.DecimalField(max_digits=11, decimal_places=8, null=True, blank=True) Geographic Features:
Map Integration Example: def get_full_address(self): """Get formatted full address""" parts = [self.street_address, self.city, self.state, self.postal_code, self.country] return ', '.join(filter(None, parts)) # Template usage with Google Maps <div id="map" data-lat="{{ business.latitude }}" data-lng="{{ business.longitude }}"> <p>{{ business.get_full_address }}</p> </div> 🕒 Business Hours System monday_hours = models.CharField(max_length=50, blank=True, help_text="e.g., 9:00 AM - 5:00 PM") tuesday_hours = models.CharField(max_length=50, blank=True) wednesday_hours = models.CharField(max_length=50, blank=True) thursday_hours = models.CharField(max_length=50, blank=True) friday_hours = models.CharField(max_length=50, blank=True) saturday_hours = models.CharField(max_length=50, blank=True) sunday_hours = models.CharField(max_length=50, blank=True) Operating Hours Management:
Template Display: <div class="business-hours"> <h4>Business Hours</h4> <ul class="list-unstyled"> <li><strong>Monday:</strong> {{ business.monday_hours|default:"Closed" }}</li> <li><strong>Tuesday:</strong> {{ business.tuesday_hours|default:"Closed" }}</li> <!-- ... other days ... --> </ul> </div> 📱 Social Media Integration facebook_url = models.URLField(blank=True) twitter_url = models.URLField(blank=True) instagram_url = models.URLField(blank=True) linkedin_url = models.URLField(blank=True) Social Presence:
✨ Feature & Amenities Flags accepts_credit_cards = models.BooleanField(default=False) parking_available = models.BooleanField(default=False) wheelchair_accessible = models.BooleanField(default=False) wifi_available = models.BooleanField(default=False) outdoor_seating = models.BooleanField(default=False) delivery_available = models.BooleanField(default=False) Customer Decision Factors:
Filter & Search Integration: # Find restaurants with WiFi and outdoor seating restaurants_with_amenities = BusinessListing.objects.filter( category__slug='restaurants', wifi_available=True, outdoor_seating=True, status='approved' ) 💼 Subscription & Status Management SUBSCRIPTION_CHOICES = [ ('free', 'Free Listing'), ('basic', 'Basic Listing'), ('premium', 'Premium Listing'), ('featured', 'Featured Listing'), ] STATUS_CHOICES = [ ('draft', 'Draft'), ('pending', 'Pending Approval'), ('approved', 'Approved'), ('rejected', 'Rejected'), ('suspended', 'Suspended'), ] subscription_type = models.CharField(max_length=20, choices=SUBSCRIPTION_CHOICES, default='free') status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='draft') is_verified = models.BooleanField(default=False) is_featured = models.BooleanField(default=False) Business Monetization:
Business Logic: # Get featured businesses for homepage featured_businesses = BusinessListing.objects.filter( status='approved', is_featured=True, subscription_type__in=['premium', 'featured'] ).order_by('-created_at') # Subscription-based features def can_upload_multiple_photos(self): return self.subscription_type in ['premium', 'featured'] def max_photos_allowed(self): photo_limits = { 'free': 3, 'basic': 10, 'premium': 25, 'featured': 50 } return photo_limits.get(self.subscription_type, 3) 🔍 SEO & Marketing Fields meta_title = models.CharField(max_length=60, blank=True) meta_description = models.CharField(max_length=160, blank=True) keywords = models.CharField(max_length=200, blank=True, help_text="Comma-separated keywords") Search Engine Optimization:
Template SEO Integration: <head> <title>{{ business.meta_title|default:business.business_name }} - DichVuHowTo</title> <meta name="description" content="{{ business.meta_description|default:business.short_description }}"> <meta name="keywords" content="{{ business.keywords }}"> </head> 📊 Analytics & Performance Tracking views_count = models.PositiveIntegerField(default=0) phone_clicks = models.PositiveIntegerField(default=0) website_clicks = models.PositiveIntegerField(default=0) Business Intelligence:
Analytics Implementation: def increment_views(self): """Increment view counter""" self.views_count += 1 self.save(update_fields=['views_count']) def track_phone_click(self): """Track phone number clicks""" self.phone_clicks += 1 self.save(update_fields=['phone_clicks']) # In views def business_detail(request, slug): business = get_object_or_404(BusinessListing, slug=slug) business.increment_views() # Track page view return render(request, 'business_detail.html', {'business': business}) ⏰ Subscription Management created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) featured_until = models.DateTimeField(null=True, blank=True) subscription_expires = models.DateTimeField(null=True, blank=True) Temporal Business Logic:
Subscription Management: from django.utils import timezone def is_subscription_active(self): """Check if subscription is still active""" if not self.subscription_expires: return True # Lifetime subscription return timezone.now() < self.subscription_expires def is_currently_featured(self): """Check if business is currently featured""" if not self.is_featured or not self.featured_until: return self.is_featured return timezone.now() < self.featured_until # Automated tasks def expire_featured_listings(): """Celery task to expire featured listings""" expired_listings = BusinessListing.objects.filter( is_featured=True, featured_until__lt=timezone.now() ) expired_listings.update(is_featured=False)
|
Listing Category |
📂 BusinessCategory Model - Hierarchical Organization 🔤 Basic Information Fields name = models.CharField(max_length=100, unique=True) name_vi = models.CharField(max_length=100, blank=True, verbose_name="Vietnamese Name") slug = models.SlugField(max_length=100, unique=True) description = models.TextField(blank=True) description_vi = models.TextField(blank=True, verbose_name="Vietnamese Description") Purpose: Creates bilingual category structure for business organization
Real-World Examples: # Tourism category structure tourism_services = BusinessCategory.objects.create( name="Tourism Services", name_vi="Dịch vụ du lịch", slug="tourism-services", description="Companies providing travel and tourism services", description_vi="Các công ty cung cấp dịch vụ du lịch và nghỉ dưỡng" ) hotels = BusinessCategory.objects.create( name="Hotels & Accommodation", name_vi="Khách sạn & Chỗ ở", slug="hotels-accommodation", parent=tourism_services, description="Hotels, hostels, and accommodation providers" ) 🎨 Visual & Organization Fields icon = models.CharField(max_length=50, default='fas fa-building') parent = models.ForeignKey('self', on_delete=models.CASCADE, null=True, blank=True, related_name='subcategories') is_active = models.BooleanField(default=True) sort_order = models.PositiveIntegerField(default=0) Purpose: Visual presentation and hierarchical organization
Category Hierarchy Example: Tourism Services (fas fa-plane) ├── Hotels & Accommodation (fas fa-bed) │ ├── Luxury Hotels (fas fa-crown) │ ├── Budget Hotels (fas fa-wallet) │ └── Hostels (fas fa-users) ├── Restaurants (fas fa-utensils) │ ├── Vietnamese Cuisine (fas fa-leaf) │ ├── International Food (fas fa-globe) │ └── Street Food (fas fa-shopping-cart) └── Transportation (fas fa-car) ├── Car Rental (fas fa-car-side) ├── Motorbike Rental (fas fa-motorcycle) └── Tour Buses (fas fa-bus) 🌍 Translation Management System translation_status = models.CharField(max_length=20, choices=TRANSLATION_STATUS_CHOICES, default='pending') translated_by = models.CharField(max_length=100, blank=True, help_text="Name of translator") translated_at = models.DateTimeField(null=True, blank=True, help_text="When translation was completed") Translation Workflow:
Business Logic Methods: def get_display_name(self, language='en'): """Smart language switching""" if language == 'vi' and self.name_vi: return self.name_vi return self.name def get_business_count(self): """Get count of approved businesses in this category""" return self.businesses.filter(status='approved').count()
|
Listing Claim |
🏢 BusinessClaim Model - Ownership Verification 📋 Claim Process business = models.ForeignKey(BusinessListing, on_delete=models.CASCADE, related_name='claims') claimant = models.ForeignKey(User, on_delete=models.CASCADE, related_name='business_claims') claim_reason = models.TextField(help_text="Reason for claiming this business") verification_document = models.FileField(upload_to='claim_documents/', blank=True) status = models.CharField(max_length=20, choices=[...], default='pending') Ownership Verification:
Claim Workflow: def approve_claim(self, admin_user): """Approve business claim and transfer ownership""" if self.status == 'pending': # Transfer ownership old_owner = self.business.owner self.business.owner = self.claimant self.business.is_verified = True self.business.save()
# Update claim status self.status = 'approved' self.reviewed_at = timezone.now() self.save()
# Send notifications send_claim_approved_email(self.claimant, self.business) send_ownership_transferred_email(old_owner, self.business) # Template for claim submission <form method="post" enctype="multipart/form-data"> <h3>Claim Business Ownership</h3> <div class="form-group"> <label>Reason for Claim</label> <textarea name="claim_reason" required></textarea> </div> <div class="form-group"> <label>Verification Document</label> <input type="file" name="verification_document"> <small>Upload business license or registration document</small> </div> <button type="submit">Submit Claim</button> </form>
🎯 Real-World Integration Scenarios 🔍 Advanced Business Search def search_businesses(query, category=None, city=None, amenities=None): """Comprehensive business search with filters""" businesses = BusinessListing.objects.filter(status='approved')
# Text search if query: businesses = businesses.filter( Q(business_name__icontains=query) | Q(business_name_vi__icontains=query) | Q(description__icontains=query) | Q(description_vi__icontains=query) )
# Category filter if category: businesses = businesses.filter(category=category)
# Location filter if city: businesses = businesses.filter(city__icontains=city)
# Amenity filters if amenities: for amenity in amenities: if amenity == 'wifi': businesses = businesses.filter(wifi_available=True) elif amenity == 'parking': businesses = businesses.filter(parking_available=True) elif amenity == 'accessible': businesses = businesses.filter(wheelchair_accessible=True)
return businesses.select_related('category').prefetch_related('images', 'reviews') 📊 Business Dashboard Analytics def get_business_analytics(business): """Generate analytics for business owner dashboard""" return { 'total_views': business.views_count, 'phone_clicks': business.phone_clicks, 'website_clicks': business.website_clicks, 'average_rating': business.calculate_average_rating(), 'total_reviews': business.reviews.count(), 'verified_reviews': business.reviews.filter(is_verified=True).count(), 'subscription_status': business.is_subscription_active(), 'featured_until': business.featured_until, 'images_count': business.images.count(), 'max_images': business.max_photos_allowed(), 'monthly_views': get_monthly_views(business), 'competitor_comparison': get_competitor_metrics(business) } 🌟 Featured Business Rotation def get_featured_businesses_for_homepage(): """Get featured businesses with smart rotation""" # Get currently featured businesses featured = BusinessListing.objects.filter( status='approved', is_featured=True, subscription_type__in=['premium', 'featured'] ).select_related('category').prefetch_related('images')
# Apply smart rotation based on subscription level premium_businesses = featured.filter(subscription_type='premium') featured_businesses = featured.filter(subscription_type='featured')
# Feature rotation: 60% featured, 40% premium import random final_list = []
if featured_businesses.exists(): final_list.extend(random.sample(list(featured_businesses), min(6, len(featured_businesses))))
if premium_businesses.exists(): final_list.extend(random.sample(list(premium_businesses), min(4, len(premium_businesses))))
return final_list[:10] # Return top 10 for homepage
|
Listing Image |
📸 BusinessImage Model - Visual Content 🖼️ Image Management business = models.ForeignKey(BusinessListing, on_delete=models.CASCADE, related_name='images') image = models.ImageField(upload_to='business_images/') caption = models.CharField(max_length=200, blank=True) is_primary = models.BooleanField(default=False) sort_order = models.PositiveIntegerField(default=0) uploaded_at = models.DateTimeField(auto_now_add=True) Visual Presentation:
Image Management Logic: def set_as_primary(self): """Set this image as primary and unset others""" # First, unset all other primary images for this business BusinessImage.objects.filter( business=self.business, is_primary=True ).update(is_primary=False)
# Set this image as primary self.is_primary = True self.save() # Template usage {% for image in business.images.all %} <div class="gallery-item {% if image.is_primary %}primary{% endif %}"> <img src="{{ image.image.url }}" alt="{{ image.caption }}"> {% if image.caption %} <div class="caption">{{ image.caption }}</div> {% endif %} </div> {% endfor %}
|
Listing Review |
⭐ BusinessReview Model - Customer Feedback 📝 Review System business = models.ForeignKey(BusinessListing, on_delete=models.CASCADE, related_name='reviews') reviewer = models.ForeignKey(User, on_delete=models.CASCADE, related_name='business_reviews') rating = models.PositiveIntegerField(validators=[MinValueValidator(1), MaxValueValidator(5)]) title = models.CharField(max_length=200) review_text = models.TextField() is_verified = models.BooleanField(default=False) Review Features:
Review Analytics: def calculate_average_rating(self): """Calculate average rating for business""" reviews = self.reviews.all() if reviews: total_rating = sum(review.rating for review in reviews) return round(total_rating / len(reviews), 1) return 0 def get_rating_distribution(self): """Get distribution of ratings (1-5 stars)""" from django.db.models import Count return self.reviews.values('rating').annotate( count=Count('rating') ).order_by('rating') # Template display <div class="rating-summary"> <div class="average-rating"> {{ business.calculate_average_rating }} / 5 stars ({{ business.reviews.count }} review{{ business.reviews.count|pluralize }}) </div>
{% for rating_data in business.get_rating_distribution %} <div class="rating-bar"> {{ rating_data.rating }} stars: {{ rating_data.count }} review{{ rating_data.count|pluralize }} </div> {% endfor %} </div> 🔒 Review Integrity class Meta: unique_together = ['business', 'reviewer'] ordering = ['-created_at'] Anti-Spam Measures:
Verification Flag: Distinguishes verified customer reviews
|
Nhom |
Notes |
|
The Business Directory models provide a comprehensive foundation for managing travel-related businesses in Vietnam, with full multilingual support, subscription management, customer reviews, and business verification systems suitable for a professional travel platform .
|
|
I'll provide a comprehensive explanation of the Business Directory models and their fields, showing how they work together to create a complete business listing platform for the DichVuHowTo travel website. 🏢 Business Directory Models Overview The business directory system consists of four main models that work together to create a comprehensive business listing platform with multilingual support, reviews, and business verification.
|
|
|
Listing |
🏪 BusinessListing Model - Core Business Information 📋 Basic Business Information business_name = models.CharField(max_length=200) business_name_vi = models.CharField(max_length=200, blank=True, verbose_name="Vietnamese Business Name") slug = models.SlugField(max_length=200, unique=True) category = models.ForeignKey(BusinessCategory, on_delete=models.CASCADE, related_name='businesses') owner = models.ForeignKey(User, on_delete=models.CASCADE, related_name='businesses') Core Identity:
Example Usage: saigon_hotel = BusinessListing.objects.create( business_name="Saigon Grand Hotel", business_name_vi="Khách sạn Sài Gòn Grand", slug="saigon-grand-hotel", category=luxury_hotels_category, owner=hotel_manager_user ) 📝 Description Fields description = models.TextField() description_vi = models.TextField(blank=True, verbose_name="Vietnamese Description") short_description = models.CharField(max_length=300, help_text="Brief description for listings") short_description_vi = models.CharField(max_length=300, blank=True, verbose_name="Vietnamese Short Description") Content Strategy:
Template Usage: <!-- Listing card --> <div class="business-card"> <h3>{{ business.get_display_name:request.LANGUAGE_CODE }}</h3> <p>{{ business.get_display_short_description:request.LANGUAGE_CODE }}</p> </div> <!-- Detail page --> <div class="business-detail"> {{ business.get_display_description:request.LANGUAGE_CODE|safe }} </div> 📞 Contact Information phone = models.CharField(max_length=20) email = models.EmailField() website = models.URLField(blank=True) Customer Communication:
Template Implementation: <div class="contact-info"> <a href="tel:{{ business.phone }}" class="btn btn-primary"> <i class="fas fa-phone"></i> Call Now </a> <a href="mailto:{{ business.email }}" class="btn btn-secondary"> <i class="fas fa-envelope"></i> Email </a> {% if business.website %} <a href="{{ business.website }}" target="_blank" class="btn btn-info"> <i class="fas fa-globe"></i> Website </a> {% endif %} </div> 📍 Location & Mapping street_address = models.CharField(max_length=200) city = models.CharField(max_length=100) state = models.CharField(max_length=100) postal_code = models.CharField(max_length=20) country = models.CharField(max_length=100, default='Vietnam') latitude = models.DecimalField(max_digits=10, decimal_places=8, null=True, blank=True) longitude = models.DecimalField(max_digits=11, decimal_places=8, null=True, blank=True) Geographic Features:
Map Integration Example: def get_full_address(self): """Get formatted full address""" parts = [self.street_address, self.city, self.state, self.postal_code, self.country] return ', '.join(filter(None, parts)) # Template usage with Google Maps <div id="map" data-lat="{{ business.latitude }}" data-lng="{{ business.longitude }}"> <p>{{ business.get_full_address }}</p> </div> 🕒 Business Hours System monday_hours = models.CharField(max_length=50, blank=True, help_text="e.g., 9:00 AM - 5:00 PM") tuesday_hours = models.CharField(max_length=50, blank=True) wednesday_hours = models.CharField(max_length=50, blank=True) thursday_hours = models.CharField(max_length=50, blank=True) friday_hours = models.CharField(max_length=50, blank=True) saturday_hours = models.CharField(max_length=50, blank=True) sunday_hours = models.CharField(max_length=50, blank=True) Operating Hours Management:
Template Display: <div class="business-hours"> <h4>Business Hours</h4> <ul class="list-unstyled"> <li><strong>Monday:</strong> {{ business.monday_hours|default:"Closed" }}</li> <li><strong>Tuesday:</strong> {{ business.tuesday_hours|default:"Closed" }}</li> <!-- ... other days ... --> </ul> </div> 📱 Social Media Integration facebook_url = models.URLField(blank=True) twitter_url = models.URLField(blank=True) instagram_url = models.URLField(blank=True) linkedin_url = models.URLField(blank=True) Social Presence:
✨ Feature & Amenities Flags accepts_credit_cards = models.BooleanField(default=False) parking_available = models.BooleanField(default=False) wheelchair_accessible = models.BooleanField(default=False) wifi_available = models.BooleanField(default=False) outdoor_seating = models.BooleanField(default=False) delivery_available = models.BooleanField(default=False) Customer Decision Factors:
Filter & Search Integration: # Find restaurants with WiFi and outdoor seating restaurants_with_amenities = BusinessListing.objects.filter( category__slug='restaurants', wifi_available=True, outdoor_seating=True, status='approved' ) 💼 Subscription & Status Management SUBSCRIPTION_CHOICES = [ ('free', 'Free Listing'), ('basic', 'Basic Listing'), ('premium', 'Premium Listing'), ('featured', 'Featured Listing'), ] STATUS_CHOICES = [ ('draft', 'Draft'), ('pending', 'Pending Approval'), ('approved', 'Approved'), ('rejected', 'Rejected'), ('suspended', 'Suspended'), ] subscription_type = models.CharField(max_length=20, choices=SUBSCRIPTION_CHOICES, default='free') status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='draft') is_verified = models.BooleanField(default=False) is_featured = models.BooleanField(default=False) Business Monetization:
Business Logic: # Get featured businesses for homepage featured_businesses = BusinessListing.objects.filter( status='approved', is_featured=True, subscription_type__in=['premium', 'featured'] ).order_by('-created_at') # Subscription-based features def can_upload_multiple_photos(self): return self.subscription_type in ['premium', 'featured'] def max_photos_allowed(self): photo_limits = { 'free': 3, 'basic': 10, 'premium': 25, 'featured': 50 } return photo_limits.get(self.subscription_type, 3) 🔍 SEO & Marketing Fields meta_title = models.CharField(max_length=60, blank=True) meta_description = models.CharField(max_length=160, blank=True) keywords = models.CharField(max_length=200, blank=True, help_text="Comma-separated keywords") Search Engine Optimization:
Template SEO Integration: <head> <title>{{ business.meta_title|default:business.business_name }} - DichVuHowTo</title> <meta name="description" content="{{ business.meta_description|default:business.short_description }}"> <meta name="keywords" content="{{ business.keywords }}"> </head> 📊 Analytics & Performance Tracking views_count = models.PositiveIntegerField(default=0) phone_clicks = models.PositiveIntegerField(default=0) website_clicks = models.PositiveIntegerField(default=0) Business Intelligence:
Analytics Implementation: def increment_views(self): """Increment view counter""" self.views_count += 1 self.save(update_fields=['views_count']) def track_phone_click(self): """Track phone number clicks""" self.phone_clicks += 1 self.save(update_fields=['phone_clicks']) # In views def business_detail(request, slug): business = get_object_or_404(BusinessListing, slug=slug) business.increment_views() # Track page view return render(request, 'business_detail.html', {'business': business}) ⏰ Subscription Management created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) featured_until = models.DateTimeField(null=True, blank=True) subscription_expires = models.DateTimeField(null=True, blank=True) Temporal Business Logic:
Subscription Management: from django.utils import timezone def is_subscription_active(self): """Check if subscription is still active""" if not self.subscription_expires: return True # Lifetime subscription return timezone.now() < self.subscription_expires def is_currently_featured(self): """Check if business is currently featured""" if not self.is_featured or not self.featured_until: return self.is_featured return timezone.now() < self.featured_until # Automated tasks def expire_featured_listings(): """Celery task to expire featured listings""" expired_listings = BusinessListing.objects.filter( is_featured=True, featured_until__lt=timezone.now() ) expired_listings.update(is_featured=False)
|
Listing Category |
📂 BusinessCategory Model - Hierarchical Organization 🔤 Basic Information Fields name = models.CharField(max_length=100, unique=True) name_vi = models.CharField(max_length=100, blank=True, verbose_name="Vietnamese Name") slug = models.SlugField(max_length=100, unique=True) description = models.TextField(blank=True) description_vi = models.TextField(blank=True, verbose_name="Vietnamese Description") Purpose: Creates bilingual category structure for business organization
Real-World Examples: # Tourism category structure tourism_services = BusinessCategory.objects.create( name="Tourism Services", name_vi="Dịch vụ du lịch", slug="tourism-services", description="Companies providing travel and tourism services", description_vi="Các công ty cung cấp dịch vụ du lịch và nghỉ dưỡng" ) hotels = BusinessCategory.objects.create( name="Hotels & Accommodation", name_vi="Khách sạn & Chỗ ở", slug="hotels-accommodation", parent=tourism_services, description="Hotels, hostels, and accommodation providers" ) 🎨 Visual & Organization Fields icon = models.CharField(max_length=50, default='fas fa-building') parent = models.ForeignKey('self', on_delete=models.CASCADE, null=True, blank=True, related_name='subcategories') is_active = models.BooleanField(default=True) sort_order = models.PositiveIntegerField(default=0) Purpose: Visual presentation and hierarchical organization
Category Hierarchy Example: Tourism Services (fas fa-plane) ├── Hotels & Accommodation (fas fa-bed) │ ├── Luxury Hotels (fas fa-crown) │ ├── Budget Hotels (fas fa-wallet) │ └── Hostels (fas fa-users) ├── Restaurants (fas fa-utensils) │ ├── Vietnamese Cuisine (fas fa-leaf) │ ├── International Food (fas fa-globe) │ └── Street Food (fas fa-shopping-cart) └── Transportation (fas fa-car) ├── Car Rental (fas fa-car-side) ├── Motorbike Rental (fas fa-motorcycle) └── Tour Buses (fas fa-bus) 🌍 Translation Management System translation_status = models.CharField(max_length=20, choices=TRANSLATION_STATUS_CHOICES, default='pending') translated_by = models.CharField(max_length=100, blank=True, help_text="Name of translator") translated_at = models.DateTimeField(null=True, blank=True, help_text="When translation was completed") Translation Workflow:
Business Logic Methods: def get_display_name(self, language='en'): """Smart language switching""" if language == 'vi' and self.name_vi: return self.name_vi return self.name def get_business_count(self): """Get count of approved businesses in this category""" return self.businesses.filter(status='approved').count()
|
Listing Claim |
🏢 BusinessClaim Model - Ownership Verification 📋 Claim Process business = models.ForeignKey(BusinessListing, on_delete=models.CASCADE, related_name='claims') claimant = models.ForeignKey(User, on_delete=models.CASCADE, related_name='business_claims') claim_reason = models.TextField(help_text="Reason for claiming this business") verification_document = models.FileField(upload_to='claim_documents/', blank=True) status = models.CharField(max_length=20, choices=[...], default='pending') Ownership Verification:
Claim Workflow: def approve_claim(self, admin_user): """Approve business claim and transfer ownership""" if self.status == 'pending': # Transfer ownership old_owner = self.business.owner self.business.owner = self.claimant self.business.is_verified = True self.business.save()
# Update claim status self.status = 'approved' self.reviewed_at = timezone.now() self.save()
# Send notifications send_claim_approved_email(self.claimant, self.business) send_ownership_transferred_email(old_owner, self.business) # Template for claim submission <form method="post" enctype="multipart/form-data"> <h3>Claim Business Ownership</h3> <div class="form-group"> <label>Reason for Claim</label> <textarea name="claim_reason" required></textarea> </div> <div class="form-group"> <label>Verification Document</label> <input type="file" name="verification_document"> <small>Upload business license or registration document</small> </div> <button type="submit">Submit Claim</button> </form>
🎯 Real-World Integration Scenarios 🔍 Advanced Business Search def search_businesses(query, category=None, city=None, amenities=None): """Comprehensive business search with filters""" businesses = BusinessListing.objects.filter(status='approved')
# Text search if query: businesses = businesses.filter( Q(business_name__icontains=query) | Q(business_name_vi__icontains=query) | Q(description__icontains=query) | Q(description_vi__icontains=query) )
# Category filter if category: businesses = businesses.filter(category=category)
# Location filter if city: businesses = businesses.filter(city__icontains=city)
# Amenity filters if amenities: for amenity in amenities: if amenity == 'wifi': businesses = businesses.filter(wifi_available=True) elif amenity == 'parking': businesses = businesses.filter(parking_available=True) elif amenity == 'accessible': businesses = businesses.filter(wheelchair_accessible=True)
return businesses.select_related('category').prefetch_related('images', 'reviews') 📊 Business Dashboard Analytics def get_business_analytics(business): """Generate analytics for business owner dashboard""" return { 'total_views': business.views_count, 'phone_clicks': business.phone_clicks, 'website_clicks': business.website_clicks, 'average_rating': business.calculate_average_rating(), 'total_reviews': business.reviews.count(), 'verified_reviews': business.reviews.filter(is_verified=True).count(), 'subscription_status': business.is_subscription_active(), 'featured_until': business.featured_until, 'images_count': business.images.count(), 'max_images': business.max_photos_allowed(), 'monthly_views': get_monthly_views(business), 'competitor_comparison': get_competitor_metrics(business) } 🌟 Featured Business Rotation def get_featured_businesses_for_homepage(): """Get featured businesses with smart rotation""" # Get currently featured businesses featured = BusinessListing.objects.filter( status='approved', is_featured=True, subscription_type__in=['premium', 'featured'] ).select_related('category').prefetch_related('images')
# Apply smart rotation based on subscription level premium_businesses = featured.filter(subscription_type='premium') featured_businesses = featured.filter(subscription_type='featured')
# Feature rotation: 60% featured, 40% premium import random final_list = []
if featured_businesses.exists(): final_list.extend(random.sample(list(featured_businesses), min(6, len(featured_businesses))))
if premium_businesses.exists(): final_list.extend(random.sample(list(premium_businesses), min(4, len(premium_businesses))))
return final_list[:10] # Return top 10 for homepage
|
Listing Image |
📸 BusinessImage Model - Visual Content 🖼️ Image Management business = models.ForeignKey(BusinessListing, on_delete=models.CASCADE, related_name='images') image = models.ImageField(upload_to='business_images/') caption = models.CharField(max_length=200, blank=True) is_primary = models.BooleanField(default=False) sort_order = models.PositiveIntegerField(default=0) uploaded_at = models.DateTimeField(auto_now_add=True) Visual Presentation:
Image Management Logic: def set_as_primary(self): """Set this image as primary and unset others""" # First, unset all other primary images for this business BusinessImage.objects.filter( business=self.business, is_primary=True ).update(is_primary=False)
# Set this image as primary self.is_primary = True self.save() # Template usage {% for image in business.images.all %} <div class="gallery-item {% if image.is_primary %}primary{% endif %}"> <img src="{{ image.image.url }}" alt="{{ image.caption }}"> {% if image.caption %} <div class="caption">{{ image.caption }}</div> {% endif %} </div> {% endfor %}
|
Listing Review |
⭐ BusinessReview Model - Customer Feedback 📝 Review System business = models.ForeignKey(BusinessListing, on_delete=models.CASCADE, related_name='reviews') reviewer = models.ForeignKey(User, on_delete=models.CASCADE, related_name='business_reviews') rating = models.PositiveIntegerField(validators=[MinValueValidator(1), MaxValueValidator(5)]) title = models.CharField(max_length=200) review_text = models.TextField() is_verified = models.BooleanField(default=False) Review Features:
Review Analytics: def calculate_average_rating(self): """Calculate average rating for business""" reviews = self.reviews.all() if reviews: total_rating = sum(review.rating for review in reviews) return round(total_rating / len(reviews), 1) return 0 def get_rating_distribution(self): """Get distribution of ratings (1-5 stars)""" from django.db.models import Count return self.reviews.values('rating').annotate( count=Count('rating') ).order_by('rating') # Template display <div class="rating-summary"> <div class="average-rating"> {{ business.calculate_average_rating }} / 5 stars ({{ business.reviews.count }} review{{ business.reviews.count|pluralize }}) </div>
{% for rating_data in business.get_rating_distribution %} <div class="rating-bar"> {{ rating_data.rating }} stars: {{ rating_data.count }} review{{ rating_data.count|pluralize }} </div> {% endfor %} </div> 🔒 Review Integrity class Meta: unique_together = ['business', 'reviewer'] ordering = ['-created_at'] Anti-Spam Measures:
Verification Flag: Distinguishes verified customer reviews
|
Attached Files
You are viewing this article in public mode. Some features may be limited.