You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django适配Heroku:将用户头像存Firebase,URL存入SQLite

Hey there! Let's get that avatar upload working on Heroku by switching to Firebase Storage—since Heroku's ephemeral filesystem can't handle dynamic file storage long-term. Here's a step-by-step solution tailored to your existing Django code:

1. Install Required Packages

First, add these packages to your requirements.txt and install them locally:

firebase-admin>=6.2.0
python-dotenv>=1.0.0

Run pip install -r requirements.txt to get them set up.

2. Set Up Firebase Storage

  • Create a Firebase project (if you don't have one already) and enable Cloud Storage in the Firebase console.
  • Go to Project Settings > Service Accounts and download the JSON key file for your service account.
  • For security, store this key's content as an environment variable (instead of committing the file to version control). Use a .env file locally, and on Heroku, set it via the CLI.

3. Configure Firebase in Django

Add this configuration to your settings.py (or create a separate firebase_config.py and import it):

import firebase_admin
from firebase_admin import credentials, storage
import os
import json

# Load Firebase credentials from environment variable
service_account = json.loads(os.environ.get("FIREBASE_SERVICE_ACCOUNT"))
cred = credentials.Certificate(service_account)

# Initialize Firebase app with storage bucket
firebase_admin.initialize_app(cred, {
    "storageBucket": "your-firebase-bucket-name.appspot.com"  # Replace with your actual bucket URL
})
  • Replace your-firebase-bucket-name.appspot.com with the URL found in your Firebase Storage console.

4. Update Your Profile Model

We'll store a Firebase URL instead of a local file, so modify your models.py:

from django.db import models
from django.contrib.auth.models import User
from datetime import date

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    birth_date = models.DateField('Fecha de nacimiento', default=date.today)
    # Replace ImageField with URLField
    photo = models.URLField(
        'Foto de perfil', 
        default='https://storage.googleapis.com/your-bucket-name/default.png'  # Replace with your default avatar's Firebase URL
    )
  • Upload your default.png to Firebase Storage first, then paste its public URL as the default value.

5. Adjust the Profile Form

Keep the ImageField to let users upload files, but we'll handle the Firebase upload in the view:

# forms.py
from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserChangeForm
from .models import Profile
from django.forms.widgets import DatePickerInput

class UEditF(UserChangeForm):
    class Meta:
        model = User
        fields = ['first_name', 'last_name']

class ProfileForm(forms.ModelForm):
    birth_date = forms.DateField(widget=DatePickerInput(format='%d/%m/%Y'), label='Fecha de nacimiento')
    # Keep ImageField for file upload, make it optional to skip avatar updates
    photo = forms.ImageField(label="Foto de perfil", required=False)

    class Meta:
        model = Profile
        fields = ['birth_date', 'photo']

6. Modify the Edit Profile View

Update your views.py to handle uploading avatars to Firebase and saving the URL to the database:

from django.shortcuts import render, redirect
from .forms import UEditF, ProfileForm
from firebase_admin import storage
import time

def upload_to_firebase(file, user_id):
    """Helper function to upload file to Firebase and return its public URL"""
    bucket = storage.bucket()
    # Generate a unique filename to avoid overwriting existing avatars
    filename = f"avatars/user_{user_id}_{int(time.time())}_{file.name}"
    blob = bucket.blob(filename)
    
    # Upload file with correct content type
    blob.upload_from_file(file, content_type=file.content_type)
    # Make the file publicly accessible
    blob.make_public()
    
    return blob.public_url

def edit_profile(request):
    if request.method == 'POST':
        form = UEditF(request.POST, instance=request.user)
        extended_profile_form = ProfileForm(request.POST, request.FILES, instance=request.user.profile)
        
        if form.is_valid() and extended_profile_form.is_valid():
            form.save()
            
            # Handle avatar upload logic
            profile = extended_profile_form.save(commit=False)
            if request.FILES.get('photo'):
                uploaded_file = request.FILES['photo']
                profile.photo = upload_to_firebase(uploaded_file, request.user.id)
            profile.save()
            
            return redirect('/polls/perfil')
    else:
        form = UEditF(instance=request.user)
        extended_profile_form = ProfileForm(instance=request.user.profile)
    
    context = { 'form': form, 'extended_profile_form':extended_profile_form }
    form.fields['password'].help_text = 'Para cambiar la contraseña has clic en el menú superior derecho "Cambiar contraseña"'
    return render(request, 'registration/edit_profile.html', context)

7. Update Your Template

Make sure your template uses the stored URL directly instead of a local file path. For example, in your profile display template:

<!-- Replace {{ user.profile.photo.url }} with {{ user.profile.photo }} -->
<img src="{{ user.profile.photo }}" alt="Foto de perfil" class="avatar">

8. Deploy to Heroku

  • Push your code changes to Heroku.
  • Set the required environment variables via Heroku CLI:
    # Replace the JSON string with your service account key content
    heroku config:set FIREBASE_SERVICE_ACCOUNT='{"type": "service_account", "project_id": "...", ...}'
    heroku config:set DJANGO_SETTINGS_MODULE=your_project.settings
    
  • Run migrations on Heroku:
    heroku run python manage.py migrate
    

Quick Notes

  • Ensure your Firebase Storage bucket has public read access (adjust this in the Firebase Storage rules if needed).
  • Add error handling in the upload_to_firebase function (e.g., try-except blocks) to catch upload failures and inform the user.

内容的提问来源于stack exchange,提问作者Katherine Zambrano

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 12:47:27