Use Django’s built-in auth system — log users in and out, protect views, check permissions, read the current user, and swap in a custom user model the right way.
Note: django.contrib.auth ships with a User model, password hashing, sessions, and login views — all enabled in a new project. You configure where login redirects happen with a couple of settings.
# config/settings.py
LOGIN_URL = "login" # where @login_required sends visitors
LOGIN_REDIRECT_URL = "blog:post_list"
LOGOUT_REDIRECT_URL = "blog:post_list"Why: Django provides the LoginView and LogoutView, so you only supply a template and a URL. Where: wire them in your URLConf. The login template just renders the auth form with a CSRF token.
# config/urls.py
from django.contrib.auth import views as auth_views
from django.urls import path
urlpatterns = [
path("login/", auth_views.LoginView.as_view(), name="login"),
path("logout/", auth_views.LogoutView.as_view(), name="logout"),
]<!-- registration/login.html -->
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Log in</button>
</form>When @login_required: a function view that should reject anonymous users — they get redirected to LOGIN_URL. When LoginRequiredMixin: the class-based equivalent; list it first in the parents so it runs before the view logic.
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import CreateView
@login_required
def dashboard(request):
return render(request, "blog/dashboard.html")
class PostCreateView(LoginRequiredMixin, CreateView): # mixin first
model = Post
fields = ["title", "body"]Note: every request carries request.user — either a logged-in User or an AnonymousUser. is_authenticated tells them apart. In templates the same object is available as {{ user }}.
def profile(request):
if request.user.is_authenticated:
posts = Post.objects.filter(author=request.user)
else:
posts = Post.objects.none()
return render(request, "blog/profile.html", {"posts": posts}){% if user.is_authenticated %}
Hi, {{ user.username }} — <a href="{% url 'logout' %}">Log out</a>
{% else %}
<a href="{% url 'login' %}">Log in</a>
{% endif %}Why: you will eventually want extra fields (e.g. login by email). Note: do this on day one — set AUTH_USER_MODEL before your first migrate, because switching later is painful. AbstractUser keeps all the built-in fields and lets you add your own.
# accounts/models.py
from django.contrib.auth.models import AbstractUser
from django.db import models
class User(AbstractUser):
bio = models.TextField(blank=True)
# config/settings.py — set BEFORE the first migrate
AUTH_USER_MODEL = "accounts.User"
# always reference it indirectly:
# from django.conf import settings
# author = models.ForeignKey(settings.AUTH_USER_MODEL, ...)