diff --git a/OACPL/settings.base.py b/OACPL/settings.base.py
index 10ff7c6..32fa383 100644
--- a/OACPL/settings.base.py
+++ b/OACPL/settings.base.py
@@ -53,7 +53,8 @@ INSTALLED_APPS = [
     'forum.apps.ForumConfig',
     'main.apps.MainConfig',
     'newsletters.apps.NewslettersConfig',
-    'tinymce'
+    'tinymce',
+    'widget_tweaks'
 ]
 
 MIDDLEWARE = [
diff --git a/charter_members/admin.py b/charter_members/admin.py
index f284b3c..1c458d4 100644
--- a/charter_members/admin.py
+++ b/charter_members/admin.py
@@ -1,16 +1,16 @@
 from django.contrib import admin
 
-from .models import Chapter, Position, Attorney
+from .models import Region, Position, Attorney
 
 
-admin.site.register(Chapter)
+admin.site.register(Region)
 admin.site.register(Position)
 
 
 @admin.register(Attorney)
 class MemberAdmin(admin.ModelAdmin):
-    list_display = ['name', 'position', 'chapter', 'phone_formatted', 'email', 'front_page', 'order', 'joined', 'thumbnail']
-    list_filter = ['chapter', 'position', 'front_page', 'joined']
-    search_fields = ['email', 'joined', 'name', 'chapter', 'position', 'website', 'phone', 'phone_formatted']
-    fields = ['image_preview', 'image', 'name', 'position', 'chapter', 'biography', 'phone', 'email', 'website', 'front_page', 'order', 'joined']
+    list_display = ['last_name', 'first_name', 'position', 'region', 'phone_formatted', 'email', 'front_page', 'order', 'joined', 'thumbnail']
+    list_filter = ['region', 'position', 'front_page', 'joined']
+    search_fields = ['email', 'joined', 'last_name', 'first_name', 'region', 'position', 'website', 'phone', 'phone_formatted']
+    fields = ['image_preview', 'image', 'last_name', 'first_name', 'position', 'region', 'biography', 'phone', 'email', 'website', 'front_page', 'order', 'joined']
     readonly_fields = ['image_preview']
diff --git a/charter_members/forms.py b/charter_members/forms.py
new file mode 100644
index 0000000..fefc3d9
--- /dev/null
+++ b/charter_members/forms.py
@@ -0,0 +1,78 @@
+from django.core import mail
+from django import forms
+from django.contrib.auth.models import Group, User
+
+from tinymce import TinyMCE
+
+from newsletters.models import Subscriber
+from .models import Attorney, Position
+from OACPL import settings
+from OACPL.utils import render_to_string
+
+
+class RegisterForm(forms.ModelForm):
+    def email_validator(self):
+        if User.objects.filter(email=self).exists():
+            raise forms.ValidationError('This email is already registered')
+
+    def password_length(self):
+        if len(self) < 8:
+            raise forms.ValidationError('Password must be at least 8 characters long')
+
+    biography = forms.CharField(widget=forms.Textarea, required=False, label='Biography')
+    call_to_bar = forms.CharField(max_length=4, required=False, label='Year of Call to Bar')
+    case_law = forms.BooleanField(initial=True, required=False)
+    email = forms.EmailField(max_length=255, validators=[email_validator])
+    lso = forms.CharField(max_length=20, required=False, label='LSO #')
+    newsletter = forms.BooleanField(initial=True, required=False)
+    request_training = forms.CharField(max_length=255, required=False, label='Request Training For...')
+    password1 = forms.CharField(widget=forms.PasswordInput(), validators=[password_length])
+    password2 = forms.CharField(widget=forms.PasswordInput())
+    provide_training = forms.CharField(max_length=255, required=False, label='Offer Training For...')
+
+    class Meta:
+        model = Attorney
+        fields = ['first_name', 'last_name', 'region', 'password1', 'password2', 'image', 'email', 'address', 'phone', 'website', 'call_to_bar', 'lso', 'biography', 'provide_training', 'request_training', 'case_law', 'newsletter']
+
+    def clean(self):
+        cleaned_data = super().clean()
+        password = cleaned_data.get('password1')
+        password_confirm = cleaned_data.get('password2')
+        if password != password_confirm:
+            raise forms.ValidationError("The two password fields must match.")
+        return cleaned_data
+
+    def save(self, commit=True):
+        # Create attorney profile
+        user = super().save(commit=False)
+        member = Position.objects.filter(name='Member').first()
+        if member:
+            user.position = member
+        user.save()
+
+        # Add user to default Group
+        default_group = Group.objects.filter(name='default').first()
+        if default_group:
+            default_group[0].user_set.add(user)
+
+        # Send confirmation email
+        mail.send_mail('OACPL Registration', 'You have successfully registered to the Ontario Association of Child Protection Lawyers!', settings.EMAIL_HOST_USER, [user.email], html_message=render_to_string('email.html', {'content': 'You have successfully registered to the Ontario Association of Child Protection Lawyers!', 'name': user.first_name + ' ' + user.last_name, 'base_url': settings.BASE_URL}))
+
+        # Subscribe to newsletters
+        if self.cleaned_data['newsletter'] == 'on' and not Subscriber.objects.filter(email=user.email).exists():
+            Subscriber.objects.create(email=user.email)
+
+        # Send email to register@oacpl.org
+        body = '{} {} ({}) has registered with OACPL. 
'.format(user.first_name, user.last_name, user.email)
+        if self.cleaned_data['case_law'] == 'on':
+            body += 'They have request access to case law. 
'
+        if self.cleaned_data['provide_training']:
+            body += 'They have offered to provide training for: {}. 
'.format(self.cleaned_data['provide_training'])
+        if self.cleaned_data['request_training']:
+            body += 'They have request training for: {}. 
'.format(self.cleaned_data['request_training'])
+        mail.send_mail(user.first_name + ' ' + user.last_name, body.replace('
', ' '), settings.EMAIL_HOST_USER, ['register@oacpl.org'], html_message=render_to_string('email.html', {'content': body, 'base_url': settings.BASE_URL}))
+
+        # Create Auth
+        auth = User.objects.create_user(user.email, first_name=user.first_name, last_name=user.last_name, email=user.email, password=self.cleaned_data['password1'])
+        auth.save()
+        return auth
diff --git a/charter_members/models.py b/charter_members/models.py
index b8a898b..72ab97f 100644
--- a/charter_members/models.py
+++ b/charter_members/models.py
@@ -1,10 +1,11 @@
 from django.conf import settings
 from django.db import models
+from django.utils import timezone
 
 from tinymce import HTMLField
 
 
-class Chapter(models.Model):
+class Region(models.Model):
     name = models.CharField(max_length=50)
 
     def __str__(self):
@@ -12,23 +13,27 @@ class Chapter(models.Model):
 
 
 class Position(models.Model):
-    position_name = models.CharField(max_length=50)
+    name = models.CharField(max_length=50)
 
     def __str__(self):
-        return self.position_name
+        return self.name
 
 
 class Attorney(models.Model):
+    address = models.CharField(max_length=255)
     biography = HTMLField(blank=True, null=True)
-    chapter = models.ForeignKey(Chapter, blank=True, null=True)
-    email = models.CharField(max_length=255, blank=True, null=True)
+    call_to_bar = models.CharField(max_length=4, blank=True, null=True)
+    region = models.ForeignKey(Region, blank=True, null=True)
+    email = models.CharField(max_length=255)
+    first_name = models.CharField(max_length=100)
     front_page = models.BooleanField(default=False)
     image = models.ImageField(upload_to='portraits', default='portraits/silhouette.png')
-    joined = models.DateField(blank=True, null=True)
-    name = models.CharField(max_length=100)
+    joined = models.DateField(default=timezone.now)
+    last_name = models.CharField(max_length=100)
+    lso = models.CharField(max_length=20, blank= True, null=True)
     order = models.IntegerField(blank=True, null=True, verbose_name='Order On Front Page')
-    phone = models.CharField(max_length=10, blank=True, null=True)
-    position = models.ForeignKey(Position)
+    phone = models.CharField(max_length=10)
+    position = models.ForeignKey(Position, blank=True, null=True)
     website = models.CharField(max_length=255, blank=True, null=True)
 
     def phone_formatted(self):
@@ -47,4 +52,4 @@ class Attorney(models.Model):
     image_preview.allow_tags = True
 
     def __str__(self):
-        return self.name
+        return self.first_name + ' ' + self.last_name
diff --git a/charter_members/templates/all.html b/charter_members/templates/all.html
index ed0316e..b335ef9 100644
--- a/charter_members/templates/all.html
+++ b/charter_members/templates/all.html
@@ -3,19 +3,19 @@
 {% block body %}
     
{{ attorney.biography | safe }}
@@ -62,32 +69,96 @@
             
 
-