Python/Django新手:使用Twilio存储短信回复号码至数据库遇报错
Hey there! Let's break this down step by step since you're new to Django and Twilio—no worries, we'll get this sorted out.
First, let's tackle that TypeError: 'type' object is not iterable error, then walk through how to properly store subscription numbers in your database based on user responses.
Fixing the "TypeError: 'type' object is not iterable"
This error almost always happens when you're trying to loop over or iterate a class itself instead of an instance/queryset of that class. For example:
- If you wrote
for number in Subscription(referencing the model class) instead offor number in Subscription.objects.all()(referencing a queryset of actual records) - Or if you accidentally passed a model class (like
User) instead of a value (like a phone number string) when creating a database entry
Double-check your code for these common mistakes—we'll make sure our solution below avoids this entirely.
Step 1: Create a Subscription Model
First, define a Django model to store user subscription data. This will track phone numbers, their chosen subscription type, and status.
In your app's models.py:
from django.db import models class Subscription(models.Model): # Define possible subscription options (customize these to fit your campaigns) SUBSCRIPTION_TYPES = [ ('GENERAL', 'General Promotions'), ('EXCLUSIVE', 'Exclusive Offers'), ('NEWS', 'Product Updates'), ] phone_number = models.CharField(max_length=20, unique=True) # Twilio uses E.164 format (+1234567890) subscription_type = models.CharField(max_length=20, choices=SUBSCRIPTION_TYPES) is_active = models.BooleanField(default=True) created_at = models.DateTimeField(auto_now_add=True) def __str__(self): return f"{self.phone_number} - {self.get_subscription_type_display()}"
Run migrations to create the table in your database:
python manage.py makemigrations python manage.py migrate
Step 2: Handle Incoming SMS & Store Subscriptions
Use django_twilio's decorator to create a view that processes incoming Twilio SMS, parses the user's subscription request, and saves the data to your database.
In your app's views.py:
from django.http import HttpResponse from twilio.twiml.messaging_response import MessagingResponse from django_twilio.decorators import twilio_view from .models import Subscription @twilio_view def handle_incoming_sms(request): # Extract data from Twilio's incoming request sender_number = request.POST.get('From') # This is the user's phone number (E.164 format) message_content = request.POST.get('Body', '').strip().upper() # Initialize Twilio's response object twilio_resp = MessagingResponse() # Map user messages to subscription types subscription_map = { 'SUBSCRIBE': 'GENERAL', 'EXCLUSIVE': 'EXCLUSIVE', 'NEWS': 'NEWS' } # Validate the user's request if message_content not in subscription_map: twilio_resp.message("Sorry, we didn't catch that! Reply SUBSCRIBE, EXCLUSIVE, or NEWS to join our lists.") return HttpResponse(str(twilio_resp)) # Get the chosen subscription type selected_type = subscription_map[message_content] # Save or update the subscription in the database try: # Use get_or_create to avoid duplicate entries subscription, was_created = Subscription.objects.get_or_create( phone_number=sender_number, defaults={'subscription_type': selected_type} ) # If the user already subscribed, update their preference if not was_created: subscription.subscription_type = selected_type subscription.is_active = True subscription.save() twilio_resp.message(f"Updated your subscription to {selected_type.lower()} offers!") else: twilio_resp.message(f"Thanks for joining our {selected_type.lower()} list!") except Exception as e: twilio_resp.message("Oops, something went wrong. Please try again later.") # Log the error for debugging (you can use Django's logging framework here) print(f"Error saving subscription: {str(e)}") return HttpResponse(str(twilio_resp))
Step 3: Configure the URL Route
Add a URL path so Twilio can send incoming SMS to your view.
In your project's urls.py:
from django.urls import path from your_app_name import views urlpatterns = [ # ... other URLs path('sms/incoming/', views.handle_incoming_sms, name='handle_incoming_sms'), ]
Final Setup Tips
- Twilio Webhook Configuration: Go to your Twilio dashboard, select your phone number, and set the "A Message Comes In" webhook URL to your Django app's
/sms/incoming/endpoint. If you're developing locally, use a tool like ngrok to expose your server to the internet. - Phone Number Validation: For extra robustness, add validation to ensure
sender_numberis in a valid E.164 format (Twilio sends numbers this way by default, but it's good to double-check). - Error Logging: Replace the
print()statement with Django's built-in logging to track errors more effectively in production.
内容的提问来源于stack exchange,提问作者Ach1916

