├── .gitignore ├── LICENSE ├── README.md ├── accounts ├── __init__.py ├── admin.py ├── apps.py ├── migrations │ └── __init__.py ├── models.py ├── tests.py ├── urls.py └── views.py ├── db.sqlite3 ├── django_project ├── __init__.py ├── asgi.py ├── settings.py ├── urls.py └── wsgi.py ├── manage.py ├── requirements.txt └── templates ├── base.html ├── home.html └── registration ├── login.html ├── password_reset_complete.html ├── password_reset_confirm.html ├── password_reset_done.html ├── password_reset_form.html └── signup.html /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__ 2 | db.sqlite3 3 | .git 4 | .venv 5 | .DS_Store -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 William S. Vincent 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Django Auth Tutorial source code 2 | 3 | Accompanies the tutorial for [Django Login, Logout, Signup, Password Change, and Password Reset](https://learndjango.com/tutorials/django-login-and-logout-tutorial) available on [LearnDjango.com](https://learndjango.com). 4 | 5 | If you find this repo helpful, please give it a ⭐. -------------------------------------------------------------------------------- /accounts/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wsvincent/django-auth-tutorial/1a83ae76234ca5f78030d2a2bbafa19b723f8fb2/accounts/__init__.py -------------------------------------------------------------------------------- /accounts/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /accounts/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class AccountsConfig(AppConfig): 5 | default_auto_field = "django.db.models.BigAutoField" 6 | name = "accounts" 7 | -------------------------------------------------------------------------------- /accounts/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wsvincent/django-auth-tutorial/1a83ae76234ca5f78030d2a2bbafa19b723f8fb2/accounts/migrations/__init__.py -------------------------------------------------------------------------------- /accounts/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | # Create your models here. 4 | -------------------------------------------------------------------------------- /accounts/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /accounts/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | 3 | from .views import SignUpView 4 | 5 | 6 | urlpatterns = [ 7 | path("signup/", SignUpView.as_view(), name="signup"), 8 | ] 9 | -------------------------------------------------------------------------------- /accounts/views.py: -------------------------------------------------------------------------------- 1 | from django.contrib.auth.forms import UserCreationForm 2 | from django.urls import reverse_lazy 3 | from django.views import generic 4 | 5 | 6 | class SignUpView(generic.CreateView): 7 | form_class = UserCreationForm 8 | success_url = reverse_lazy("login") 9 | template_name = "registration/signup.html" 10 | -------------------------------------------------------------------------------- /db.sqlite3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wsvincent/django-auth-tutorial/1a83ae76234ca5f78030d2a2bbafa19b723f8fb2/db.sqlite3 -------------------------------------------------------------------------------- /django_project/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wsvincent/django-auth-tutorial/1a83ae76234ca5f78030d2a2bbafa19b723f8fb2/django_project/__init__.py -------------------------------------------------------------------------------- /django_project/asgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | ASGI config for django_project project. 3 | 4 | It exposes the ASGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/5.0/howto/deployment/asgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.asgi import get_asgi_application 13 | 14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django_project.settings") 15 | 16 | application = get_asgi_application() 17 | -------------------------------------------------------------------------------- /django_project/settings.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | 3 | # Build paths inside the project like this: BASE_DIR / 'subdir'. 4 | BASE_DIR = Path(__file__).resolve().parent.parent 5 | 6 | 7 | # Quick-start development settings - unsuitable for production 8 | # See https://docs.djangoproject.com/en/5.0/howto/deployment/checklist/ 9 | 10 | # SECURITY WARNING: keep the secret key used in production secret! 11 | SECRET_KEY = "django-insecure-bekb+5+!#s&*jjb5!701ztl^0otie+$s@)kbd^z(bh$(q9g^mc" 12 | 13 | # SECURITY WARNING: don't run with debug turned on in production! 14 | DEBUG = True 15 | 16 | ALLOWED_HOSTS = [] 17 | 18 | 19 | # Application definition 20 | 21 | INSTALLED_APPS = [ 22 | "django.contrib.admin", 23 | "django.contrib.auth", 24 | "django.contrib.contenttypes", 25 | "django.contrib.sessions", 26 | "django.contrib.messages", 27 | "django.contrib.staticfiles", 28 | "accounts", # new 29 | ] 30 | 31 | MIDDLEWARE = [ 32 | "django.middleware.security.SecurityMiddleware", 33 | "django.contrib.sessions.middleware.SessionMiddleware", 34 | "django.middleware.common.CommonMiddleware", 35 | "django.middleware.csrf.CsrfViewMiddleware", 36 | "django.contrib.auth.middleware.AuthenticationMiddleware", 37 | "django.contrib.messages.middleware.MessageMiddleware", 38 | "django.middleware.clickjacking.XFrameOptionsMiddleware", 39 | ] 40 | 41 | ROOT_URLCONF = "django_project.urls" 42 | 43 | TEMPLATES = [ 44 | { 45 | "BACKEND": "django.template.backends.django.DjangoTemplates", 46 | "DIRS": [BASE_DIR / "templates"], # new 47 | "APP_DIRS": True, 48 | "OPTIONS": { 49 | "context_processors": [ 50 | "django.template.context_processors.debug", 51 | "django.template.context_processors.request", 52 | "django.contrib.auth.context_processors.auth", 53 | "django.contrib.messages.context_processors.messages", 54 | ], 55 | }, 56 | }, 57 | ] 58 | 59 | WSGI_APPLICATION = "django_project.wsgi.application" 60 | 61 | 62 | # Database 63 | # https://docs.djangoproject.com/en/5.0/ref/settings/#databases 64 | 65 | DATABASES = { 66 | "default": { 67 | "ENGINE": "django.db.backends.sqlite3", 68 | "NAME": BASE_DIR / "db.sqlite3", 69 | } 70 | } 71 | 72 | 73 | # Password validation 74 | # https://docs.djangoproject.com/en/5.0/ref/settings/#auth-password-validators 75 | 76 | AUTH_PASSWORD_VALIDATORS = [ 77 | { 78 | "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", 79 | }, 80 | { 81 | "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", 82 | }, 83 | { 84 | "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator", 85 | }, 86 | { 87 | "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", 88 | }, 89 | ] 90 | 91 | 92 | # Internationalization 93 | # https://docs.djangoproject.com/en/5.0/topics/i18n/ 94 | 95 | LANGUAGE_CODE = "en-us" 96 | 97 | TIME_ZONE = "UTC" 98 | 99 | USE_I18N = True 100 | 101 | USE_TZ = True 102 | 103 | 104 | # Static files (CSS, JavaScript, Images) 105 | # https://docs.djangoproject.com/en/5.0/howto/static-files/ 106 | 107 | STATIC_URL = "static/" 108 | 109 | # Default primary key field type 110 | # https://docs.djangoproject.com/en/5.0/ref/settings/#default-auto-field 111 | 112 | DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" 113 | 114 | LOGIN_REDIRECT_URL = "home" # new 115 | LOGOUT_REDIRECT_URL = "home" # new 116 | 117 | EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend" 118 | -------------------------------------------------------------------------------- /django_project/urls.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from django.urls import path, include 3 | from django.views.generic.base import TemplateView 4 | 5 | urlpatterns = [ 6 | path("admin/", admin.site.urls), 7 | path("accounts/", include("accounts.urls")), # new 8 | path("accounts/", include("django.contrib.auth.urls")), 9 | path("", TemplateView.as_view(template_name="home.html"), name="home"), 10 | ] 11 | -------------------------------------------------------------------------------- /django_project/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for django_project project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/5.0/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django_project.settings") 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Django's command-line utility for administrative tasks.""" 3 | import os 4 | import sys 5 | 6 | 7 | def main(): 8 | """Run administrative tasks.""" 9 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django_project.settings") 10 | try: 11 | from django.core.management import execute_from_command_line 12 | except ImportError as exc: 13 | raise ImportError( 14 | "Couldn't import Django. Are you sure it's installed and " 15 | "available on your PYTHONPATH environment variable? Did you " 16 | "forget to activate a virtual environment?" 17 | ) from exc 18 | execute_from_command_line(sys.argv) 19 | 20 | 21 | if __name__ == "__main__": 22 | main() 23 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | asgiref==3.8.1 2 | Django==5.2.1 3 | sqlparse==0.4.4 4 | -------------------------------------------------------------------------------- /templates/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | {% block title %}Django Auth Tutorial{% endblock %} 7 | 8 | 9 | 10 |
11 | {% block content %} 12 | {% endblock %} 13 |
14 | 15 | 16 | -------------------------------------------------------------------------------- /templates/home.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block title %}Home{% endblock %} 4 | 5 | {% block content %} 6 | {% if user.is_authenticated %} 7 |

Hi {{ user.username }}!

8 |

Password Change

9 |
10 | {% csrf_token %} 11 | 12 |
13 | {% else %} 14 |

You are not logged in

15 |

Password Reset

16 |

Log In

17 | {% endif %} 18 | {% endblock %} -------------------------------------------------------------------------------- /templates/registration/login.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block title %}Login{% endblock %} 4 | 5 | {% block content %} 6 |

Log In

7 |
8 | {% csrf_token %} 9 | {{ form }} 10 | 11 |
12 | {% endblock %} -------------------------------------------------------------------------------- /templates/registration/password_reset_complete.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block title %}Password reset complete{% endblock %} 4 | 5 | {% block content %} 6 |

Password reset complete

7 |

Your new password has been set. You can log in now on the log in page.

8 | {% endblock %} -------------------------------------------------------------------------------- /templates/registration/password_reset_confirm.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block title %}Enter new password{% endblock %} 4 | 5 | {% block content %} 6 | 7 | {% if validlink %} 8 | 9 |

Set a new password!

10 |
11 | {% csrf_token %} 12 | {{ form.as_p }} 13 | 14 |
15 | 16 | {% else %} 17 | 18 |

The password reset link was invalid, possibly because it has already been used. Please request a new password reset. 19 |

20 | 21 | {% endif %} 22 | {% endblock %} -------------------------------------------------------------------------------- /templates/registration/password_reset_done.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block title %}Email Sent{% endblock %} 4 | 5 | {% block content %} 6 |

Check your inbox.

7 |

We've emailed you instructions for setting your password. You should receive the email shortly!

8 | {% endblock %} -------------------------------------------------------------------------------- /templates/registration/password_reset_form.html: -------------------------------------------------------------------------------- 1 | {% extends 'base.html' %} 2 | 3 | {% block title %}Forgot Your Password?{% endblock %} 4 | 5 | {% block content %} 6 |

Forgot your password?

7 |

Enter your email address below, and we'll email instructions for setting a new one.

8 | 9 |
10 | {% csrf_token %} 11 | {{ form.as_p }} 12 | 13 |
14 | {% endblock %} -------------------------------------------------------------------------------- /templates/registration/signup.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block title %}Sign Up{% endblock %} 4 | 5 | {% block content %} 6 |

Sign up

7 |
8 | {% csrf_token %} 9 | {{ form }} 10 | 11 |
12 | {% endblock %} --------------------------------------------------------------------------------