Coverage for accounts / models.py: 95%
18 statements
« prev ^ index » next coverage.py v7.13.2, created at 2026-03-10 14:10 +0000
« prev ^ index » next coverage.py v7.13.2, created at 2026-03-10 14:10 +0000
1""" Accounts model (CustomUser records) for storing users customized to allow login by email, etc.
3Mix in SafeDeleteManager into CustomUserManager for Soft Deletes using safedelete
5- https://django-safedelete.readthedocs.io/en/latest/managers.html
6- safe delete of custom users example found at;
7- https://codeberg.org/mvlaev/Cars/src/branch/main/cars/users_app/models.py"
8"""
9from django.contrib.auth.models import AbstractUser, UserManager
10from common.base_model import BaseModel
11# from safedelete.models import SafeDeleteModel
12# from safedelete.models import SOFT_DELETE_CASCADE
13from safedelete.managers import SafeDeleteManager
14from auditlog.registry import auditlog
17# from auditlog.models import AuditlogHistoryField
20class CustomUserManager(SafeDeleteManager, UserManager):
21 """Custom User model Manager class ('objects').
23 Manager class for CustomUsers (Accounts). Access to this class is through the 'objects' instance attribute of the CustomUser Class.
25 Soft Delete of Users are implemented through SafeDelete.
26 See: https://django-safedelete.readthedocs.io/en/latest/managers.html
28 Args:
29 param1 (class): SafeDelete manager class mixin
30 param2 (class): UserManager for CustomUser Abstract Class
32 """
34 def all_deleted(self):
35 """Returns all soft deleted customuser records.
37 .. ToDo:: replace accounts.models.CustomUserManager.all_deleted with SafeDeleteManager.deleted_only()
39 - see: https://django-safedelete.readthedocs.io/en/latest/managers.html
40 - note: these functions are only found in model manager classes
41 - thus: all models must declare their custom manager based off of SafeDeleteManager
43 No arguments are passed to this function when calling it
45 Returns:
46 recordset: The soft deleted custom user records.
48 Example:
50 .. code-block:: python
52 # Print out all deleted records
53 for rec in Account.all_deleted():
54 print(rec)
56 """
57 return self.all_with_deleted().filter(deleted__isnull=False)
60class CustomUser(BaseModel, AbstractUser):
61 '''CustomUser model - Abstract User customized to allow login by email
63 Mix in BaseModel to provide:
64 - soft deletes using django-safedelete
65 - https://django-safedelete.readthedocs.io/en/latest/index.html
66 - record history / versioning through django-auditlog
67 - https://github.com/jazzband/django-auditlog
68 '''
69 objects = CustomUserManager()
71 def name_or_email(self):
72 '''Return the user's full name, otherwise return their email.'''
73 if self.first_name != '' and self.last_name != '':
74 return "{fname} {lname}".format(fname=self.first_name, lname=self.last_name)
75 else:
76 print(f'missing full name, using user email: {self.email}')
77 return self.email
79 pass
81 def __str__(self):
82 '''What to print when printing a user's record.'''
83 # fields = [field.name for field in self._meta.fields if field.name != 'password']
84 # return ', '.join(f"{field}: {getattr(self, field)}" for field in fields)
85 return f'{self.email} - {self.last_name}, {self.first_name}'
88# place as last line in file to ensure it gets all changes into AuditLog
89auditlog.register(CustomUser, exclude_fields=[
90 'password', # protect this field for security reasons
91 'last_login', # do not update audit log for each login
92],
93 )