Django Admin
————————个人的一些doc摘录
Composition
- accounts
- permission
- group
- cookie-based user sessions
Auth system handles:
- Authtication
- verify who the user is
- Authorization
- determine what an authenticated user is allowed to manipulate
COMPOSITION
- Users
- Permission: binary flag to dertermine wether a user is able to perform a task
- Groups: apply label and permission to some uses in common
- Password hashing system
- Form and view system
- Pluggbale backend system
USER
User Objects
- username
- password
- first_name
- last_name
Create Users
>>> from django.contrib.auth.models import User
>>> user = User.objects.create_user('tree', 'tree@inad.com', 'password')
# At this point, user is a User object that has already been saved
# to the database. You can continue to change its attributes
# if you want to change other fields.
>>> user.last_name = 'Lennon'
>>> user.save()
Create Superusers
python manage.py createsuperuser --username=Tree --emial=shuwei@inad.com
The admin site is designed to utilze by superuser.
Change Password
In user model, django does not store raw password but hash. So there are two ways to manipulate:
-
python manage.py changepassword 'username' <new password>
You will be asked to enter twice, the new password established if matched. If a username is not provided, django will attempt to change password of the current user.
- *
from django.contrib.auth import User
u = User.objects.get(username='Tree')
u.set_password('123')
u.save()
Changing a user’s password will log out all their sessions if the SessionAuthenticationMiddleware is enabled.
Authenticaing Users
from django.contrib.auth import authenticate
user = authenticate(username='tree', password='secret')
if user is not None:
# the password verified for the user
if user.is_active:
print("User is valid, active and authenticated")
else:
print("The password is valid, but the account has been disabled!")
else:
# the authentication system was unable to verify the username and password
print("The username and password were incorrect.")
Django tries authenticating across all of its authentication backends. If the first authentication method fails, he tries the second one, and so on, until all backends have been attempted.
Permission & Authorization
User object have two many-to-many fields: groups and user_permissions
request.user
attribute is used in every request to represent the current.
if request.user.is_authenticated():
# Do something for authenticated users.
else:
# Do something for anonymous users.
How to log a user in
login() function takes a HttprRequest and a User object.
from django.contrib.auth import authenticate, login
def my_view(request):
username = request.POST['username']
password = request.POST['password']
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
login(request, user)
# Redirect to a success page.
else:
# Return a 'disabled account' error message
else:
# Return an 'invalid login' error message.
When you’re manually logging a user in, you must call authenticate() before you call login().
How to log a user out
from django.contrib.auth import logout
def logout_view(request):
logout(request)
# Redirect to a success page.
All session data will be cleaned out immediately.
Userful Decorators
@login_required
- If the user isn’t logged in, redirect to LOGIN_URL, passing the current absolute path in the query string. Example: /accounts/login/?next=/reviews/3/.
- If the user is logged in, execute the view normally. The view code is free to assume the user is logged in.
By default, the path that the user should be redirected to upon successful authentication is stored in a query string parameter called “next”. If you would prefer to use a different name for this parameter, login_required() takes an optional redirect_field_name parameter: @login_required(login_url='/accounts/login/')
The login_required decorator does NOT check the is_active flag on a user.
@user_pass_test
To limit access based on certain permissions or some other test:
from django.contrib.auth.decorators import user_passes_test
def email_check(user):
return user.email.endswith('@example.com')
@user_passes_test(email_check)
def my_view(request):
...
user_passes_test() optional arguments:login_url
Lets you specify the URL that users who don’t pass the test will be redirected to. It may be a login page and defaults to LOGIN_URL if you don’t specify one.
@permission_required
It’s a relatively common task to check whether a user has a particular permission and takes a . like positional argument.
from django.contrib.auth.decorators import permission_required
@permission_required('reviews.can_vote', login_url='/loginpage/')
def my_view(request):
...
Extending user model
- Scene 1
from django.conf import settings
from django.db import models
class Myclass(models.Model)
owner = models.onetoonefield(settings.AUTH_USER_MODEL)
- Scene 2
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import User
from app.models import Employee
# Define an inline admin descriptor for Employee model
class EmployeeInline(admin.StackedInline):
model = Employee
# Define a new User admin
class UserAdmin(UserAdmin):
inlines = (EmployeeInline, )
# Re-register UserAdmin
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
In this case, when a User object is created, use ‘django.db.models.signals.post_save’ to update the related model at the same time.
Custom User Model
from django.contrib.auth.models import AbstractUser
from django.db import models
class MyUser(AbstractUser):
name = models.CharField()
in settings:
AUTH_USER_MODEL = 'app.MyUser'
Changing AUTH_USER_MODEL has a big effect on your database structure. It changes the tables that are available, and it will affect the construction of foreign keys and many-to-many relationships. If you intend to set AUTH_USER_MODEL, you should set it before creating any migrations or running manage.py migrate for the first time.
Custom authentication backend
from django.conf import settings
from django.contrib.auth.models import User, check_password
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 = 'sha1$4e987$afbcf42e21bd417fb71db8c66b321e9fc33051de'
"""
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
Then we can handle custom authorization in this backend:
class SettingsBackend(object):
...
def has_perm(self, user_obj, perm, obj=None):
if user_obj.username == settings.ADMIN_LOGIN:
return True
else:
return False
Custom permission
To create custom permissions for a given model object, use the permissions model Meta attribute.
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"),
)
The only thing this does is create those extra permissions when you run manage.py migrate.
The following checks if a user may view tasks:
user.has_perm('app.view_task')
TIPS
It is not worth to heavily customize the Django admin. It is desifned for administrators not end users.
You can give your models custom permissions that can be checked through Django’s authorization system.
You can extend the default User model, or substitute a completely customized model.