The comes with two sets of models that are useful for most projects.
The first is a custom
users app with a
If you need to store custom data related to a user,
you can put fields directly on this model.
A custom user model is the recommended way to start a project according to the Django docs.
The second is a
teams app, that includes the
Most projects inevitably need some type of "Team" concept,
so it's one of the few places we like to provide a starting point.
You can rename it if you like, or simply call it something else in your frontend HTML (ex. "Organization" or "Group"),
but in general the
Team is where you'll group users together and attach billing information.
If you really don't intend to use it, you can delete it.
We include two modifications to what the Django
- The email for a user must be unique (helps with login and duplication)
uuidfield is added via
UUIDModel(helps with identifying users without exposing the standard auto-incrementing ID)
When you need to store something directly on a user,
go ahead and write your code in the
# app/users/models.py class User(AbstractUser, UUIDModel): email = models.EmailField(unique=True) # Add your own fields and methods here!
The quickstart comes with all of the
django.contrib.auth.urls enabled at the root (ex. "example.com/login/"). This includes:
- password changes
- password resets
We also include a standard signup form to let users create an account using username, email address, and password.
# app/urls.py urlpatterns = [ # ... path("signup/", SignupView.as_view(), name="signup"), path("", include("django.contrib.auth.urls")), ]
When someone completes the signup form,
they'll be redirected to log in using their new account.
You can customize the
SignupView to log them in immediately, show welcome messages, or start an email confirmation flow first.
When you're setting up the relationships in your project, most of the time you'll want to associate things with a "team" rather than a "user".
Whether you need teams right off the bat or plan to support them later,
it's a good idea to tie "projects", billing, etc. to a
Team even if that team is just a single
Down the road,
if you need to transfer a "project" from a user to their company team,
you can effectively do a
Team->Team transfer which is much simpler than changing the type of relationship from a
User to a
if you plan to support subscriptions for individuals and businesses,
you should consider both of those to be a
Team on the backend which will simplify a lot of the billing logic.
Teams in Forge come with a few fields we think are useful, but you can customize is from there:
# app/teams/models.py class Team(TimestampModel, UUIDModel): name = models.CharField(max_length=255) members = models.ManyToManyField( "users.User", related_name="teams", through="TeamMembership" ) # Add your own fields and methods here! class TeamRoles(models.TextChoices): ... class TeamMembership(TimestampModel, UUIDModel): ...
When you add people to teams,
we also provide a
role field with basic
You can add to these as needed,
but if you aren't using roles right away then just make everyone a
MEMBER so you can add admin-specific features later!
team = Team.objects.create("A new team") team_member1 = TeamMembership.objects.create( team=team, user=user, role=TeamRoles.MEMBER, )
You can use any combination of the mixins when creating your models.
Technically these are "abstract" models,
so you don't actually need
models.Model in your class definition if you use at least one of these.
# app/projects/models.py from django.db import models from forge.models import TimestampModel, UUIDModel class Project(TimestampModel, UUIDModel): name = models.CharField(max_length=255)
TimestampModel includes two fields:
In practice, you can use this on almost every model in your app unless you have a specific reason not to.
# app/projects/models.py from django.db import models from forge.models import TimestampModel class Project(TimestampModel): name = models.CharField(max_length=255)
UUIDModel includes a unique
This is a standard way to identify objects in URLs and APIs where you'd rather not expose the auto-incrementing
In URLs, this can often be an alternative to a user-managed
which can require a lot more effort to get right (uniqueness, edits/redirects, reserved names, etc.).
Note that our implementation does not replace the primary key of a model.
# app/projects/models.py from django.db import models from forge.models import UUIDModel class Project(UUIDModel): name = models.CharField(max_length=255)