如何在Django 2中实现类似Instagram的多账号登录注册功能?
Hey there! Let's walk through the best way to build Instagram-style login and registration in Django 2. I’ve built similar flows before, so this approach is clean, maintainable, and aligns exactly with your requirements.
Django’s default User model is missing two critical pieces for your use case: a phone number field and enforced uniqueness for emails. We’ll extend AbstractUser to fix this—this keeps all the built-in auth functionality while adding our custom fields.
# accounts/models.py from django.contrib.auth.models import AbstractUser from django.db import models from django.core.validators import RegexValidator class CustomUser(AbstractUser): # Add phone number with regex validation to ensure valid formatting phone_regex = RegexValidator( regex=r'^\+?1?\d{9,15}$', message="Phone number must be entered like '+999999999' (up to 15 digits)." ) phone_number = models.CharField( validators=[phone_regex], max_length=17, blank=True, unique=True, help_text="Optional. Enter a valid phone number." ) # Make email unique (Django's default allows duplicate emails) email = models.EmailField(unique=True, blank=False) # Required settings for custom user models USERNAME_FIELD = 'username' REQUIRED_FIELDS = ['email'] # Ensure email is mandatory for registration def __str__(self): return self.username
Don’t forget to tell Django to use this custom model in your settings.py:
# settings.py AUTH_USER_MODEL = 'accounts.CustomUser'
Next, we need a form that lets users sign up with either (username + email + password) or (username + phone + password) (or both, if you want). We’ll extend Django’s UserCreationForm to add the phone number field and add validation to ensure at least one contact method (email/phone) is provided, and that no duplicates exist.
# accounts/forms.py from django.contrib.auth.forms import UserCreationForm from .models import CustomUser from django import forms class CustomUserCreationForm(UserCreationForm): phone_number = forms.CharField(required=False, help_text="Optional. Enter a valid phone number.") class Meta: model = CustomUser fields = ('username', 'email', 'phone_number', 'password1', 'password2') def clean(self): cleaned_data = super().clean() email = cleaned_data.get('email') phone_number = cleaned_data.get('phone_number') # Make sure user provides at least one contact method if not email and not phone_number: raise forms.ValidationError("You need to enter either an email address or a phone number.") # Check if phone number is already taken (if provided) if phone_number and CustomUser.objects.filter(phone_number=phone_number).exists(): raise forms.ValidationError("This phone number is already registered to another account.") return cleaned_data
Django’s default login only uses usernames. To let users log in with username, email, OR phone number, we need a custom auth backend that checks all three fields against the login input.
# accounts/backends.py from django.contrib.auth.backends import ModelBackend from django.contrib.auth import get_user_model from django.db.models import Q class CustomAuthBackend(ModelBackend): def authenticate(self, request, username=None, password=None, **kwargs): UserModel = get_user_model() try: # Look up user by username, email, OR phone number user = UserModel.objects.get( Q(username=username) | Q(email=username) | Q(phone_number=username) ) except UserModel.DoesNotExist: # No user found with any of these fields return None except UserModel.MultipleObjectsReturned: # Safeguard in case of duplicates (our model prevents this, but better safe than sorry) user = UserModel.objects.filter( Q(username=username) | Q(email=username) | Q(phone_number=username) ).first() # Verify the password is correct if user.check_password(password): return user return None def get_user(self, user_id): UserModel = get_user_model() try: return UserModel.objects.get(pk=user_id) except UserModel.DoesNotExist: return None
Add this backend to your settings.py so Django uses it:
# settings.py AUTHENTICATION_BACKENDS = [ 'accounts.backends.CustomAuthBackend', 'django.contrib.auth.backends.ModelBackend', # Keep default as fallback ]
We’ll use Django’s built-in class-based views for registration and login—they’re clean and require minimal code.
# accounts/views.py from django.views.generic.edit import CreateView from django.contrib.auth.views import LoginView from django.urls import reverse_lazy from .forms import CustomUserCreationForm class RegisterView(CreateView): form_class = CustomUserCreationForm success_url = reverse_lazy('login') # Redirect to login after successful registration template_name = 'accounts/register.html' class CustomLoginView(LoginView): template_name = 'accounts/login.html' redirect_authenticated_user = True # Redirect logged-in users away from login page
Now wire up the URLs:
# accounts/urls.py from django.urls import path from .views import RegisterView, CustomLoginView urlpatterns = [ path('register/', RegisterView.as_view(), name='register'), path('login/', CustomLoginView.as_view(), name='login'), ]
Include these in your project’s main urls.py:
# project/urls.py from django.contrib import admin from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), path('accounts/', include('accounts.urls')), ]
Here are simple templates to get you started—you’ll want to style them to match Instagram’s look, but this covers the functionality.
Register Template (templates/accounts/register.html)
<!DOCTYPE html> <html> <head> <title>Sign Up</title> </head> <body> <h2>Create Your Account</h2> <form method="post"> {% csrf_token %} {{ form.as_p }} <button type="submit">Sign Up</button> </form> <p>Already have an account? <a href="{% url 'login' %}">Log In</a></p> </body> </html>
Login Template (templates/accounts/login.html)
<!DOCTYPE html> <html> <head> <title>Log In</title> </head> <body> <h2>Log In</h2> <form method="post"> {% csrf_token %} {{ form.as_p }} <button type="submit">Log In</button> </form> <p>Don't have an account? <a href="{% url 'register' %}">Sign Up</a></p> </body> </html>
- Email/Phone Verification: Instagram requires users to verify their email—you can add this with custom logic or packages like
django-allauth. For phone verification, services like Twilio work great. - Password Reset: Extend Django’s default password reset to support both email and phone number (if needed).
- Form Styling: Ditch the default
form.as_pand add CSS to make your forms look clean and modern (like Instagram’s minimal design). - Friendly Error Messages: Customize form error messages to be more user-friendly (e.g., "This email is already in use" instead of generic validation text).
内容的提问来源于stack exchange,提问作者Lakshitha Kumara

