1 Permission management model design
1.1 create app
Create an APP named System, which contains basic system modules such as user management, menu management and permission management.
- Open our project using PyCharm, right-click the project root directory and select New → Python Package. In the window that pops up, type Apps. This Package will be used to store all apps created in the project.
- Select Tools above Pycharm and click Run Manage.py Task… , a window will open below PyCharm, enter StartApp System and press Enter to create app, as shown below:
- Move the system you just created to apps
- To access our new app, right-click apps and choose Mark Directory as → Sources root
- Modify sandboxMP sandboxMP/Settings. Py to join the following:
import sys
sys.path.insert(0, os.path.join(BASE_DIR, 'apps'))
Copy the code
1.2 Creating a Permission Authentication Model
SandboxMP project uses a custom permission authentication model, which is described as follows:
Menu: Menu management, used for storage system available URL Role: Role group: Associate the foreign key with Menu. Users in the Role group inherit the access permission of the Role association Menu. Structure: Organizational Structure, including unit and department information UserProfile: Replaces the original User modelCopy the code
Here are the model details for permission authentication, copied to apps/ System /models.py
from django.db import models
from django.contrib.auth.models import AbstractUser
class Menu(models.Model):
"""Menu"""
name = models.CharField(max_length=30, unique=True, verbose_name="Menu name") # unique=True, this field must have a unique value in the table.
parent = models.ForeignKey("self", null=True, blank=True, on_delete=models.SET_NULL, verbose_name="Parent menu")
icon = models.CharField(max_length=50, null=True, blank=True, verbose_name="Icon")
code = models.CharField(max_length=50, null=True, blank=True, verbose_name="Code")
url = models.CharField(max_length=128, unique=True, null=True, blank=True)
def __str__(self):
return self.name
class Meta:
verbose_name = 'menu'
verbose_name_plural = verbose_name
@classmethod
def get_menu_by_request_url(cls, url):
return dict(menu=Menu.objects.get(url=url))
class Role(models.Model):
"""Role: For permission binding"""
name = models.CharField(max_length=32, unique=True, verbose_name="Role")
permissions = models.ManyToManyField("menu", blank=True, verbose_name="URL authorization")
desc = models.CharField(max_length=50, blank=True, null=True, verbose_name="Description")
class Structure(models.Model):
"""Organizational Structure"""
type_choices = (("unit"."Unit"), ("department"."Department"))
name = models.CharField(max_length=60, verbose_name="Name")
type = models.CharField(max_length=20, choices=type_choices, default="department", verbose_name="Type")
parent = models.ForeignKey("self", null=True, blank=True, on_delete=models.SET_NULL, verbose_name="Superclass schema")
class Meta:
verbose_name = "Organizational Structure"
verbose_name_plural = verbose_name
def __str__(self):
return self.name
class UserProfile(AbstractUser):
name = models.CharField(max_length=20, default="", verbose_name="Name")
birthday = models.DateField(null=True, blank=True, verbose_name="Date of birth")
gender = models.CharField(max_length=10, choices=(("male"."Male"), ("female"."Female")),
default="male", verbose_name="Gender")
mobile = models.CharField(max_length=11, default="", verbose_name="Mobile phone number")
email = models.EmailField(max_length=50, verbose_name="Email")
image = models.ImageField(upload_to="image/%Y/%m", default="image/default.jpg",
max_length=100, null=True, blank=True)
department = models.ForeignKey("Structure", null=True, blank=True, on_delete=models.SET_NULL, verbose_name="Department")
post = models.CharField(max_length=50, null=True, blank=True, verbose_name="Position")
superior = models.ForeignKey("self", null=True, blank=True, on_delete=models.SET_NULL, verbose_name="Superior supervisor")
roles = models.ManyToManyField("role", verbose_name="Role", blank=True)
class Meta:
verbose_name = "User Information"
verbose_name_plural = verbose_name
ordering = ['id']
def __str__(self):
return self.name
Copy the code
1.3 Using the Model
After defining the models, and telling Django to use them, we need to modify settings.py and add the name of the application where models.py is located to INSTALLED_APPS:
INSTALLED_APPS = [...'system',]Copy the code
To use the custom authentication model UserProfile, add the following to setting.py:
AUTH_USER_MODEL = 'system.UserProfile'
Copy the code
Var ImageField = ImageField (x, X, x); Var ImageField = ImageField (x, X, x);
C:\Users\RobbieHan>workon sandboxMP
(sandboxMP) C:\Users\RobbieHan>pip install pillow
Copy the code
You can also run the installation command PIP Install Pillow from the Terminal window of PyCharm
Finally, execute Names, Hoisting and Migrate to generate the table, use Pycharm Tools, and click Run Manage.py Task… In the manage.py window, enter the following command:
makemigrations
migrate
Copy the code
1.4 Knowledge points related to Models
Field type:
The fields used in the permission authentication model are as follows:
CharField: is used to store strings, and a parameter max_length must be specified to limit the maximum length of the field Foreignkey: is an association field, to create a many-to-one relationship between multiple tables, you can use models. Foreignkey ('self') ManyToManyField: EmailField: email field, which is used to check whether the email address is valid. ImageField: ImageField, which is used to define image uploading and image checking. The pillow library is requiredCopy the code
Field options:
Verbose_name: blank: if set to True, this field must have a unique value. This enforces the data to be unique at the database level. The default value is False, and if True, this field is allowed to be null: The default value is False. If True, Django will dump the null value into the database as NULL Choices: is an iterable structure. The first element in each tuple is the value stored in the database. The second element is an easy-to-understand description.Copy the code
On_delete: before django2.0, the on_delete option is not required when defining associated fields. After django2.0, the on_delete option is required when defining associated fields. The common parameters are as follows:
on_delete=models.CASCADE, Delete the associated data and delete the association with it
on_delete=models.DO_NOTHING, Delete associated data and do nothing
on_delete=models.PROTECT, Error ProtectedError is raised when associated data is deleted
on_delete=models.SET_NULL, Delete the associated data and set the associated value to NULL
on_delete=models.SET_DEFAULT, Delete associated data and set the associated value to the default value
Copy the code
Note that when using SET_NULL, this field needs to be set to null when the model is defined. For example:
user = models.ForeignKey(User, on_delete=models.SET_NULL, blank=True, null=True)
Copy the code
When using SET_DEFAULT, you need to define default:
user = models.ForeignKey(User, on_delete=models.SET_DEFAULT, default='Default value')
Copy the code
More field type and options, please reference: docs.djangoproject.com/en/1.11/ref…
2 User authentication and access restrictions
User login authentication requirements are as follows:
- Users log in to access certain pages,
- If the user is not logged in and accesses it directly, it will jump to the login screen,
- After the user completes login in the login interface, the user will automatically access the previously accessed address.
- Users can use user names, mobile phone numbers, or other fields as login user names.
In Pycharm, select sandboxMP/apps/ System, right-click and select New → Python File. In the window that is displayed, enter the name views_user and import the required module in the page that you have just created:
from django.shortcuts import render
from django.views.generic.base import View
from django.http import HttpResponseRedirect
from django.contrib.auth import authenticate, login, logout
from django.urls import reverse
Copy the code
Description: create the following view, are written in the book of sandboxMP/apps/system/views_user. Py file
2.1 Creating the Index Page View
The index page view is the first view created in this project:
class IndexView(View):
def get(self, request):
return render(request, 'index.html')
Copy the code
Introduction:
Views: The official Django documentation describes “views” as a way to encapsulate the logic that handles a user’s request and returns a response. We can define view functions to accept Web requests and return Web responses, or we can use class-based view objects. The view implementation of this project is based on class-based views. Compared with function-based views, there are certain differences and advantages:
- You can write code related to HTTP methods (GET, POST, and so on) in a separate way, without having to judge HTTP methods through conditional branching
- Decompose code into reusable components, such as mixins (multiple inheritance), which take advantage of object-oriented technology and are more flexible to use and easy to extend
Render function: a Django shortcut function that combines a given template with a given context dictionary and returns an selected HttpRespose object. Render (request, template_name, context=None, content_type=None, status=None, using=None) render(request, template_name, context=None, content_type=None, status=None, using=None) Other parameters are optional.
2.2 Creating a User Login View
Before creating the user login view, first create a sandboxMP/apps/system/forms. Py files, used for land user input validation, content is as follows:
from django import forms
class LoginForm(forms.Form):
username = forms.CharField(required=True, error_messages={"requeired": "Please fill in user name"})
password = forms.CharField(required=True, error_messages={"requeired": "Please fill in your password."})
Copy the code
Create user login view:
from .forms import LoginForm
class LoginView(View):
def get(self, request):
if not request.user.is_authenticated:
return render(request, 'system/users/login.html')
else:
return HttpResponseRedirect('/')
def post(self, request):
redirect_to = request.GET.get('next'.'/')
login_form = LoginForm(request.POST)
ret = dict(login_form=login_form)
if login_form.is_valid():
user_name = request.POST['username']
pass_word = request.POST['password']
user = authenticate(username=user_name, password=pass_word)
if user is not None:
if user.is_active:
login(request, user)
return HttpResponseRedirect(redirect_to)
else:
ret['msg'] = 'User not active! '
else:
ret['msg'] = 'Wrong username or password! '
else:
ret['msg'] = 'User and password cannot be empty! '
return render(request, 'system/users/login.html', ret)
Copy the code
Django uses sessions and middleware to intercept request objects in authentication systems. They provide a request.user attribute on each request, representing the current user. If the current User is not logged in, this property will be set to an instance of AnonymousUser, otherwise it will be a User instance. Request.user. is_authenticated: Used to check whether users are logged in, such as LoginView:
# When the user visits the login page, judge that if the user does not log in, he/she will visit the login page, if logged in, he/she will jump to the home page
if not request.user.is_authenticated:
return render(request, 'system/users/login.html')
else:
return HttpResponseRedirect('/')
Copy the code
Is_valid (): a method of the Form power that does field validation and returns True if the input field value is valid and stores the Form data into the cleaned_data property. Authenticate (request=None, **credentials): Authenticate users. The credentials are keyword parameters. The default values are username and password. 4. Login (request, user, backend=None): used to login to a user from the view and store the user ID in the session table. Note: You must authenticate the user successfully using authenticate() before calling login(). HttpResponseRedirect[source]: HttpResponseRedirect[source]: HttpResponseRedirect[source]: HttpResponseRedirect[source]: HttpResponseRedirect[source]: HttpResponseRedirect[source]: HttpResponseRedirect[source]
2.3 Creating a User Logout View
class LogoutView(View):
def get(self, request):
logout(request)
return HttpResponseRedirect(reverse('login'))
Copy the code
Logout (request): Logout of a user. 2. Reverse (viewName): Performs reverse url parsing based on the URL name.
2.4 Configuring URL Routing for Users
Want to through the URL to access the view application, also need to configure the URL routing, modify sandboxMP sandboxMP/urls. Py:
from django.contrib import admin
from django.urls import path
from system.views_user import IndexView, LoginView, LogoutView
urlpatterns = [
path('admin/', admin.site.urls),
path(' ', IndexView.as_view(), name='index'),
path('login/', LoginView.as_view(), name='login'),
path('logout/', LogoutView.as_view(), name='logout'),]Copy the code
2.5 Creating An Authentication User
Select Tools in Pycharm and click Run manage.py Task… , enter createsuperuser in the open window, and enter the user name, email address, and password as prompted. The procedure is as follows:
manage.py@sandboxMP > createsuperuser
"C: \ Program Files \ JetBrains \ PyCharm2017.3.2 \ bin \ runnerw exe" C:\Users\RobbieHan\Envs\sandboxMP\Scripts\python.exe "C: \ Program Files \ JetBrains \ PyCharm2017.3.2 \ helpers \ pycharm \ django_manage py." "Createsuperuser D:/ProjectFile/sandboxMP User name: admin Email: [email protected] Warning: Password input may be echoed. Password: ! qaz@wsx Warning: Password input may be echoed. Password (again): ! qaz@wsx Superuser created successfully.Copy the code
Run the project and access the system: http://127.0.0.1:8000. We have no login user and can directly access the home page, which is inconsistent with our requirements. Next, implement page access restrictions that require logged-in users to access.
2.6 Page Access Restrictions
Implementation requirements for page access restrictions:
- Users can access certain pages only after logging in to the system
- If the user does not log in and accesses directly, the login screen will be redirected
- After a user logs in to the login page, the login address before the login page is automatically accessed
New sandboxMP/apps/system/mixins. Py, write the following content:
from django.contrib.auth.decorators import login_required
class LoginRequiredMixin(object):
@classmethod
def as_view(cls, **init_kwargs):
view = super(LoginRequiredMixin, cls).as_view(**init_kwargs)
return login_required(view)
Copy the code
Modify sandboxMP sandboxMP/Settings. Py, join LOGIN_URL
LOGIN_URL = '/login/'
Copy the code
LoginRequiredMixin: LoginRequiredMixin: LoginRequiredMixin: LoginRequiredMixin: LoginRequiredMixin: LoginRequiredMixin
from .mixin import LoginRequiredMixin
class IndexView(LoginRequiredMixin, View):
def get(self, request):
return render(request, 'index.html')
Copy the code
Note: LoginRequiredMixin is at the far left of the inheritance list
Restart the program, we visit the home page again, open a browser, type http://127.0.0.1:8000, then we will find that the browser URL will be: http://127.0.0.1:8000/login/? Next =/, we need to log in before jumping to the home page. Use the user we created in Section 2.5: admin, password:! qaz@wsx Login system
2.7 Access to media Files
Although the default profile picture is set when creating a user and the image used by the default profile picture is placed, the profile picture cannot be displayed after the user logs in. Therefore, you need to configure media file access.
A media file is a file uploaded by the user. The path of the file is changed, for example, the profile picture file uploaded by the user. Example Set the file upload directory
Modify sandboxMP sandboxMP/Settings. Py file, add the following configuration:
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
Copy the code
Open the sandboxMP sandboxMP/urls. Py, add the following configuration:
from django.conf import settings
from django.urls import re_path
from django.views.static import serve
if settings.DEBUG:
urlpatterns += [
re_path(r'^media/(? P
.*)$'
, serve, {"document_root": settings.MEDIA_ROOT}),
]
Copy the code
Refresh the page to see the user’s avatar. Note that if settings.debug is used because this configuration mode should only be used in development mode, and access to these media files should be handled through a Web front end in production.
The latest and most complete document is published in knowledge planet, you can search the public account “knowledge planet” through wechat, directly reply to “52824366” to get access to this section of the document corresponding source version: github.com/RobbieHan/s…
Very welcome interested friends, to my Github or nuggets guest, spare time to give a “like” or “Star,” gift rose hand left lingering incense document supporting project address: github.com/RobbieHan/s… Lightweight office management system project open source address: github.com/RobbieHan/g…