(Oh hi! We do follow each other on Twitter – recognized your picture. Small world!)
Custom user model.
type property is set to a choice field. Choices are derived from:
# This is a tuple without the round brackets.
CLIENT = "CLIENT", "Client"
ASSISTANT = "ASSISTANT", "Assistant"
CUSTOMER_SUPPORT = "CUSTOMER_SUPPORT", "Customer Support"
MANAGER = "MANAGER", "Manager"
type = models.CharField(
_("Type"), max_length=50, choices=Types.choices, default=Types.CLIENT
Proxy models for
def get_queryset(self, *args, **kwargs):
results = super().get_queryset(*args, **kwargs)
This is a proxy model to the User class. Primarily,
it gives you a nicer interface to interact with
`CLIENT` type users, and avoids any "silly" errors
down the line.
base_type = User.Types.CLIENT
# A simple abstraction to ensure ClientUser queries
# return only users of 'client' type.
objects = ClientUserManager()
# This means that no table will be created for this
# model in the database. By being a proxy model,
# we are able to add additional methods (and methods
# only) to this model.
proxy = True
verbose_name = _("Client")
verbose_name_plural = _("Clients")
Repeat for all types of users:
ManagerUser. All of them are proxy to the custom
class ClientProfile(UserProfileMixin, TimeStampedModel):
Profile model for storing extra data about a certain
type of user. In this case, the user is a client.
In either case, the owner field is named 'user'.
user = models.OneToOneField(
help_text="This is the client to whom the profile belongs.",
Repeat for all types of users:
Now, setting up that relationship where a person subscribes to our application but 90% of them will be singing up themselves, paying themselves, and using the service themselves.
However, I want to keep the option for the future where 1 person (representing an organization, a club, a company, etc.) can sign up, set up billing, and finally be responsible for
SubClientUsers who will be using the service.
Can you elaborate on this, such as why do you feel this is wrong? Is there some code that has a “smell” to it or maybe a design? Could you share it?
The design is as follows for users:
ClientUser is the building block.
SubClientUser is anyone who has access to the system, while a
ClientUser is anyone who pays for it on behalf of one or more
SubClientUser stores their profile information in
SubClientProfile (things like contact number, address, communication preferences, age, etc.), while a
ClientUser stores their billing details in
ClientProfile (billing address, payment methods, etc.)
And for billing:
Product can be a
Plan for which
Subscriptions are started, or a
Credit for which one-time
Purchases are made.
- Any incoming and outgoing transactions are stored in a
Transactions table. Refunds, purchases, sales, etc. Everything financial goes here.
The reason it feels weird to me, I think, is because in the case where 90% users are self-paying and using, billing data and personal profile data is split in two places. It has the potential to make the admin area confusing, as well as the client area code to be spaghetti over time?