Building Custom User Profiles in Django: Image Upload Guide
Written on
Chapter 1: Introduction to Extending Django User Models
In Django, there are two primary methods to enhance the user model. The first method utilizes the AbstractUser class, while the second involves establishing a separate model that maintains a one-to-one association with the Django user model. This guide will concentrate on the latter approach, along with the process of enabling image uploads.
Section 1.1: Setting Up Your Django Environment
To get started, you’ll need to install some essential packages. Use the following commands:
pip install Django
pip install psycopg[binary]
pip install Pillow
Next, initiate your Django project with:
django-admin startproject auth_project .
django-admin startapp chicken
Section 1.2: Registering the Application
Before proceeding, it's crucial to register your newly created app. Modify your settings.py file to include the app in the INSTALLED_APPS list:
INSTALLED_APPS = [
'chicken.apps.ChickenConfig',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
Section 1.3: Configuring the Database
This tutorial will utilize a local PostgreSQL instance. Below is the configuration for your settings.py:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'PASSWORD': '123456',
'NAME': 'django-auth',
'HOST': '127.0.0.1',
'PORT': '5432',
'USER': 'postgres',
}
}
Chapter 2: Creating a Custom User Profile
To create a one-to-one relationship with the Django user model, we will add fields such as date_of_birth and photo to our profile.
from django.db import models
from django.conf import settings
class Profile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
date_of_birth = models.DateField(blank=True, null=True)
photo = models.ImageField(upload_to="users/%Y/%m/%d/", blank=True)
def __str__(self):
return f"Profile of {self.user.username}"
Section 2.1: Integrating with Django Admin
To manage the profile model via the Django admin interface, you'll need to add it to admin.py:
from django.contrib import admin
from .models import Profile
@admin.register(Profile)
class ProfileAdmin(admin.ModelAdmin):
list_display = ["user", "date_of_birth", "photo"]
raw_id_fields = ["user"]
Section 2.2: Running Migrations
Next, execute the following commands to apply your changes:
python manage.py makemigrations
python manage.py migrate
Section 2.3: Creating a Superuser
To access the Django admin, you'll need to create an admin account:
python manage.py createsuperuser
Chapter 3: Developing User Profiles
To display a list of users along with their profiles, use the following code:
from django.contrib.auth.models import User
from django.shortcuts import render
def user_list(request):
users = User.objects.select_related('profile').all()
return render(request, 'user_list.html', {"users": users})
Section 3.1: Crafting the Profile Form
A profile form will enable users to update their date of birth and profile picture:
from django import forms
from .models import Profile
class ProfileEditForm(forms.ModelForm):
class Meta:
model = Profile
fields = ["date_of_birth", "photo"]
widgets = {
"date_of_birth": forms.DateInput(attrs={"class": "form-control"}),}
Section 3.2: Implementing User Detail View
To retrieve the user's profile manually, use the following function:
from django.shortcuts import get_object_or_404
def user_detail(request, id):
user = get_object_or_404(User.objects.select_related('profile'), id=id)
if request.method == 'POST':
profile_form = ProfileEditForm(
instance=user.profile,
data=request.POST,
files=request.FILES)
if profile_form.is_valid():
profile_form.save()else:
profile_form = ProfileEditForm(instance=user.profile)
return render(request, 'user_detail.html', {"profile_form": profile_form})
Section 3.3: Configuring URLs
Don’t forget to register your URLs in the urls.py file of your app:
from django.urls import path
from . import views
app_name = "chicken"
urlpatterns = [
path("", views.user_list, name="user_list"),
path("<int:id>/", views.user_detail, name="user_detail"),
]
Next, link these URLs in your main project’s urls.py:
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('users/', include('chicken.urls', namespace='chicken')),
]
Chapter 4: Handling Media Files
For image uploads, ensure that Django can manage media files by adding the following to settings.py:
MEDIA_URL = "media/"
MEDIA_ROOT = BASE_DIR / "media"
Also, adjust your main urls.py to serve media files during development:
from django.conf import settings
from django.conf.urls.static import static
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
Chapter 5: Building HTML Templates
Your base.html file should include Bootstrap and set up the basic layout:
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Users Example</title>
<link rel="stylesheet" href="{% static 'path/to/bootstrap.css' %}">
</head>
<body>
{% block content %}
{% endblock %}
</body>
</html>
Next, create user_detail.html to extend base.html:
{% extends "base.html" %}
{% block content %}
<h1>User Detail</h1>
<form method="POST" enctype="multipart/form-data">
{{ profile_form.as_p }}
{% csrf_token %}
<button type="submit">Submit</button>
</form>
<a href="{% url 'chicken:user_list' %}">Back</a>
{% endblock %}
And user_list.html to show a list of users:
{% extends "base.html" %}
{% block content %}
<h1>Users</h1>
<ul>
{% for user in users %}
<li>{{ user.username }} - <a href="{% url 'chicken:user_detail' user.id %}">Edit</a></li>{% endfor %}
</ul>
{% endblock %}
Chapter 6: Running and Testing the Application
To run your application, execute:
python manage.py runserver
Visit the user list page to see all users listed. Clicking the edit button will direct you to the profile edit page where you can upload an image. Upon successful upload, the image will replace the placeholder.
Thank you for exploring this guide! I hope you found it beneficial. Should you have any feedback or inquiries, feel free to reach out.