Add User and UserProfile models

This commit is contained in:
Neil Martinsen-Burrell 2022-09-22 12:13:53 -05:00
parent 331d2e575a
commit e0b3023520
No known key found for this signature in database
GPG key ID: 6A3C818CC10D0184
11 changed files with 391 additions and 0 deletions

View file

@ -2,3 +2,5 @@
max-line-length = 88 max-line-length = 88
max-complexity = 10 max-complexity = 10
extend-ignore = E203 extend-ignore = E203
# migrations are auto-generated and often break rules
exclude=registrar/migrations/*

15
src/registrar/admin.py Normal file
View file

@ -0,0 +1,15 @@
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .models import User, UserProfile
# edit a user's profile on the user page
class UserProfileInline(admin.StackedInline):
model = UserProfile
class MyUserAdmin(UserAdmin):
inlines = [UserProfileInline]
admin.site.register(User, MyUserAdmin)

17
src/registrar/apps.py Normal file
View file

@ -0,0 +1,17 @@
from django.apps import AppConfig
class RegistrarConfig(AppConfig):
"""Configure signal handling for our registrar Django application."""
name = "registrar"
def ready(self):
"""Runs when all Django applications have been loaded.
We use it here to load signals that connect related models.
"""
# noqa here because we are importing something to make the signals
# get registered, but not using what we import
from . import signals # noqa

View file

@ -54,6 +54,9 @@ BASE_DIR = path.resolve().parent.parent
# SECURITY WARNING: don't run with debug turned on in production! # SECURITY WARNING: don't run with debug turned on in production!
DEBUG = env_debug DEBUG = env_debug
# Use our user model instead of the default
AUTH_USER_MODEL = "registrar.User"
# Applications are modular pieces of code. # Applications are modular pieces of code.
# They are provided by Django, by third-parties, or by yourself. # They are provided by Django, by third-parties, or by yourself.
@ -504,6 +507,10 @@ if DEBUG:
INSTALLED_APPS += ("nplusone.ext.django",) INSTALLED_APPS += ("nplusone.ext.django",)
MIDDLEWARE += ("nplusone.ext.django.NPlusOneMiddleware",) MIDDLEWARE += ("nplusone.ext.django.NPlusOneMiddleware",)
NPLUSONE_RAISE = True NPLUSONE_RAISE = True
NPLUSONE_WHITELIST = [
{"model": "admin.LogEntry", "field": "user"},
{"model": "registrar.UserProfile"},
]
# insert the amazing django-debug-toolbar # insert the amazing django-debug-toolbar
INSTALLED_APPS += ("debug_toolbar",) INSTALLED_APPS += ("debug_toolbar",)

View file

@ -0,0 +1,168 @@
# Generated by Django 4.1.1 on 2022-09-22 16:05
from django.conf import settings
import django.contrib.auth.models
import django.contrib.auth.validators
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
class Migration(migrations.Migration):
initial = True
dependencies = [
("auth", "0012_alter_user_first_name_max_length"),
]
operations = [
migrations.CreateModel(
name="User",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("password", models.CharField(max_length=128, verbose_name="password")),
(
"last_login",
models.DateTimeField(
blank=True, null=True, verbose_name="last login"
),
),
(
"is_superuser",
models.BooleanField(
default=False,
help_text="Designates that this user has all permissions without explicitly assigning them.",
verbose_name="superuser status",
),
),
(
"username",
models.CharField(
error_messages={
"unique": "A user with that username already exists."
},
help_text="Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.",
max_length=150,
unique=True,
validators=[
django.contrib.auth.validators.UnicodeUsernameValidator()
],
verbose_name="username",
),
),
(
"first_name",
models.CharField(
blank=True, max_length=150, verbose_name="first name"
),
),
(
"last_name",
models.CharField(
blank=True, max_length=150, verbose_name="last name"
),
),
(
"email",
models.EmailField(
blank=True, max_length=254, verbose_name="email address"
),
),
(
"is_staff",
models.BooleanField(
default=False,
help_text="Designates whether the user can log into this admin site.",
verbose_name="staff status",
),
),
(
"is_active",
models.BooleanField(
default=True,
help_text="Designates whether this user should be treated as active. Unselect this instead of deleting accounts.",
verbose_name="active",
),
),
(
"date_joined",
models.DateTimeField(
default=django.utils.timezone.now, verbose_name="date joined"
),
),
(
"groups",
models.ManyToManyField(
blank=True,
help_text="The groups this user belongs to. A user will get all permissions granted to each of their groups.",
related_name="user_set",
related_query_name="user",
to="auth.group",
verbose_name="groups",
),
),
(
"user_permissions",
models.ManyToManyField(
blank=True,
help_text="Specific permissions for this user.",
related_name="user_set",
related_query_name="user",
to="auth.permission",
verbose_name="user permissions",
),
),
],
options={
"verbose_name": "user",
"verbose_name_plural": "users",
"abstract": False,
},
managers=[("objects", django.contrib.auth.models.UserManager())],
),
migrations.CreateModel(
name="UserProfile",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("created_at", models.DateTimeField(auto_now_add=True)),
("updated_at", models.DateTimeField(auto_now=True)),
("street1", models.CharField(max_length=2)),
("street2", models.CharField(max_length=2)),
("street3", models.CharField(max_length=2)),
("city", models.CharField(max_length=2)),
("sp", models.CharField(max_length=2)),
("pc", models.CharField(max_length=2)),
("cc", models.CharField(max_length=2)),
("voice", models.CharField(max_length=2)),
("fax", models.CharField(max_length=2)),
("email", models.CharField(max_length=2)),
("display_name", models.TextField()),
(
"user",
models.OneToOneField(
null=True,
on_delete=django.db.models.deletion.CASCADE,
to=settings.AUTH_USER_MODEL,
),
),
],
options={"abstract": False},
),
]

View file

@ -0,0 +1,63 @@
# Generated by Django 4.1.1 on 2022-09-22 16:51
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("registrar", "0001_initial"),
]
operations = [
migrations.AlterField(
model_name="userprofile",
name="cc",
field=models.TextField(blank=True),
),
migrations.AlterField(
model_name="userprofile",
name="city",
field=models.TextField(blank=True),
),
migrations.AlterField(
model_name="userprofile",
name="email",
field=models.TextField(blank=True),
),
migrations.AlterField(
model_name="userprofile",
name="fax",
field=models.TextField(blank=True),
),
migrations.AlterField(
model_name="userprofile",
name="pc",
field=models.TextField(blank=True),
),
migrations.AlterField(
model_name="userprofile",
name="sp",
field=models.TextField(blank=True),
),
migrations.AlterField(
model_name="userprofile",
name="street1",
field=models.TextField(),
),
migrations.AlterField(
model_name="userprofile",
name="street2",
field=models.TextField(blank=True),
),
migrations.AlterField(
model_name="userprofile",
name="street3",
field=models.TextField(blank=True),
),
migrations.AlterField(
model_name="userprofile",
name="voice",
field=models.TextField(blank=True),
),
]

View file

@ -0,0 +1,18 @@
# Generated by Django 4.1.1 on 2022-09-22 16:53
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("registrar", "0002_alter_userprofile_cc_alter_userprofile_city_and_more"),
]
operations = [
migrations.AlterField(
model_name="userprofile",
name="street1",
field=models.TextField(blank=True),
),
]

View file

View file

@ -0,0 +1,3 @@
from .models import User, UserProfile
__all__ = [User, UserProfile]

View file

@ -0,0 +1,81 @@
from django.contrib.auth.models import AbstractUser
from django.db import models
class User(AbstractUser):
"""
A custom user model that performs identically to the default user model
but can be customized later.
"""
def __str__(self):
if self.userprofile.display_name:
return self.userprofile.display_name
else:
return self.username
class TimeStampedModel(models.Model):
"""
An abstract base model that provides self-updating
`created_at` and `updated_at` fields.
"""
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
abstract = True
# don't put anything else here, it will be ignored
class AddressModel(models.Model):
"""
An abstract base model that provides common fields
for postal addresses.
"""
# contact's street (null ok)
street1 = models.TextField(blank=True)
# contact's street (null ok)
street2 = models.TextField(blank=True)
# contact's street (null ok)
street3 = models.TextField(blank=True)
# contact's city
city = models.TextField(blank=True)
# contact's state or province (null ok)
sp = models.TextField(blank=True)
# contact's postal code (null ok)
pc = models.TextField(blank=True)
# contact's country code
cc = models.TextField(blank=True)
class Meta:
abstract = True
# don't put anything else here, it will be ignored
class ContactModel(models.Model):
"""
An abstract base model that provides common fields
for contact information.
"""
voice = models.TextField(blank=True)
fax = models.TextField(blank=True)
email = models.TextField(blank=True)
class Meta:
abstract = True
# don't put anything else here, it will be ignored
class UserProfile(TimeStampedModel, ContactModel, AddressModel):
user = models.OneToOneField(User, null=True, on_delete=models.CASCADE)
display_name = models.TextField()
def __str__(self):
if self.display_name:
return self.display_name
else:
return self.user.username

17
src/registrar/signals.py Normal file
View file

@ -0,0 +1,17 @@
from django.db.models.signals import post_save
from django.contrib.auth.models import User
from django.dispatch import receiver
from .models import UserProfile
@receiver(post_save, sender=User)
def create_profile(sender, instance, created, **kwargs):
if created:
UserProfile.objects.create(user=instance)
@receiver(post_save, sender=User)
def save_profile(sender, instance, **kwargs):
# instance is a User, it has a profile from the one-to-one relation
instance.userprofile.save()