能否在Django中创建以REST API为数据源的外键模型字段?
Absolutely, there are a few solid, beginner-friendly approaches to solve this problem—perfect for learning how to integrate independent Django services. Let’s break down the most practical methods based on your needs:
Method 1: Load Dropdown Options via Frontend AJAX (Real-Time Data)
This approach pulls the latest currency data directly from the first project's API when the user loads the form, great if the currency list changes frequently.
Step 1: Update the JournalEntry Model
Since you can't use a ForeignKey across separate databases, store the currency code as a CharField:
# Second project's models.py from django.db import models class JournalEntry(models.Model): date = models.DateField() # Store the 3-letter currency code (e.g., "DKK", "GBP") currency = models.CharField(max_length=3) value = models.IntegerField()
Step 2: Render the Form and Populate with JavaScript
Create a template that renders an empty dropdown, then use fetch() to pull data from the API and populate it:
<!-- Second project's template: journalentry_form.html --> <form method="post"> {% csrf_token %} {{ form.as_p }} <!-- Custom currency dropdown --> <label for="id_currency">Currency:</label> <select id="id_currency" name="currency" required> <option value="">Select a currency</option> </select> <button type="submit">Save Entry</button> </form> <script> // Fetch currency data from the first project's API fetch('http://your-first-project-domain/currencies/') .then(response => response.json()) .then(data => { const selectElement = document.getElementById('id_currency'); data.forEach(currency => { const option = document.createElement('option'); option.value = currency.code; option.textContent = `${currency.name} (${currency.code})`; selectElement.appendChild(option); }); }) .catch(error => console.error('Failed to load currencies:', error)); </script>
Step 3: Fix Cross-Origin Requests (CORS)
The first project needs to allow the second project to access its API. Install django-cors-headers in the first project:
pip install django-cors-headers
Then update its settings.py:
# First project's settings.py INSTALLED_APPS = [ # ... other apps 'corsheaders', ] MIDDLEWARE = [ # ... other middleware 'corsheaders.middleware.CorsMiddleware', 'django.middleware.common.CommonMiddleware', ] # Allow your second project's domain (use "*" for development only) CORS_ALLOWED_ORIGINS = [ "http://your-second-project-domain:8000", ]
Method 2: Populate Dropdown via Backend API Call (Server-Side Control)
If you need server-side validation or want to handle API errors gracefully, pull the currency data when initializing the form in the backend.
Step 1: Model Setup
Same as Method 1—use a CharField for currency.
Step 2: Create a Custom Form
Use requests to fetch data from the API and populate the dropdown choices when the form loads:
# Second project's forms.py from django import forms import requests from .models import JournalEntry class JournalEntryForm(forms.ModelForm): currency = forms.ChoiceField(choices=[], required=True) class Meta: model = JournalEntry fields = ['date', 'currency', 'value'] def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # Fetch currency data from the external API try: response = requests.get('http://your-first-project-domain/currencies/') response.raise_for_status() # Raise error for bad HTTP status codes currencies = response.json() # Convert API data to Django choice format: (value, display_text) self.fields['currency'].choices = [ (curr['code'], f"{curr['name']} ({curr['code']})") for curr in currencies ] # Set initial value if editing an existing entry if self.instance.pk: self.fields['currency'].initial = self.instance.currency except requests.exceptions.RequestException as e: # Fallback if API is down self.fields['currency'].choices = [('', 'Could not load currencies')]
Step 3: Use the Form in Your View
# Second project's views.py from django.shortcuts import render, redirect from .forms import JournalEntryForm def create_journal_entry(request): if request.method == 'POST': form = JournalEntryForm(request.POST) if form.is_valid(): form.save() return redirect('journalentry_list') # Redirect to your list view else: form = JournalEntryForm() return render(request, 'journalentry_form.html', {'form': form})
Your template can just use {{ form.as_p }}—the dropdown will be pre-populated with data from the API.
Method 3: Sync API Data to Local Database (Offline Access)
If you need to query currency data locally or work offline, sync the API data to a local model in the second project.
Step 1: Create Local Models
# Second project's models.py from django.db import models class LocalCurrency(models.Model): name = models.CharField(max_length=50) code = models.CharField(max_length=3, unique=True) def __str__(self): return f"{self.name} ({self.code})" class JournalEntry(models.Model): date = models.DateField() # Now you can use a ForeignKey to the local currency model currency = models.ForeignKey(LocalCurrency, on_delete=models.PROTECT) value = models.IntegerField()
Step 2: Create a Sync Command
Make a Django management command to pull data from the API and update your local database:
# Second project: management/commands/sync_currencies.py import requests from django.core.management.base import BaseCommand from your_app_name.models import LocalCurrency class Command(BaseCommand): help = 'Sync currencies from the external Django API' def handle(self, *args, **options): try: response = requests.get('http://your-first-project-domain/currencies/') response.raise_for_status() currencies = response.json() # Update or create local currency records for curr in currencies: LocalCurrency.objects.update_or_create( code=curr['code'], defaults={'name': curr['name']} ) self.stdout.write(self.style.SUCCESS('Successfully synced currencies!')) except requests.exceptions.RequestException as e: self.stdout.write(self.style.ERROR(f'Sync failed: {str(e)}'))
Step 3: Run the Sync
Execute the command to populate your local currency table:
python manage.py sync_currencies
For regular updates, set up a cron job or use a task manager like Celery to run this command automatically.
Now your JournalEntry form will automatically render a dropdown from the LocalCurrency model—no extra frontend or backend work needed!
Which Method Should You Choose?
- Method 1: Best for real-time data updates, frontend-focused.
- Method 2: Ideal if you need server-side validation or error handling.
- Method 3: Great for offline access or when you need to query currency data locally.
内容的提问来源于stack exchange,提问作者Solomon

