├── users ├── __init__.py ├── migrations │ └── __init__.py ├── models.py ├── tests.py ├── admin.py ├── apps.py ├── urls.py ├── views.py └── forms.py ├── profiles ├── __init__.py ├── migrations │ └── __init__.py ├── tests.py ├── apps.py ├── admin.py ├── utils.py ├── tokens.py ├── urls.py ├── models.py ├── forms.py └── views.py ├── static ├── css │ ├── style.css │ ├── style.min.css │ └── addons │ │ ├── datatables.min.css │ │ └── datatables.css ├── img │ ├── overlays │ │ ├── 01.png │ │ ├── 02.png │ │ ├── 03.png │ │ ├── 04.png │ │ ├── 05.png │ │ ├── 06.png │ │ ├── 07.png │ │ ├── 08.png │ │ └── 09.png │ ├── lightbox │ │ ├── preloader.gif │ │ ├── default-skin.png │ │ └── default-skin.svg │ └── svg │ │ ├── arrow_left.svg │ │ └── arrow_right.svg ├── font │ └── roboto │ │ ├── Roboto-Bold.eot │ │ ├── Roboto-Bold.ttf │ │ ├── Roboto-Thin.eot │ │ ├── Roboto-Thin.ttf │ │ ├── Roboto-Bold.woff │ │ ├── Roboto-Bold.woff2 │ │ ├── Roboto-Light.eot │ │ ├── Roboto-Light.ttf │ │ ├── Roboto-Light.woff │ │ ├── Roboto-Light.woff2 │ │ ├── Roboto-Medium.eot │ │ ├── Roboto-Medium.ttf │ │ ├── Roboto-Medium.woff │ │ ├── Roboto-Regular.eot │ │ ├── Roboto-Regular.ttf │ │ ├── Roboto-Thin.woff │ │ ├── Roboto-Thin.woff2 │ │ ├── Roboto-Medium.woff2 │ │ ├── Roboto-Regular.woff │ │ └── Roboto-Regular.woff2 ├── index.html └── js │ ├── popper.min.js │ ├── bootstrap.min.js │ └── addons │ └── datatables.min.js ├── website ├── __init__.py ├── wsgi.py ├── urls.py └── settings.py ├── compose.yaml ├── readme_images ├── home.PNG ├── signin.PNG ├── signup.PNG └── dashboard.PNG ├── templates ├── app │ ├── home.html │ ├── profile_edit.html │ ├── dashboard.html │ └── signup.html ├── registration │ ├── account_activation_email.html │ ├── logout.html │ ├── account_activation_sent.html │ ├── account_activation_invalid.html │ └── login.html ├── base.html └── navbar.html ├── requirements.txt ├── Dockerfile ├── manage.py ├── .gitignore └── README.md /users/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /profiles/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/css/style.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /website/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/css/style.min.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /users/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /profiles/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /users/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | # Create your models here. 4 | -------------------------------------------------------------------------------- /users/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /profiles/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /users/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /compose.yaml: -------------------------------------------------------------------------------- 1 | services: 2 | web: 3 | build: website 4 | ports: 5 | - '8000:8000' 6 | -------------------------------------------------------------------------------- /readme_images/home.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Alexmhack/Django-Signup/HEAD/readme_images/home.PNG -------------------------------------------------------------------------------- /readme_images/signin.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Alexmhack/Django-Signup/HEAD/readme_images/signin.PNG -------------------------------------------------------------------------------- /readme_images/signup.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Alexmhack/Django-Signup/HEAD/readme_images/signup.PNG -------------------------------------------------------------------------------- /readme_images/dashboard.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Alexmhack/Django-Signup/HEAD/readme_images/dashboard.PNG -------------------------------------------------------------------------------- /static/img/overlays/01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Alexmhack/Django-Signup/HEAD/static/img/overlays/01.png -------------------------------------------------------------------------------- /static/img/overlays/02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Alexmhack/Django-Signup/HEAD/static/img/overlays/02.png -------------------------------------------------------------------------------- /static/img/overlays/03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Alexmhack/Django-Signup/HEAD/static/img/overlays/03.png -------------------------------------------------------------------------------- /static/img/overlays/04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Alexmhack/Django-Signup/HEAD/static/img/overlays/04.png -------------------------------------------------------------------------------- /static/img/overlays/05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Alexmhack/Django-Signup/HEAD/static/img/overlays/05.png -------------------------------------------------------------------------------- /static/img/overlays/06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Alexmhack/Django-Signup/HEAD/static/img/overlays/06.png -------------------------------------------------------------------------------- /static/img/overlays/07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Alexmhack/Django-Signup/HEAD/static/img/overlays/07.png -------------------------------------------------------------------------------- /static/img/overlays/08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Alexmhack/Django-Signup/HEAD/static/img/overlays/08.png -------------------------------------------------------------------------------- /static/img/overlays/09.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Alexmhack/Django-Signup/HEAD/static/img/overlays/09.png -------------------------------------------------------------------------------- /users/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class UsersConfig(AppConfig): 5 | name = 'users' 6 | -------------------------------------------------------------------------------- /profiles/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class ProfilesConfig(AppConfig): 5 | name = 'profiles' 6 | -------------------------------------------------------------------------------- /static/font/roboto/Roboto-Bold.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Alexmhack/Django-Signup/HEAD/static/font/roboto/Roboto-Bold.eot -------------------------------------------------------------------------------- /static/font/roboto/Roboto-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Alexmhack/Django-Signup/HEAD/static/font/roboto/Roboto-Bold.ttf -------------------------------------------------------------------------------- /static/font/roboto/Roboto-Thin.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Alexmhack/Django-Signup/HEAD/static/font/roboto/Roboto-Thin.eot -------------------------------------------------------------------------------- /static/font/roboto/Roboto-Thin.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Alexmhack/Django-Signup/HEAD/static/font/roboto/Roboto-Thin.ttf -------------------------------------------------------------------------------- /static/img/lightbox/preloader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Alexmhack/Django-Signup/HEAD/static/img/lightbox/preloader.gif -------------------------------------------------------------------------------- /static/font/roboto/Roboto-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Alexmhack/Django-Signup/HEAD/static/font/roboto/Roboto-Bold.woff -------------------------------------------------------------------------------- /static/font/roboto/Roboto-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Alexmhack/Django-Signup/HEAD/static/font/roboto/Roboto-Bold.woff2 -------------------------------------------------------------------------------- /static/font/roboto/Roboto-Light.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Alexmhack/Django-Signup/HEAD/static/font/roboto/Roboto-Light.eot -------------------------------------------------------------------------------- /static/font/roboto/Roboto-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Alexmhack/Django-Signup/HEAD/static/font/roboto/Roboto-Light.ttf -------------------------------------------------------------------------------- /static/font/roboto/Roboto-Light.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Alexmhack/Django-Signup/HEAD/static/font/roboto/Roboto-Light.woff -------------------------------------------------------------------------------- /static/font/roboto/Roboto-Light.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Alexmhack/Django-Signup/HEAD/static/font/roboto/Roboto-Light.woff2 -------------------------------------------------------------------------------- /static/font/roboto/Roboto-Medium.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Alexmhack/Django-Signup/HEAD/static/font/roboto/Roboto-Medium.eot -------------------------------------------------------------------------------- /static/font/roboto/Roboto-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Alexmhack/Django-Signup/HEAD/static/font/roboto/Roboto-Medium.ttf -------------------------------------------------------------------------------- /static/font/roboto/Roboto-Medium.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Alexmhack/Django-Signup/HEAD/static/font/roboto/Roboto-Medium.woff -------------------------------------------------------------------------------- /static/font/roboto/Roboto-Regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Alexmhack/Django-Signup/HEAD/static/font/roboto/Roboto-Regular.eot -------------------------------------------------------------------------------- /static/font/roboto/Roboto-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Alexmhack/Django-Signup/HEAD/static/font/roboto/Roboto-Regular.ttf -------------------------------------------------------------------------------- /static/font/roboto/Roboto-Thin.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Alexmhack/Django-Signup/HEAD/static/font/roboto/Roboto-Thin.woff -------------------------------------------------------------------------------- /static/font/roboto/Roboto-Thin.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Alexmhack/Django-Signup/HEAD/static/font/roboto/Roboto-Thin.woff2 -------------------------------------------------------------------------------- /static/img/lightbox/default-skin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Alexmhack/Django-Signup/HEAD/static/img/lightbox/default-skin.png -------------------------------------------------------------------------------- /static/font/roboto/Roboto-Medium.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Alexmhack/Django-Signup/HEAD/static/font/roboto/Roboto-Medium.woff2 -------------------------------------------------------------------------------- /static/font/roboto/Roboto-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Alexmhack/Django-Signup/HEAD/static/font/roboto/Roboto-Regular.woff -------------------------------------------------------------------------------- /static/font/roboto/Roboto-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Alexmhack/Django-Signup/HEAD/static/font/roboto/Roboto-Regular.woff2 -------------------------------------------------------------------------------- /templates/app/home.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block title %} 4 | Home 5 | {% endblock %} 6 | 7 | {% block content %} 8 | 9 | {{ block.super }} 10 | 11 | {% endblock content %} 12 | -------------------------------------------------------------------------------- /static/img/svg/arrow_left.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/img/svg/arrow_right.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /profiles/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | from .models import Profile 4 | 5 | @admin.register(Profile) 6 | class ProfileModelAdmin(admin.ModelAdmin): 7 | list_display = ('user', 'location') 8 | list_search_fields = ('user', 'location') 9 | -------------------------------------------------------------------------------- /templates/registration/account_activation_email.html: -------------------------------------------------------------------------------- 1 | {% autoescape off %} 2 | Hi {{ user.username }}, 3 | 4 | Please click on the link below to confirm your registration: 5 | 6 | http://{{ domain }}{% url 'profiles:activate' uidb64=uid token=token %} 7 | {% endautoescape %} 8 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | asgiref==3.7.2 2 | certifi==2024.2.2 3 | charset-normalizer==3.3.2 4 | Django==5.0.3 5 | django-utils-six==2.0 6 | django-widget-tweaks==1.5.0 7 | idna==3.6 8 | python-decouple==3.8 9 | requests==2.31.0 10 | six==1.16.0 11 | sqlparse==0.4.4 12 | typing_extensions==4.10.0 13 | urllib3==2.2.1 14 | -------------------------------------------------------------------------------- /templates/registration/logout.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block title %} 4 | Logout 5 | {% endblock %} 6 | 7 | {% block content %} 8 | 9 |
13 | {{ field.label_tag }} 14 | {{ field|attr:"rows:20"|attr:"cols:20" }} 15 | 18 | {% for error in field.errors %} 19 |
{{ error }}
20 | {% endfor %} 21 | 22 | {% endfor %} 23 |{{ message }}
17 |Bio: {{ user.profile.bio }}
27 |Joined: {{ user.profile.timestamp }}
28 | 29 | {% endblock content %} 30 | -------------------------------------------------------------------------------- /users/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render, redirect 2 | from django.contrib.auth import authenticate, login 3 | from django.contrib.auth.forms import UserCreationForm 4 | from django.contrib import messages 5 | from django.contrib.auth.decorators import login_required 6 | 7 | from .forms import SignUpForm 8 | 9 | def signup_view(request): 10 | if request.user.is_authenticated: 11 | return redirect('users:dashboard') 12 | if request.method == "POST": 13 | form = SignUpForm(request.POST) 14 | if form.is_valid(): 15 | form.save() 16 | username = form.cleaned_data.get('username') 17 | password = form.cleaned_data.get('password1') 18 | user = authenticate(username=username, password=password) 19 | login(request, user) 20 | return redirect('users:dashboard') 21 | else: 22 | messages.error(request, 'Correct the errors below') 23 | else: 24 | form = SignUpForm() 25 | 26 | return render(request, 'app/signup.html', {'form': form}) 27 | 28 | 29 | @login_required 30 | def dashboard_view(request): 31 | return render(request, 'app/dashboard.html') 32 | 33 | 34 | def home_view(request): 35 | return render(request, 'app/home.html') 36 | -------------------------------------------------------------------------------- /users/forms.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | from django.contrib.auth.forms import UserCreationForm 3 | from django.contrib.auth.models import User 4 | 5 | class SignUpForm(UserCreationForm): 6 | email = forms.EmailField( 7 | label='', 8 | max_length=254, 9 | widget=forms.EmailInput( 10 | attrs={ 11 | "placeholder": "Email", 12 | "class": "form-control" 13 | } 14 | ) 15 | ) 16 | 17 | username = forms.CharField( 18 | label='', 19 | max_length=30, 20 | min_length=5, 21 | required=True, 22 | widget=forms.TextInput( 23 | attrs={ 24 | "placeholder": "Username", 25 | "class": "form-control" 26 | } 27 | ) 28 | ) 29 | 30 | password1 = forms.CharField( 31 | label='', 32 | max_length=30, 33 | min_length=8, 34 | required=True, 35 | widget=forms.PasswordInput( 36 | attrs={ 37 | "placeholder": "Password", 38 | "class": "form-control" 39 | } 40 | ) 41 | ) 42 | 43 | password2 = forms.CharField( 44 | label='', 45 | max_length=30, 46 | min_length=8, 47 | required=True, 48 | widget=forms.PasswordInput( 49 | attrs={ 50 | "placeholder": "Confirm Password", 51 | "class": "form-control" 52 | } 53 | ) 54 | ) 55 | 56 | class Meta: 57 | model = User 58 | fields = ('username', 'email', 'password1', 'password2') 59 | -------------------------------------------------------------------------------- /profiles/forms.py: -------------------------------------------------------------------------------- 1 | from django import forms 2 | from django.contrib.auth.forms import UserCreationForm 3 | from django.contrib.auth.models import User 4 | 5 | class SignUpForm(UserCreationForm): 6 | username = forms.CharField( 7 | label='', 8 | max_length=30, 9 | min_length=5, 10 | required=True, 11 | widget=forms.TextInput( 12 | attrs={ 13 | "placeholder": "Username", 14 | "class": "form-control" 15 | } 16 | ) 17 | ) 18 | 19 | email = forms.EmailField( 20 | label='', 21 | max_length=255, 22 | required=True, 23 | widget=forms.EmailInput( 24 | attrs={ 25 | "placeholder": "Email", 26 | "class": "form-control" 27 | } 28 | ) 29 | ) 30 | 31 | password1 = forms.CharField( 32 | label='', 33 | max_length=30, 34 | min_length=8, 35 | required=True, 36 | widget=forms.PasswordInput( 37 | attrs={ 38 | "placeholder": "Password", 39 | "class": "form-control" 40 | } 41 | ) 42 | ) 43 | 44 | password2 = forms.CharField( 45 | label='', 46 | max_length=30, 47 | min_length=8, 48 | required=True, 49 | widget=forms.PasswordInput( 50 | attrs={ 51 | "placeholder": "Confirm Password", 52 | "class": "form-control" 53 | } 54 | ) 55 | ) 56 | 57 | location = forms.CharField( 58 | label='', 59 | max_length=30, 60 | required=False, 61 | widget=forms.HiddenInput( 62 | attrs={ 63 | "display": "none" 64 | } 65 | ) 66 | ) 67 | 68 | class Meta: 69 | model = User 70 | fields = ('username', 'email', 'password1', 'password2', 'location') 71 | -------------------------------------------------------------------------------- /static/img/lightbox/default-skin.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |MDB Team
30 |MDB Team
38 |{{ message }}
17 |{{ message }}
17 |p[c]&&(e.offsets.popper[f]+=s[f]+g-p[c]);var u=s[f]+s[a]/2-g/2,b=t(e.instance.popper,'margin'+l).replace('px',''),y=u-h(e.offsets.popper)[f]-b;return y=X(V(p[a]-g,y),0),e.arrowElement=i,e.offsets.arrow={},e.offsets.arrow[f]=Math.round(y),e.offsets.arrow[m]='',e},element:'[x-arrow]'},flip:{order:600,enabled:!0,fn:function(e,t){if(W(e.instance.modifiers,'inner'))return e;if(e.flipped&&e.placement===e.originalPlacement)return e;var o=w(e.instance.popper,e.instance.reference,t.padding,t.boundariesElement),i=e.placement.split('-')[0],n=L(i),r=e.placement.split('-')[1]||'',p=[];switch(t.behavior){case fe.FLIP:p=[i,n];break;case fe.CLOCKWISE:p=K(i);break;case fe.COUNTERCLOCKWISE:p=K(i,!0);break;default:p=t.behavior;}return p.forEach(function(s,d){if(i!==s||p.length===d+1)return e;i=e.placement.split('-')[0],n=L(i);var a=e.offsets.popper,l=e.offsets.reference,f=_,m='left'===i&&f(a.right)>f(l.left)||'right'===i&&f(a.left)
Bio: {{ user.profile.bio }}
391 |Location: {{ user.profile.location }}
392 |Joined: {{ user.profile.timestamp }}
393 | ``` 394 | 395 | **For customizing the forms you can use [django-widget-tweaks](https://pypi.org/project/django-widget-tweaks/)** 396 | 397 | # Signup With Confirmation Email 398 | Django provides built-in system for sending emails. But first of test purposes 399 | we will be using **Console Backend** for emails. 400 | 401 | Add this settings in ```settings.py``` file 402 | 403 | ``` 404 | EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' 405 | ``` 406 | 407 | Now for checking if a user is authenticated we will create a field in the profile 408 | model to determine if the user is confirmed or not. 409 | 410 | **profiles/models.py** 411 | ``` 412 | class Profile(models.Model): 413 | ... 414 | email_confirmed = models.BooleanField(default=False) 415 | ``` 416 | 417 | And for creating a one time link using django we will create a new file ```tokens.py``` 418 | 419 | ``` 420 | from django.contrib.auth.tokens import PasswordResetTokenGenerator 421 | from django.utils import six 422 | 423 | class AccountActivationTokenGenerator(PasswordResetTokenGenerator): 424 | def _make_hash_value(self, user, timestamp): 425 | return ( 426 | six.text_type(user.pk) + six.text_type(timestamp) + 427 | six.text_type(user.profile.email_confirmed) 428 | ) 429 | 430 | 431 | account_activation_token = AccountActivationTokenGenerator() 432 | ``` 433 | 434 | We use the ```pk``` from the user ```timestamp``` and the ```email_confirmed``` field 435 | to create a token. We basically extended the PasswordResetTokenGenerator to create a 436 | unique token generator to confirm email addresses. This make use of your project’s 437 | SECRET_KEY, so it is a pretty safe and reliable method. 438 | 439 | Now we need to define views for account activation as well as account activation sent 440 | view 441 | 442 | ``` 443 | def account_activation_sent_view(request): 444 | return render(request, 'registration/account_activation_sent.html') 445 | 446 | 447 | def account_activate(request, uidb64, token): 448 | try: 449 | uid = urlsafe_base64_decode(uidb64).decode() 450 | print(uid) 451 | user = User.objects.get(pk=uid) 452 | except (TypeError, ValueError, OverflowError, User.DoesNotExist) as e: 453 | print(e) 454 | user = None 455 | 456 | if user is not None and account_activation_token.check_token(user, token): 457 | user.is_active = True 458 | user.profile.email_confirmed = True 459 | user.save() 460 | login(request, user) 461 | return redirect('users:dashboard') 462 | else: 463 | return render(request, 'registration/account_activation_invalid.html') 464 | ``` 465 | 466 | ```account_activation_sent_view``` is justfor redirecting users if their account activation url is wrong. The template **registration/account_activation_sent.html** 467 | will be 468 | 469 | ``` 470 | {% extends "base.html" %} 471 | 472 | {% block title %} 473 | {{ block.super }} - Check Your Email Account 474 | {% endblock %} 475 | 476 | {% block content %} 477 | 478 |