Penyesuaian pembuktian keaslian di DjangoLink to this heading
Pembuktian keaslian yang datang dengan Django adalah cukup bagus untuk kasus umum, tetapi anda mungkin tidak butuh memenuhi dengan awal out-of-the-box. Untuk menyesuaiakan pembuktian keaslian ke proyek anda butuh melibatkan pemahaman titik apa dari sistem disediakan dapat di perpanjang atau diganti. Dokumen ini menyediakan rincian tentang bagaimana sistem pembuktian keaslian dapat di sesuaikan.
Authentication backends menyediakan sistem dapat diperpanjang untuk ketika nama pengguna dan sandi disimpan dengan model User butuh diperiksa keasliannya terhadap layanan berbeda dari awa Django.
Anda dapat memberikan model anda perizinan perizinan disesuaikan yang dapat diperiksa melalui sistem pemeriksaan keaslian Django.
Anda dapat extend User model awal, atau substitute model disesuaikan yang lengkap.
Sumber pembuktian keaslian lainLink to this heading
Mungkin ada kali anda harus butuh mengait ke dalam sumber pembuktian keaslian lain -- yaitu, sumber lain dari nama pengguna dan sandi atau cara pembuktian keaslian.
Sebagai contoh, perusahaan anda mungkin sudah mempunyai pengaturan LDAP yang menyimpan nama pengguna dan sandi untuk setiap karyawan. Itu akan menjadi cekcok untuk kedua administrator jaringan dan pengguna nya sendiri jika pengguna mempunyai akun terpisah di LDAP dan aplikasi berbasis-Django.
Jadi, untuk menangani keadaan seperti ini, sistem pembuktian keaslian Django membiarkan anda memasang sumber pembuktian keaslian lain. Anda dapat mengesampingkan skema berbasis-basisdata awal Django, atau anda dapat menggunakan sistem awal untuk dipasangkan dengan sistem lain.
Lihat acuan backend pembuktian keaslian untuk informasi pada backend pembuktian keaslian yang disertakan dengan Django.
Menentukan backend pembuktian keaslianLink to this heading
Dibelakang layar, Django merawat daftar "backend pembuktian keaslian" yang dia periksa untuk pembuktian keaslian. Ketika seseorang memanggil django.contrib.auth.authenticate() -- seperti digambarkan di How to log a user in -- Django mencoba membuktikan keaslian disemua bakcend pembuktian keaslian itu. Jika cara pembuktian keaslian pertama gagal, Django mencoba yang kedua, dan selanjutnya, sampai semua backend telah dicoba.
Daftar backend pembuktian keaslian untuk digunakan ditentukan dalam pengaturan AUTHENTICATION_BACKENDS. Ini seharusnya daftar nama jalur Python yang menunjuk ke kelas Python yang mengetahui bagaimana membuktikan keaslian. Kelas ini dapat berada dimanapun di jalur Python anda.
Secara awal, AUTHENTICATION_BACKENDS disetel ke:
['django.contrib.auth.backends.ModelBackend']
Itu adalah backend pembuktian keaslian dasar yang memeriksa basisdata pengguna Django dan permintaan perizinan terpasang-tetap. Dia tidak menyediakan perlindungan terhadap serangan paksa brutal melalui mekanisme pembatasan apapun. Anda dapat salah satu menerapkan mekanisme pembatasan laju anda sendiri di backend pembuktian keaslian penyesuaian, atau menggunakan mekanisme yang disediakan oleh kebanyakan peladen Jaringan.
Urutan masalah AUTHENTICATION_BACKENDS, jadi jika nama pengguna dan sandi sama adalah sah di banyak backend, Django akan menghentikan pengolahan pada pertama yang positif cocok.
Jika backend memunculkan pengecualian PermissionDenied, pembuktian keaslian akan segera gagal. Django tidak akan memeriksa backend yang mengikuti.
Menulis backend pembuktian keaslianLink to this heading
Sebuah backend pembuktian keaslian adalah sebuah kelas yang menerapkan dua cara dibutuhkan: get_user(user_id) dan authenticate(**credentials), dan juga kumpulan dari pilihan perizinan terhubung cara pembuktian keaslian.
Cara get_user mengambil user_id -- yng dapat berupa nama pengguna, ID basisdata atau apapun, tetapi harus menjadu primary key dari obyek User anda -- dan mengembalikan obyek User.
Cara authenticate mengambil mandat sebagai argumen kata kunci. Kebanyakan dari waktu, dia akan kelihatan seperti ini:
class MyBackend(object):
def authenticate(self, username=None, password=None):
# Check the username/password and return a User.
...
Tetapi itu dapat juga membuktikan keaslian sebuah token, seperti begitu:
class MyBackend(object):
def authenticate(self, token=None):
# Check the token and return a User.
...
Salah satu cara, authenticate harus memeriksa mandat yang dia dapatkan, dan dia harus mengembalikan obyek User yang cocok dengan mandat, jika mandat sah. Jika mereka tidak sah, dia harus mengembalikan None.
Admin Django erat ke Django Obyek User. Cara terbaik berurusan dengna ini adalah membuat obyek user Django untuk setiap pengguna yang ada untuk backend anda (sebagai contoh dalam direktori LDAP, basisdata SQL eksternal anda, dll.) Anda dapat salah satu menulis tulisan untuk melakukannya terlebih dahulu, atau cara authenticate anda dapat melakukannya pertama kali pengguna masuk.
Ini adalah sebuah contoh yang membuktikan keaslian variabel terhdap nama pengguna dan sandi ditentukan dalam berkas settings.py anda dan membuat sebuah obyek User Django pertama kali pengguna dibuktikan keaslian:
from django.conf import settings
from django.contrib.auth.hashers import check_password
from django.contrib.auth.models import User
class SettingsBackend(object):
"""
Authenticate against the settings ADMIN_LOGIN and ADMIN_PASSWORD.
Use the login name, and a hash of the password. For example:
ADMIN_LOGIN = 'admin'
ADMIN_PASSWORD = 'pbkdf2_sha256$30000$Vo0VlMnkR4Bk$qEvtdyZRWTcOsCnI/oQ7fVOu1XAURIZYoOZ3iq8Dr4M='
"""
def authenticate(self, username=None, password=None):
login_valid = (settings.ADMIN_LOGIN == username)
pwd_valid = check_password(password, settings.ADMIN_PASSWORD)
if login_valid and pwd_valid:
try:
user = User.objects.get(username=username)
except User.DoesNotExist:
# Create a new user. Note that we can set password
# to anything, because it won't be checked; the password
# from settings.py will.
user = User(username=username, password='get from settings.py')
user.is_staff = True
user.is_superuser = True
user.save()
return user
return None
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
Penyesuaian perizinanLink to this heading
Untuk membuat perizinan penyesuaian untuk obyek model yang diberikan, gunakan permissions model Meta attribute.
Model task contoh ini membuat tiga perizinan penyesuaian, yaitu, tindakan pengguna dapat atau tidak dapat dilakukan dengan permintaan Task, khusus pada apliaksi anda:
class Task(models.Model):
...
class Meta:
permissions = (
("view_task", "Can see available tasks"),
("change_task_status", "Can change the status of tasks"),
("close_task", "Can remove a task by setting its status as closed"),
)
Satu-satunya ini dilakukan adalah membuat perizinan tambahan ketika anda menjalankan manage.py migrate (fungsi yang membuat perizinan terhubung ke sinyal post_migrate). Kode anda bertanggung jawab dari pemeriksaan nilai perizinan ini ketika sebuah pengguna mencoba mengakses fungsionalitas disediakan oleh aplikasi (melihat tugas, merubah keadaan dari tugas, menutup tugas.) Melanjutkan contoh diatas, pemeriksaan berikut jika sebuah pengguna mungkin melihat tugas:
user.has_perm('app.view_task')
Memperpanjang model User yang adaLink to this heading
Terdapat dua jalan untuk memperpanjang model User awal tanpa mengganti model milik anda. Jika perubahan anda butuhkan murni kebiasaan, dan tidak membutuhkan perubahan apapun ke apa ang disimpan di basisdata, anda dapat membuat proxy model berdasarkan pada User. Ini mengizinkan fitur apapun ditawarkan oleh model proxy termasuk pemesanan awal, pengelola penyesuaian, atau cara model penyesuaian.
Jika anda berharap menyimpan informasi terkait ke User, anda dapat menggunakan OneToOneField pada sebuah model mengandung bidang untuk informasi tambahan. Ini model satu-ke-satu selalu memanggil model profil, karena dia akan menyimpan informasi terkait bukan-asli tentang pengguna situs. Sebagai contoh anda mungkin membuat sebuah model Employee:
from django.contrib.auth.models import User
class Employee(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
department = models.CharField(max_length=100)
Mengganggap Pegawai Fred Smith yang ada yang mempunyai kedua model User dan Employee, anda dapat mengakses informasi terkait menggunakan standar Django ketentuan model terkait:
>>> u = User.objects.get(username='fsmith')
>>> freds_department = u.employee.department
Untuk menambahkan profil bidang model ke halaman pengguna dalam admin, tentukan sebuah class:~django.contrib.admin.InlineModelAdmin (untuk contoh ini, kami akan menggunakan StackedInline) di admin.py aplikasi anda dan menambahkannya ke kelas UserAdmin yang terdaftar dengan kelas User:
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.contrib.auth.models import User
from my_user_profile_app.models import Employee
# Define an inline admin descriptor for Employee model
# which acts a bit like a singleton
class EmployeeInline(admin.StackedInline):
model = Employee
can_delete = False
verbose_name_plural = 'employee'
# Define a new User admin
class UserAdmin(BaseUserAdmin):
inlines = (EmployeeInline, )
# Re-register UserAdmin
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
Model profil ini tidak khusus di jalan apapun - mereka hanya model Django yang terjadi untuk mempunyai kaitan satu-ke-satu dengan model User. Seperti, mereka tidak mendapatkan otomatis dibuat ketika pengguna dibuat, tetapi django.db.models.signals.post_save dapat digunakan untuk membuat atau memperbaharui model terkait sewajarnya.
Catat bahwa menggunakan hasil model terkait di tambahan permintaan atau penggabungan untuk mendapatkan data terkait, dan tergantung pada kebutuhan anda mengganti model User dan menambahkan bidang terkait mungkin pilihan terbaik anda. Bagaimanapun tautan terkait ke model User awal dalam aplikasi proyek anda mungkin membenarkan muatan basisdata lebih.
Mengganti model User penyesuaianLink to this heading
Beberapa macam proyek mungkin mempunyai persyaratan pembuktian keaslian untuk dimana model User dipasang tetap Django tidak selalu sesuai. Sebagai contoh, pada beberapa situs akan masuk akal menggunakan sebauh alamat surel sebagai token pencirian daripada nama pengguna.
Django mengizinkan anda untuk mengesampingkan model User awal dengan menyediakan nilai untuk pengaturan AUTH_USER_MODEL yang mengacu sebuah model penyesuaian:
AUTH_USER_MODEL = 'myapp.MyUser'
Pasangan titik ini menggambarkan nama dari aplikasi Django (yang harus berada di INSTALLED_APPS), dan nama dari model Django yang anda harapkan untuk digunakan sebagai model User anda.
Mengacu model UserLink to this heading
If you reference User directly (for
example, by referring to it in a foreign key), your code will not work in
projects where the AUTH_USER_MODEL setting has been changed to a
different User model.
- get_user_model()Link to this definition
Instead of referring to
Userdirectly, you should reference the user model usingdjango.contrib.auth.get_user_model(). This method will return the currently active User model -- the custom User model if one is specified, orUserotherwise.Ketika anda menentukan foreign key atau hubungan many-to-many pada model User, anda harus menjelaskan penyesuaian model menggunakan pengaturan
AUTH_USER_MODEL. Sebagai contoh:from django.conf import settings from django.db import models class Article(models.Model): author = models.ForeignKey( settings.AUTH_USER_MODEL, on_delete=models.CASCADE, )Ketika terhubung ke sinyal yang dikirim oleh model
User. anda harus menentukan penyesuaian model menggunakan pengaturanAUTH_USER_MODEL. Sebagai contoh:from django.conf import settings from django.db.models.signals import post_save def post_save_receiver(sender, instance, created, **kwargs): pass post_save.connect(post_save_receiver, sender=settings.AUTH_USER_MODEL)Secara umum, anda harus mengacu model User dengan pengaturan
AUTH_USER_MODELdi kode yang dijalankan pada waktu impor.get_user_model()hanya bekerja sekali ketika Django telah mengimpor semua model.
Menentukan penyesuaian model UserLink to this heading
Django mengharapkan model User penyesuaian anda memenuhi persyaratan minimal.
Jika anda menggunakan backend pembuktian keaslian awal, kemudian model anda harus mempunyai bidang unik tunggal yang dapat digunakan untuk tujuan pencirian. Ini dapat berupa nama pengguna, sebauh alamat surel, atau atribut unik lainnya. Bidang nama pengguna tidak unik diizinakn jika anda menggunakan penyesuaian backend pembuktian keaslian yang dapat mendukungnya.
Model anda harus menyediakan cara terbaik utnuk mengalamatkan pengguna dalam bentuk "short" and "long". Penafsiran paling umum dari ini akan digunakan nama diberikan pengguna sebagai penciri "short", dan nama lengkap pengguna sebagai penciri "long". Bagaimanapun, tidak ada batasan pada apa yang duca cara ini kembalikan - jika anda ingin, mereka dapat mengembalikan nilai sama yang tepat.
The easiest way to construct a compliant custom User model is to inherit from
AbstractBaseUser.
AbstractBaseUser provides the core
implementation of a User model, including hashed passwords and tokenized
password resets. You must then provide some key implementation details:
- class models.CustomUserLink to this definition
- USERNAME_FIELDLink to this definition
A string describing the name of the field on the User model that is used as the unique identifier. This will usually be a username of some kind, but it can also be an email address, or any other unique identifier. The field must be unique (i.e., have
unique=Trueset in its definition), unless you use a custom authentication backend that can support non-unique usernames.Dalam contoh berikut, bidang
identifierdigunakan sebagai bidang pengenal:class MyUser(AbstractBaseUser): identifier = models.CharField(max_length=40, unique=True) ... USERNAME_FIELD = 'identifier'USERNAME_FIELDnow supportsForeignKeys. Since there is no way to pass model instances during thecreatesuperuserprompt, expect the user to enter the value ofto_fieldvalue (theprimary_keyby default) of an existing instance.
- REQUIRED_FIELDSLink to this definition
A list of the field names that will be prompted for when creating a user via the
createsuperusermanagement command. The user will be prompted to supply a value for each of these fields. It must include any field for whichblankisFalseor undefined and may include additional fields you want prompted for when a user is created interactively.REQUIRED_FIELDShas no effect in other parts of Django, like creating a user in the admin.Sebagai contoh, ini adalah pengertian sebagian untuk model
Useryang menentukan dua bidang diwajibkan - tanggal dari kelahiran dan tinggi:class MyUser(AbstractBaseUser): ... date_of_birth = models.DateField() height = models.FloatField() ... REQUIRED_FIELDS = ['date_of_birth', 'height']REQUIRED_FIELDSnow supportsForeignKeys. Since there is no way to pass model instances during thecreatesuperuserprompt, expect the user to enter the value ofto_fieldvalue (theprimary_keyby default) of an existing instance.
- is_activeLink to this definition
A boolean attribute that indicates whether the user is considered "active". This attribute is provided as an attribute on
AbstractBaseUserdefaulting toTrue. How you choose to implement it will depend on the details of your chosen auth backends. See the documentation of theis_active attribute on the built-in user modelfor details.
- get_full_name()Link to this definition
A longer formal identifier for the user. A common interpretation would be the full name of the user, but it can be any string that identifies the user.
- get_short_name()Link to this definition
A short, informal identifier for the user. A common interpretation would be the first name of the user, but it can be any string that identifies the user in an informal way. It may also return the same value as
django.contrib.auth.models.User.get_full_name().
The following methods are available on any subclass of
AbstractBaseUser:
- class models.AbstractBaseUserLink to this definition
- get_username()Link to this definition
Mengembalikan nilai dari bidang dicalonkan oleh
USERNAME_FIELD.
- is_anonymous()Link to this definition
Always returns
False. This is a way of differentiating fromAnonymousUserobjects. Generally, you should prefer usingis_authenticated()to this method.
- is_authenticated()Link to this definition
Always returns
True. This is a way to tell if the user has been authenticated. This does not imply any permissions, and doesn't check if the user is active - it only indicates that the user has provided a valid username and password.
- set_password(raw_password)Link to this definition
Sets the user's password to the given raw string, taking care of the password hashing. Doesn't save the
AbstractBaseUserobject.When the raw_password is
None, the password will be set to an unusable password, as ifset_unusable_password()were used.
- check_password(raw_password)Link to this definition
Returns
Trueif the given raw string is the correct password for the user. (This takes care of the password hashing in making the comparison.)
- set_unusable_password()Link to this definition
Marks the user as having no password set. This isn't the same as having a blank string for a password.
check_password()for this user will never returnTrue. Doesn't save theAbstractBaseUserobject.You may need this if authentication for your application takes place against an existing external source such as an LDAP directory.
- has_usable_password()Link to this definition
Returns
Falseifset_unusable_password()has been called for this user.
- get_session_auth_hash()Link to this definition
Mengembalikan nilai HMAC dari kolom kata sandi. Digunakan untuk Session invalidation on password change.
You should also define a custom manager for your User model. If your
User model defines username, email, is_staff, is_active,
is_superuser, last_login, and date_joined fields the same as
Django's default User, you can just install Django's
UserManager; however, if your User
model defines different fields, you will need to define a custom manager that
extends BaseUserManager providing two
additional methods:
- class models.CustomUserManagerLink to this definition
- create_user(*username_field*, password=None, \**other_fields)Link to this definition
The prototype of
create_user()should accept the username field, plus all required fields as arguments. For example, if your user model usesemailas the username field, and hasdate_of_birthas a required field, thencreate_usershould be defined as:def create_user(self, email, date_of_birth, password=None): # create user here ...
- create_superuser(*username_field*, password, \**other_fields)Link to this definition
The prototype of
create_superuser()should accept the username field, plus all required fields as arguments. For example, if your user model usesemailas the username field, and hasdate_of_birthas a required field, thencreate_superusershould be defined as:def create_superuser(self, email, date_of_birth, password): # create superuser here ...Tidak seperti
create_user(),create_superuser()harus membutuhkan pemanggil untuk menyedianan sebuah sandi.
BaseUserManager menyediakan cara kegunaan berikut:
- class models.BaseUserManagerLink to this definition
- classmethod normalize_email(email)Link to this definition
Normalizes email addresses by lowercasing the domain portion of the email address.
- get_by_natural_key(username)Link to this definition
Retrieves a user instance using the contents of the field nominated by
USERNAME_FIELD.
- make_random_password(length=10, allowed_chars='abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789')Link to this definition
Returns a random password with the given length and given string of allowed characters. Note that the default value of
allowed_charsdoesn't contain letters that can cause user confusion, including:i,l,I, and1(huruf kecil i, huruf kecil L, huruf besar i, dan angka satu)o,O, and0(huruf kecil o, huruf besar o, dan nol)
Extending Django's default UserLink to this heading
If you're entirely happy with Django's User
model and you just want to add some additional profile information, you could
simply subclass django.contrib.auth.models.AbstractUser and add your
custom profile fields, although we'd recommend a separate model as described in
the "Model design considerations" note of Menentukan penyesuaian model User.
AbstractUser provides the full implementation of the default
User as an abstract model.
Custom users and the built-in auth formsLink to this heading
Django's built-in forms and views make certain assumptions about the user model that they are working with.
Bentuk berikut cocok dengan subkelas apapun dari AbstractBaseUser:
AuthenticationForm: Menggunakan bidang nama pengguna ditentukan olehUSERNAME_FIELD.
The following forms make assumptions about the user model and can be used as-is if those assumptions are met:
PasswordResetForm: Assumes that the user model has a field namedemailthat can be used to identify the user and a boolean field namedis_activeto prevent password resets for inactive users.
Finally, the following forms are tied to
User and need to be rewritten or extended
to work with a custom user model:
If your custom user model is a simple subclass of AbstractUser, then you
can extend these forms in this manner:
from django.contrib.auth.forms import UserCreationForm
from myapp.models import CustomUser
class CustomUserCreationForm(UserCreationForm):
class Meta(UserCreationForm.Meta):
model = CustomUser
fields = UserCreationForm.Meta.fields + ('custom_field',)
Penyesuaian pengguna dan django.contrib.adminLink to this heading
If you want your custom User model to also work with Admin, your User model must define some additional attributes and methods. These methods allow the admin to control access of the User to admin content:
- class models.CustomUserLink to this definition
- is_staffLink to this definition
Mengembalikan
Truejika pengguna diizinkan mempunyai akses ke situs admin
- is_activeLink to this definition
Mengembalikan
Truejika akun pengguna saat ini aktif.
- has_perm(perm, obj=None):
Returns
Trueif the user has the named permission. Ifobjis provided, the permission needs to be checked against a specific object instance.
- has_module_perms(app_label):
Mengembalikan
Truejika pengguna mempunyai perizinan untuk mengakses model pada aplikasi yang diberikan.
You will also need to register your custom User model with the admin. If
your custom User model extends django.contrib.auth.models.AbstractUser,
you can use Django's existing django.contrib.auth.admin.UserAdmin
class. However, if your User model extends
AbstractBaseUser, you'll need to define
a custom ModelAdmin class. It may be possible to subclass the default
django.contrib.auth.admin.UserAdmin; however, you'll need to
override any of the definitions that refer to fields on
django.contrib.auth.models.AbstractUser that aren't on your
custom User class.
Penyesuaian pengguna dan perizinanLink to this heading
To make it easy to include Django's permission framework into your own User
class, Django provides PermissionsMixin.
This is an abstract model you can include in the class hierarchy for your User
model, giving you all the methods and database fields necessary to support
Django's permission model.
PermissionsMixin menyediakan cara dan atribut berikut:
- class models.PermissionsMixinLink to this definition
- is_superuserLink to this definition
Boolean. Designates that this user has all permissions without explicitly assigning them.
- get_group_permissions(obj=None)Link to this definition
Returns a set of permission strings that the user has, through their groups.
If
objis passed in, only returns the group permissions for this specific object.
- get_all_permissions(obj=None)Link to this definition
Returns a set of permission strings that the user has, both through group and user permissions.
If
objis passed in, only returns the permissions for this specific object.
- has_perm(perm, obj=None)Link to this definition
Returns
Trueif the user has the specified permission, wherepermis in the format"<app label>.<permission codename>"(see permissions). If the user is inactive, this method will always returnFalse.If
objis passed in, this method won't check for a permission for the model, but for this specific object.
- has_perms(perm_list, obj=None)Link to this definition
Returns
Trueif the user has each of the specified permissions, where each perm is in the format"<app label>.<permission codename>". If the user is inactive, this method will always returnFalse.If
objis passed in, this method won't check for permissions for the model, but for the specific object.
- has_module_perms(package_name)Link to this definition
Returns
Trueif the user has any permissions in the given package (the Django app label). If the user is inactive, this method will always returnFalse.
PermissionsMixin dan ModelBackend
If you don't include the
PermissionsMixin, you must ensure you
don't invoke the permissions methods on ModelBackend. ModelBackend
assumes that certain fields are available on your user model. If your
User model doesn't provide those fields, you will receive database
errors when you check permissions.
Custom users and proxy modelsLink to this heading
One limitation of custom User models is that installing a custom User model
will break any proxy model extending User.
Proxy models must be based on a concrete base class; by defining a custom User
model, you remove the ability of Django to reliably identify the base class.
If your project uses proxy models, you must either modify the proxy to extend the User model that is currently in use in your project, or merge your proxy's behavior into your User subclass.
Sebuah contoh penuhLink to this heading
Here is an example of an admin-compliant custom user app. This user model uses
an email address as the username, and has a required date of birth; it
provides no permission checking, beyond a simple admin flag on the user
account. This model would be compatible with all the built-in auth forms and
views, except for the User creation forms. This example illustrates how most of
the components work together, but is not intended to be copied directly into
projects for production use.
This code would all live in a models.py file for a custom
authentication app:
from django.db import models
from django.contrib.auth.models import (
BaseUserManager, AbstractBaseUser
)
class MyUserManager(BaseUserManager):
def create_user(self, email, date_of_birth, password=None):
"""
Creates and saves a User with the given email, date of
birth and password.
"""
if not email:
raise ValueError('Users must have an email address')
user = self.model(
email=self.normalize_email(email),
date_of_birth=date_of_birth,
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, date_of_birth, password):
"""
Creates and saves a superuser with the given email, date of
birth and password.
"""
user = self.create_user(
email,
password=password,
date_of_birth=date_of_birth,
)
user.is_admin = True
user.save(using=self._db)
return user
class MyUser(AbstractBaseUser):
email = models.EmailField(
verbose_name='email address',
max_length=255,
unique=True,
)
date_of_birth = models.DateField()
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
objects = MyUserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['date_of_birth']
def get_full_name(self):
# The user is identified by their email address
return self.email
def get_short_name(self):
# The user is identified by their email address
return self.email
def __str__(self): # __unicode__ on Python 2
return self.email
def has_perm(self, perm, obj=None):
"Does the user have a specific permission?"
# Simplest possible answer: Yes, always
return True
def has_module_perms(self, app_label):
"Does the user have permissions to view the app `app_label`?"
# Simplest possible answer: Yes, always
return True
@property
def is_staff(self):
"Is the user a member of staff?"
# Simplest possible answer: All admins are staff
return self.is_admin
Then, to register this custom User model with Django's admin, the following
code would be required in the app's admin.py file:
from django import forms
from django.contrib import admin
from django.contrib.auth.models import Group
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.contrib.auth.forms import ReadOnlyPasswordHashField
from customauth.models import MyUser
class UserCreationForm(forms.ModelForm):
"""A form for creating new users. Includes all the required
fields, plus a repeated password."""
password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
class Meta:
model = MyUser
fields = ('email', 'date_of_birth')
def clean_password2(self):
# Check that the two password entries match
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError("Passwords don't match")
return password2
def save(self, commit=True):
# Save the provided password in hashed format
user = super(UserCreationForm, self).save(commit=False)
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
return user
class UserChangeForm(forms.ModelForm):
"""A form for updating users. Includes all the fields on
the user, but replaces the password field with admin's
password hash display field.
"""
password = ReadOnlyPasswordHashField()
class Meta:
model = MyUser
fields = ('email', 'password', 'date_of_birth', 'is_active', 'is_admin')
def clean_password(self):
# Regardless of what the user provides, return the initial value.
# This is done here, rather than on the field, because the
# field does not have access to the initial value
return self.initial["password"]
class UserAdmin(BaseUserAdmin):
# The forms to add and change user instances
form = UserChangeForm
add_form = UserCreationForm
# The fields to be used in displaying the User model.
# These override the definitions on the base UserAdmin
# that reference specific fields on auth.User.
list_display = ('email', 'date_of_birth', 'is_admin')
list_filter = ('is_admin',)
fieldsets = (
(None, {'fields': ('email', 'password')}),
('Personal info', {'fields': ('date_of_birth',)}),
('Permissions', {'fields': ('is_admin',)}),
)
# add_fieldsets is not a standard ModelAdmin attribute. UserAdmin
# overrides get_fieldsets to use this attribute when creating a user.
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('email', 'date_of_birth', 'password1', 'password2')}
),
)
search_fields = ('email',)
ordering = ('email',)
filter_horizontal = ()
# Now register the new UserAdmin...
admin.site.register(MyUser, UserAdmin)
# ... and, since we're not using Django's built-in permissions,
# unregister the Group model from admin.
admin.site.unregister(Group)
Finally, specify the custom model as the default user model for your project
using the AUTH_USER_MODEL setting in your settings.py:
AUTH_USER_MODEL = 'customauth.MyUser'