37. Django structure, Security, ...
September, 2020
home
Contents
01. package, folder, file, module, function
- A demo is used to help better understanding the above five.
- The demo is to create a local python package.
- The following are the steps and code
1. Create a new folder named MyApp.
2. Inside MyApp, create a subfolder with the name 'mypackage'.
3. Create an empty __init__.py file in the mypackage folder
4. under mypackage, create a python file, myfunctions
def sum(x,y):
return x+y
def average(x,y):
return (x+y)/2
def power(x,y):
return x**y
5. in the terminal, MyApp > python
6. >>> from mypackage import functions
7. >>> power(3,2)
8. >>> 9
comments
- A package is built from a folder.
- myfunctions is a file in the explorer, it is a module in python code.
- power is a python function.
02. folder, file, class, as_views()
sample code snippet-1 is as below:
from .models import Post
- A dot means current folder, like folder blogs
- models.py is a file name; models is module name in python code.
- Post is a class name, it is defined in module models.
sample code snippet-2 is as below:
from .views import BlogListView
- A dot means current folder, like folder views
- models.py is a file name; models is module name in python code.
- BlogListView is a class name, it is defined in module views.
sample code snippet-3 is as below:
path('', HomePageView.as_view(), name='home')
- in some urls.py
- The function, as_view makes the class as a HTTP callable function:
- handle events
- get a http request
- return a http response
03. six built-in Django apps
- In setting.py, you can see six built-in Django app.
- They are admin, auth, session...
- If you use one admin page, it is from admin app.
- Sometimes, you forget using migratecommand, you will get some issue from session.
- In a typical your application, you can create a superuser,
- find a html file, add the following code with html tag
- {{user.username}}
- {{user.is_authenticated}}
- create a superuser. Using the admin, there is at least one is authed for testing.
- test the content html page, you'll see the username, and True-False result.
- These are from built-in auth app.
- From the perspective of enclosing, apps are the parts.
- If they are not built-in, installing are required.
- Python is a interpreting language. During the runtime, the machine code are created.
04. Using built-in auth for authentication
- My learning is from book Django for Beginners, chapter 7
- The module is django.contrib.auth
- ------Log In -------------------
- path in urls.py is needed.
- path('accounts/', include('django.contrib.auth.urls')),
- A html file is needed in templates/registration folder
- Code a html form, the template code is {{form.as_p}}, form object is from its default view.
- When you submit the form, the web site will redirect a page.
- ------Log Out, -------------------
- In the home html, add a log out link, like {% url 'logout' %}
- No html form.
- When you the link, the web site will redirect a page.
- ------ Sign Up -------------
- Create an app for signup, and its urls.py
- A app, and your view is needed.
-
class SignUpView(generic.CreateView):
form_class = UserCreationForm
success_url = reverse_lazy('login')
template_name = 'signup.html'
- A html file is needed.
- When you button for signup the form, the web site will redirect a page.
05. Using Custom User Model for authentication
- My learning is from book Django for Beginners, chapter 8 and chapter 9
- To begin with, add one additional field in User Model. It is age.
- Create a new project, users.
- In settings.py, add it, and add AUTH_USER_MODEL = 'users.CustomUser'
- Add this field in models.py
- In users/forms.py, create two forms for create and update.
- users/admin.py, use the two forms for custom admin, register it.
- Module django.contrib.auth takes care of login, logout.
- Module user takes care of signup for the additonal field.
- The class SignUpView provides the form with the additional field.
06. Mixins for Permsissions and authorizations
lab
- ------- initial setup -------
- Drag and drop the Github download file, djangoforbeginners-master, chapter 14 into code vs.
- pipenv installdjango==2.2.0, pipenv shell,python manage.py migrate
- python manage.py createsuperuser
- python manage.py runserver
- 127.0.0.1:8000/admin/, add one article, one user
- -------- home page, app pages------------
- 127.0.0.1:8000/, see the home page
- in settings.py, path('', include('pages.urls')),
- in pages.urls, path('', views.HomePageView.as_view(), name='home'),
- app pages is used in previous demo.
- In home.html, {% extends 'base.html' %}
- The links for login and logout, their views are from built-in auth.
- They do not use mixin for auth.
- ---------- mixin ----------------->
- In view classes, mixin means multiple inheritances, because of different contexts - security, contents.
- ---------- LoginRequiredMixin -------------------
- continue lab, log out
- 127.0.0.1:8000/, see the home page. click the link, View All Articles.
- Redirect to login page, Because the auth is required.
- the related code in article/views.py as below:
from django.contrib.auth.mixins import LoginRequiredMixin,
class ArticleListView(LoginRequiredMixin, ListView):
model = Article
template_name = 'article_list.html'
login_url = 'login'
- After you login, redirect the page to the list page.
- The same are for pages - detail, update, delete.
- ------------ UserPassesTestMixin for Permission -------------
- Only the author of an article has the permission to update or delete this article.
class ArticleUpdateView(LoginRequiredMixin, UserPassesTestMixin, UpdateView):
model = Article
fields = ('title', 'body',)
template_name = 'article_edit.html'
login_url = 'login'
def test_func(self):
obj = self.get_object()
return obj.author == self.request.user
- Class UserPassesTestMixin provides a method test-func.
- Class ArticleUpdateView overrides it.
- If the author of the article is not the page request user, return False.
- Error 403 Forbbidden will be thrown.
- Otherwise, the update will be ok.
- The same is for delete
- test as below:
- The author of article 1 is peter.
- login as another authed user. Browse the list page.
- click the edit button for article 1, redirect to an error page with message 403 Forbidden.
07. Setting model data in the code of some view class, not from user input
- The typical example is to set the author of an article from the user to create the article.
- continue the previous lab.
# articles/views.py
...
class ArticleCreateView(CreateView):
model = Article
template_name = 'article_new.html'
fields = ('title', 'body')
#print(form)
def form_valid(self, form):
#print(form)
form.instance.author = self.request.user
return super().form_valid(form)
lab
- login
- 127.0.0.1:8000/, home page
- On the top menu, click new to create new article
- The form shows up. Then enter data, click save.
- Then, method form_valid will be called.
- It is not called from the view class.
- After returning to the caller, the new will be save, and redirect.
- Utility print method is used to see more, like print(form) outside the function or inside.
- You can see the content in your terminal window.
- print(form) statement outside the function:
- When the server starts, class ArticleCreateView will be created, listening for any request.
- in the terminal, you see "NameError: name 'form' is not defined"
- print(form) statement outside the function:
- comment it out.
- put it inside the function, save code
- run again, you see a table with many rows are created.
- It is called a form, without submit button.
- Thers is no need for a button. It is all automatic.
- Just follow the sample code.
08. BasicAuthentication and Review on REST web service
--------------------- Review on REST web service--------
- If django frame is added, there will be no templates folder for html files.
- These websites are for rest web service, not monolithic website.
- All the urls are called endpoints.
- Django framework will provide pages for all the endpoints in any browser as bonus. It is called browsable API.
--------------------- BasicAuthentication -------------
# in settings.py
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': [
...,
],
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.BasicAuthentication'
],
}
- When a client makes an HTTP request, the client authenticates with its credentials (username/password).
- and then receives a session ID from the server.
- SessionAuthentication is needed for Default and Token, passing the credentials.
- For BasicAuthentication, the crendential are not encrypted. HTTPS is better.
09. Permissions on REST web service
continue from 08, BasicAuthentication
# in settings.py
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
],
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.BasicAuthentication'
],
}
#posts/permissions.py
from rest_framework import permissions
class IsAuthorOrReadOnly(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
# Read-only permissions are allowed for any request
if request.method in permissions.SAFE_METHODS:
print('location x620')
#print(request.user)
#print(request.user == '')
print('user is ' + str(request.user))
if (str(request.user) == 'AnonymousUser'):
print("location y")
return False
else:
return True
# Write permissions are only allowed to the author of a post
return obj.author == request.user
- The custom permission - update or delete for a post is only for the author.
- for see a post, it is ok without additional auth check.
- The method has_object_permission must has the higher execution precedence.
10. TokenAuthentication on REST web service
------ 10.1 initial setup for lab ------
- create a folder, cloned from the folder for topic 9.
- The following are for the starting point:
- for rest api
- Permissions for viewing the list and details required auth.
- BasicAuthentication
- permissions for update and delete is only for the author.
- pipenv install django==2.2.0 pipenv shell
- python manage.py runserver
- 127.0.0.1:8000/admin, login admin, no section Tokens
- from urls.py file, path('api-auth/', include('rest_framework.urls')),
- Login and logout provided by BasicAuth are from views in rest_framework.
------ 10.2 Adding app rest_framework.authtoken ------
- in the settings.py, add the app as below:
- 'rest_framework.authtoken',
- save, python manage.py makemigrations,python manage.py migrate
- test again.... in /admin/
- see section Tokens
------ 10.3 Installing django-rest-auth and adding ------
- pipenv install django-rest-auth==0.9.5
- in the settings.py, add the app as below:
- 'rest_auth',
- save, python manage.py makemigrations,python manage.py migrate
- in urls.py in the project folder, add code as below:
- path('api/v1/rest-auth/', include('rest_auth.urls')),
- for token auth
- Using admin, add a user, joe
- in the browser, type 127.0.0.1:8000/api/v1/rest-auth/login/, enter joe
- Browse the list page and detail pages.
- type 127.0.0.1:8000/api/v1/rest-auth/logout/
- Using admin, see a token is created for joe.
- From the above, it is clear that token auth is applied.
- In settings.py, change BasicAuthentication to TokenAuthentication.
- It must be for documentation purpose.
------ 10.4 user registration ------
- App rest_auth also provides user signup feature.
- One additional package is needed for this purpose.
- pipenv install django-allauth==0.38.0
- in settings.py, add 5 more apps and add two more lines as below:
- 'django.contrib.sites',
- 'allauth',
- 'allauth.account',
- 'allauth.socialaccount',
- 'rest_auth.registration',
- EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
- SITE_ID = 1
- add one path in urls.py of the project folder.
- path('api/v1/rest-auth/registration/', include('rest_auth.registration.urls')),
- save codes, start the server.
- in my browser, enter 127.0.0.1:8000/api/v1/rest-auth/registration/
- enter a user.
- login with the new user...