咱們在開發一個網站的時候,無可避免的須要設計實現網站的用戶系統。此時咱們須要實現包括用戶註冊,登陸,用戶認證,註銷,修改密碼等功能。Django做爲一個完美主義者的終極框架,固然也會想到用戶的這些痛點,它內置了強大的用戶認證系——auth,因此本文在不創建User模型的狀況下實現用戶的註冊,登陸和認證。另外對Django Auth自帶的User模型進行擴展,運行用戶添加更多的我的信息。css
我在以前的Django學習筆記(9)——開發用戶註冊與登陸系統 中已經完成了這個註冊與登陸系統,那麼下面在這裏寫主要是向基於Django自帶的User模型從新創建本身用戶的模型。html
咱們用Django2.0開發一個叫users的APP,來實現如下六項功能:前端
因爲Django Auth自帶的User模型字段有限,咱們還須要自定義模型UserProfile對其擴展。html5
(Auth組件的相關內容能夠參考:Django學習筆記(13)——Django的用戶認證組件,視圖層和QuerySet API)python
首先咱們看一下Django Auth模塊自帶User模型所包含字段:jquery
username:用戶名 email: 電子郵件 password:密碼 first_name:名 last_name:姓 is_active: 是否爲活躍用戶。默認是True is_staff: 是否爲員工。默認是False is_superuser: 是否爲管理員。默認是False date_joined: 加入日期。系統自動生成。
下面展現咱們自定義的UserProfile模型git
user: 與User是1對1關係 org:用戶名 telephone: 電話 mod_date: 最後修改日期。系統自動生成
整個用戶註冊和登陸很是簡單,好比沒有郵箱驗證,也不能經過第三方APP受權登陸,我作的頁面也比較醜陋、一個更好的方式是使用以及成熟的第三方Django Package(好比django-allauth)來實現用戶註冊和登陸。程序員
編碼規範需求: 1. 代碼規範遵照pep8 (https://python.org/dev/peps/pep-0008/) 2. 函數有相應的註釋 3. 程序有文檔說明文件(README.md) 4. 程序的說明文檔必須包含的內容:程序的開發環境(django版本)、程序的實 現的功能、程序的啓動方式、登陸用戶信息、程序的運行效果 5. 程序設計的流程圖:
基本的項目開啓什麼的都在這裏再也不闡述了,我直接寫項目的主要思路,基礎的Django操做流程看我以前的博客就行。github
到目前爲止,我學習Django,第一步都是建立模型。爲何呢?由於大多數語言都遵循軟件開發的設計模式MVC。數據庫
這裏咱們創建一個名稱爲UserProfile的模型,代碼以下:
from django.db import models # Create your models here. from django.contrib.auth.models import User class UserProfile(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile') # 模型類中設置:blank=True,表示代碼中建立數據庫記錄時該字段可傳空白(空串,空字符串) org = models.CharField('Organization', max_length=128, blank=True) telephone = models.CharField('Telephone', max_length=50, blank=True) mod_data = models.DateTimeField('Last modified', auto_now=True) class Meta: verbose_name = 'User profile' def __str__(self): # return self.user.__str__() return "{}".format(self.user.__str__())
注意:咱們並沒改變Django Auth 自帶的User模型,也沒有創建新的User模型。而UserProfile只是對User模型的擴展。找到users/models.py,並建立上面的UserProfile模型。因爲咱們引入了Django Auth自帶的User模型,因此咱們必須開始先把它import進來。
自定義的UserProfile模型新增字段的意思以下:
user: 與User是1對1關係 org:用戶名 telephone: 電話 mod_date: 最後修改日期。系統自動生成
我比較習慣先寫URL,再寫視圖View,從URL配置上,你應該能夠理解咱們想實現的六個功能。
下面是users/urls.py代碼內容:
from django.urls import re_path, path from users import views app_name = 'users' urlpatterns = [ re_path(r'^register/$', views.register, name='register'), re_path(r'^login/$', views.login, name='login'), re_path(r'^user/(?P<pk>\d+)/profile/$', views.profile, name='profile'), re_path(r'^user/(?P<pk>\d+)/profile/update/$', views.profile_update, name='profile_update'), re_path(r'^user/(?P<pk>\d+)/pwd_change/$', views.pwd_change, name='pwd_change'), re_path(r"^logout/$", views.logout, name='logout'), ]
上面,咱們使用 name= '?' ,好比第一個:咱們這是給動態連接 /register/取了個名字 ‘register’,這樣咱們就能夠在HTML模板裏面經過 {% url 'users:register' %} 來調用這個連接了。
咱們須要編寫六個視圖函數,正如上面url路徑所指。
因爲這六個視圖中,register , login,profile , pwdChange這個四個視圖都須要用到表單,因此咱們先建立表單代碼。
(表單代碼咱們能夠分離出去,在users目錄下建立MyForms.py文件,而後再在裏面建立form表單,最後將其導入視圖函數,這樣代碼顯得工整,清晰,並且後期容易維護。還有MyForms.py能夠經過clean方法自定義表單驗證,很是便捷,並且邏輯更清晰)。
from django import forms from django.contrib.auth.models import User import re def email_check(email): pattern = re.compile(r"\"?([-a-zA-Z0-9.'?{}]+@\w+\.\w+)\"?") return re.match(pattern, email) class RegistrationForm(forms.Form): username = forms.CharField(label='Username', max_length=50) email = forms.EmailField(label='Email') password1 = forms.CharField(label='Password', widget=forms.PasswordInput) password2 = forms.CharField(label='Password Confirmation', widget=forms.PasswordInput) #user clean methods to define custom validation rules def clean_username(self): username = self.cleaned_data.get('username') if len(username) < 3: raise forms.ValidationError("your username must be at least 3 characters log") elif len(username) > 20: raise forms.ValidationError("your username is too long") else: filter_result = User.objects.filter(username__exact=username) if len(filter_result) > 0: raise forms.ValidationError('your username already exists') return username def clean_email(self): email = self.cleaned_data.get('email') if email_check(email): filter_result = User.objects.filter(email__exact=email) if len(filter_result) > 0: raise forms.ValidationError("your email already exists") else: raise forms.ValidationError("Please enter a valid email") return email def clean_password1(self): password1 = self.cleaned_data.get('password1') if len(password1) < 3: raise forms.ValidationError("your password is too short") elif len(password1) > 20: raise forms.ValidationError("your password is too long") return password1 def clean_password2(self): password1 = self.cleaned_data.get('password1') password2 = self.cleaned_data.get('password2') if password1 and password2 and password1 != password2: raise forms.ValidationError('Password mismatch Please enter again') return password2 class LoginForm(forms.Form): username = forms.CharField(label='Username', max_length=50) password = forms.CharField(label='Password', widget=forms.PasswordInput) # use clean methods to define custom validation rules def clean_username(self): username = self.cleaned_data.get('username') if email_check(username): filter_result = User.objects.filter(email__exact=username) if not filter_result: raise forms.ValidationError('This emial does not exist') else: filter_result = User.objects.filter(username__exact=username) if not filter_result: raise forms.ValidationError('This username does not exist Please register first') return username class ProfileForm(forms.Form): first_name = forms.CharField(label='First Name', max_length=50, required=False) last_name = forms.CharField(label='Last Name', max_length=50, required=False) org = forms.CharField(label='Organization', max_length=50, required=False) telephone = forms.CharField(label='Telephone', max_length=50, required=False) class PwdChangeForm(forms.Form): old_password = forms.CharField(label='Old Password', widget=forms.PasswordInput) password1 = forms.CharField(label='New Password', widget=forms.PasswordInput) password2 = forms.CharField(label='Password Confirmation', widget=forms.PasswordInput) # use clean methods to define custom validation rules def clean_password1(self): password1 = self.cleaned_data.get('password1') if len(password1) < 6: raise forms.ValidationError("your password is too short") elif len(password1) > 20: raise forms.ValidationError("your password is too long") return password1 def clean_password2(self): password1 = self.cleaned_data.get('password1') password2 = self.cleaned_data.get('password2') if password1 and password2 and password1 != password2: raise forms.ValidationError("Password mismatch Please enter again") return password2
上面的代碼之因此很是長,是由於咱們用clean方法加入了不少表單驗證項。好比檢查用戶名是否太短,是否過長,是否已經存在等等。
咱們在以前,Django學習筆記(14)——AJAX與Form組件知識補充(局部鉤子和全局鉤子詳解) ,一文中詳細學習了局部鉤子和全局鉤子,也就是clean方法的使用,若是不懂的話能夠先學習這一篇博文。畢竟真實的網站開發都是須要加上這些驗證規則的。
廢話就說這麼多,固然你也能夠在View視圖裏面寫Form驗證規則。隨你。下面直接看個人視圖users/views.py的內容:
from django.shortcuts import render, HttpResponse, get_object_or_404 from .MyForms import RegistrationForm, LoginForm, ProfileForm, PwdChangeForm from .models import UserProfile from django.contrib.auth.models import User from django.http import HttpResponseRedirect from django.contrib import auth from django.urls import reverse from django.contrib.auth.decorators import login_required # Create your views here. @login_required def profile(request, pk): user = get_object_or_404(User, pk=pk) return render(request, 'users/profile.html', {'user': user}) @login_required def profile_update(request, pk): user = get_object_or_404(User, pk=pk) user_profile = get_object_or_404(UserProfile, user=user) if request.method == 'POST': form = ProfileForm(request.POST) if form.is_valid(): user.first_name = form.cleaned_data['first_name'] user.last_name = form.cleaned_data['last_name'] user.save() user_profile.org = form.cleaned_data['org'] user_profile.telephone = form.cleaned_data['telephone'] user_profile.save() return HttpResponseRedirect(reverse('users:profile', args=[user.id])) else: default_data = {'first_name': user.first_name, 'last_name': user.last_name, 'org': user_profile.org, 'telephone': user_profile.telephone,} form = ProfileForm(default_data) return render(request, 'users/profile_update.html', {'form': form, 'user': user}) def register(request): if request.method == 'POST': form = RegistrationForm(request.POST) if form.is_valid(): username = form.cleaned_data['username'] email = form.cleaned_data['email'] password = form.cleaned_data['password2'] # 使用內置User自帶create_user方法建立用戶,不須要使用save() user = User.objects.create_user(username=username, password=password, email=email) # 若是直接使用objects.create()方法後不須要使用save() user_profile = UserProfile(user=user) user_profile.save() return HttpResponseRedirect("/accounts/login/") else: form = RegistrationForm() return render(request, 'users/registration.html', {'form': form}) def login(request): if request.method == 'POST': form = LoginForm(request.POST) if form.is_valid(): username = form.cleaned_data['username'] password = form.cleaned_data['password'] user = auth.authenticate(username=username, password=password) if user is not None and user.is_active: auth.login(request, user) return HttpResponseRedirect(reverse('users:profile', args=[user.id])) else: # 登陸失敗 return render(request, 'users/login.html', {'form': form, 'message':'Wrong password Please Try agagin'}) else: form = LoginForm() return render(request, 'users/login.html', {'form': form}) @login_required def logout(request): auth.logout(request) return HttpResponseRedirect("/accounts/login/") @login_required def pwd_change(request, pk): user = get_object_or_404(User, pk=pk) if request.method == "POST": form = PwdChangeForm(request.POST) if form.is_valid(): password = form.cleaned_data['old_password'] username = user.username user = auth.authenticate(username=username, password=password) if user is not None and user.is_active: new_password = form.cleaned_data['password2'] user.set_password(new_password) user.save() return HttpResponseRedirect('/accounts/login/') else: return render(request, 'users/pwd_change.html', {'form': form, 'user': user, 'message': 'Old password is wrong Try again'}) else: form = PwdChangeForm() return render(request, 'users/pwd_change.html', {'form': form, 'user': user})
下面咱們分別看看幾個視圖函數是如何工做的:
register視圖函數:
login視圖函數:
profile視圖函數:
pwd_change視圖函數:
在users目錄下建立/templates/users/文件夾,編寫HTML模板。其目錄結構以下:
展現一個 login.html 代碼:
{% extends 'base.html' %} {% load staticfiles %} {% block title %}<h1 class="my-con1">Login Page</h1>{% endblock %} {% block css %} <link rel="stylesheet" href="{% static '/CSS/login.css' %}"> {% endblock %} {% block content %} {% if message %} {{ message }} {% endif %} <div class="form-group"> <form method="post" action="" enctype="multipart/form-data"> {% csrf_token %} {% for field in form %} <div class="form-group "> {{ field.errors }} {{ field.label_tag }}{{ field }} {% if field.help_text %} <p class="help">{{ field.help_text|safe }}</p> {% endif %} </div> {% endfor %} <div class="btn"> <input type="submit" value="Login"> </div> </form> <h2 class="my-href pull-right"> <a href="/accounts/register" >Register Link</a> </h2> </div> {% endblock %}
若是你要開發一個好的網站或者網絡應用,你就必須瞭解經典的軟件開發所遵循的MVC設計模式。Django做爲最優秀的基於Python語言的網站開發框架,固然也遵循了這種設計模型。下面就學習一下什麼是MVC框架以及Django網站開發是如何遵循這種軟件開發設計模型的。
MVC是Model-View-Controller(模型-試圖-控制器)模式
若是把MVC比喻成一個糉子,那麼View就是最外面一層的綠色玉米葉,是咱們能夠直接看到的。Controller就是中間那層熟糯米,而糉子的的核心天然然是最裏面的那一層的肉餡Model模型了。
MVC最大的優勢是實現了軟件或網絡應用開發過程當中數據,業務邏輯和界面的分離,使軟件開發更清晰,也是維護變得更容易。這與靜態網頁設計中使用HTML和CSS實現了內容和樣式的分離是同一個道理。
Django網站開發全靠四件套:Model(模型),URL(連接),View(視圖)和Template(模板)。他們看似與MVC設計模式不太一致,其實本質是相同的。可是Django的View和經典的View確實有很是大的不一樣。Django四件套與經典的MVC對應關係以下。
使用Django開發網站的第一步絕對是定義模型(Model),若是寫個不須要使用數據庫的小應用,也徹底能夠不定義模型,直接寫URL和View。固然先寫URL仍是View,其實均可以,徹底取決於我的偏好。通常來講,從上向下思考問題的話,先寫URL。不過不影響。
Django自帶的User Admin 只能編輯管理基礎字段如用戶名和電子郵件。咱們如今但願能擴展User Admin,在編輯 User的同時編輯咱們User Profile 裏的額外字段(如電話)。去實現這個功能,咱們須要按照以下代碼修改 users/admin.py:
from django.contrib import admin from django.contrib.auth.models import User from django.contrib.auth.admin import UserAdmin from .models import UserProfile admin.site.unregister(User) class UserProfileInline(admin.StackedInline): model = UserProfile class UserProfileAdmin(UserAdmin): inlines = [UserProfileInline, ] admin.site.register(User, UserProfileAdmin)
下面是實際效果,咱們會發現UserAdmin後多了一欄 user Profiles。
進入後臺的方法(前提是項目URL等東西要配置好): 1,啓動項目 python manage.py runserver 2,在瀏覽器中打開地址: 127.0.0.1:8000/users/admin
(咱們進入admin後臺,向下拉,會發現)
根目錄下新建一個static目錄,並將其解壓後的Bootstrap-3.3.7目錄,總體拷貝到static目錄中,並且因爲Bootstrap依賴於jQuery,因此咱們須要引入jQuery,而且在static目錄下,新建一個CSS和JS目錄,做爲之後的樣式文件和JS文件的存放地,最後以下圖所示:
而後打開項目的settings文件,在最下面添加配置,用於指定靜態文件的搜索目錄:
STATIC_URL = '/static/' STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'static'), ]
一個網站要有本身的統一風格和公共部分,能夠將這部份內容集中到一個基礎模板 base.html中。如今,在根目錄下的template中建一個 base.html 文件做爲站點的基礎模板。
在Bootstrap文檔中,爲咱們提供了一個很是簡單並且又實用的基礎模板,代碼以下:
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- 上述3個meta標籤*必須*放在最前面,任何其餘內容都*必須*跟隨其後! --> <title>Bootstrap 101 Template</title> <!-- Bootstrap --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" rel="stylesheet"> <!-- HTML5 shim 和 Respond.js 是爲了讓 IE8 支持 HTML5 元素和媒體查詢(media queries)功能 --> <!-- 警告:經過 file:// 協議(就是直接將 html 頁面拖拽到瀏覽器中)訪問頁面時 Respond.js 不起做用 --> <!--[if lt IE 9]> <script src="https://cdn.jsdelivr.net/npm/html5shiv@3.7.3/dist/html5shiv.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/respond.js@1.4.2/dest/respond.min.js"></script> <![endif]--> </head> <body> <h1>你好,世界!</h1> <!-- jQuery (Bootstrap 的全部 JavaScript 插件都依賴 jQuery,因此必須放在前邊) --> <script src="https://cdn.jsdelivr.net/npm/jquery@1.12.4/dist/jquery.min.js"></script> <!-- 加載 Bootstrap 的全部 JavaScript 插件。你也能夠根據須要只加載單個插件。 --> <script src="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/js/bootstrap.min.js"></script> </body> </html>
咱們將其總體拷貝到 base.html文件中。由於咱們將Bootstrap的目錄都拷貝下來了,因此咱們不須要cdn引入,咱們能夠將路徑更改成本地的文件路徑。
更改後的代碼以下:
{% load staticfiles %} <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- 上述3個meta標籤*必須*放在最前面,任何其餘內容都*必須*跟隨其後! --> <!-- Bootstrap --> <link href="/static/bootstrap-3.3.7/dist/css/bootstrap.min.css" rel="stylesheet"> <!-- HTML5 shim 和 Respond.js 是爲了讓 IE8 支持 HTML5 元素和媒體查詢(media queries)功能 --> <!-- 警告:經過 file:// 協議(就是直接將 html 頁面拖拽到瀏覽器中)訪問頁面時 Respond.js 不起做用 --> <!--[if lt IE 9]> <script src="https://cdn.jsdelivr.net/npm/html5shiv@3.7.3/dist/html5shiv.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/respond.js@1.4.2/dest/respond.min.js"></script> <![endif]--> </head> <body> <!-- jQuery (Bootstrap 的全部 JavaScript 插件都依賴 jQuery,因此必須放在前邊) --> <script src="/static/JS/jquery-3.2.1.js"></script> <!-- 加載 Bootstrap 的全部 JavaScript 插件。你也能夠根據須要只加載單個插件。 --> <script src="/static/bootstrap-3.3.7/dist/js/bootstrap.min.js"></script> </body> </html>
注意:Bootstrap的全部JavaScript插件都依賴jQuery,因此必須將jQuery放在前面。
<!-- jQuery (Bootstrap 的全部 JavaScript 插件都依賴 jQuery,因此必須放在前邊) --> <script src="/static/JS/jquery-3.2.1.js"></script> <!-- 加載 Bootstrap 的全部 JavaScript 插件。你也能夠根據須要只加載單個插件。 --> <script src="/static/bootstrap-3.3.7/dist/js/bootstrap.min.js"></script>
{% static ‘相對路徑’ %} 這個Django爲咱們提供的靜態文件加載方法,能夠將頁面與靜態文件連接起來。
{% block title%} AAA {% endblock %} 設置了專門的 title。
經過block css 引入了針對性的 css樣式文件。
更改後的 base.html 內容以下:
{% load staticfiles %} <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- 上述3個meta標籤*必須*放在最前面,任何其餘內容都*必須*跟隨其後! --> {% block title %} <title>base</title> {% endblock %} <!-- Bootstrap --> <link href="/static/bootstrap-3.3.7/dist/css/bootstrap.min.css" rel="stylesheet"> <!-- HTML5 shim 和 Respond.js 是爲了讓 IE8 支持 HTML5 元素和媒體查詢(media queries)功能 --> <!-- 警告:經過 file:// 協議(就是直接將 html 頁面拖拽到瀏覽器中)訪問頁面時 Respond.js 不起做用 --> <!--[if lt IE 9]> <script src="https://cdn.jsdelivr.net/npm/html5shiv@3.7.3/dist/html5shiv.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/respond.js@1.4.2/dest/respond.min.js"></script> <![endif]--> <link rel="stylesheet" href="/static/CSS/base.css"> {% block css %} {% endblock %} </head> <body> <div class="container my-con"> {% block content %} {% endblock %} </div> <!-- jQuery (Bootstrap 的全部 JavaScript 插件都依賴 jQuery,因此必須放在前邊) --> <script src="/static/JS/jquery-3.2.1.js"></script> <!-- 加載 Bootstrap 的全部 JavaScript 插件。你也能夠根據須要只加載單個插件。 --> <script src="/static/bootstrap-3.3.7/dist/js/bootstrap.min.js"></script> </body> </html>
由於有四五個,這裏只舉其中一個例子來講。其餘的大同小異。(注意:個人前端水平有點差,因此頁面不是那麼美觀,見諒見諒啊)
好比登陸頁面,首先咱們繼承 base.html的內容,而後將本身的後端邏輯代碼填入其中,以下:
{% extends 'base.html' %} {% load staticfiles %} {% block title %}<h1 class="my-con1">Login Page</h1>{% endblock %} {% block css %} <link rel="stylesheet" href="{% static '/CSS/login.css' %}"> {% endblock %} {% block content %} {% if message %} {{ message }} {% endif %} <div class="form-group"> <form method="post" action="" enctype="multipart/form-data"> {% csrf_token %} {% for field in form %} <div class="form-group "> {{ field.errors }} {{ field.label_tag }}{{ field }} {% if field.help_text %} <p class="help">{{ field.help_text|safe }}</p> {% endif %} </div> {% endfor %} <div class="btn"> <input type="submit" value="Login"> </div> </form> <h2 class="my-href pull-right"> <a href="/accounts/register" >Register Link</a> </h2> </div> {% endblock %}
而後,咱們寫樣式的話,須要在 static/CSS目錄下新建一個樣式文件,而後裏面寫樣式(注意:我就寫了簡單的樣式,哈哈哈哈哈)。
body{ background: #e6e6e6; } .my-con1{ text-align: center; color: steelblue; } .my-href{ margin-top: 50px; }
這樣一個簡單的登陸頁面就出來了:
默認的Field是Model中定義的Field,如需更改,可在Form類內以同名字段覆蓋,好比自定義widget和required屬性等。
下面來學習class Meta內嵌類的全部元數據選項(meta options),
abstract
Optional.abstract 若是abstract = True ,這個model就是一個抽象基類
app_label
Options.app_label 若是一個model定義在默認的models.py以外(例如,若是你的APP的models在myapp.models 子模塊下),你必須定義app_label 讓DJango知道他屬於哪個APP app_label = 'myapp'
db_table
Options.db_table 定義該model在數據中的表名稱: db_table = 'music_album'
(注意:在MySQL中使用小寫字母做爲數據庫表名稱)
爲了節省時間,Django會自動的使用你的model class的名稱和包含這個model的APP名稱來構建數據庫的表名稱,一個model的數據庫表名稱是經過將‘app label’ (你在manage.py startapp 中使用的名稱 和model的類名稱,加上一個下劃線在他們之間來構成)。
例如,若是你有一個APP叫作bookstore(使用manage.py startapp bookstore建立),以及一個model定義爲class Book這樣將會建立一個名爲bookstore_book的數據庫表。
若是想自定義數據庫的表名稱,須要在class Meta 使用db_table參數來自定義。
若是你的數據庫表名稱是一個SQL保留字,或者它包含不容許出如今Python變量中的字符(好比連字符)這是沒問題的,由於Django會自動給列名添加引號。
Django模型中的verbose_name咱們經常可能須要使用,好比將數據庫裏面的數據導出成csv文件。那麼,csv文件的表頭的名字能夠經過取每一個字段的verbose_name來獲取,數據能夠經過queryset語句來獲取。這樣製做出來的csv表就能像數據庫同樣,字段名和字段值一一對應了。
Options.verbose_name 指明一個易於理解和表述的對象名稱,單數形式: verbose_name = 'user_name' 若是這個值沒有設定,Django將會使用該model的類名的分詞形式做爲其對象的表述名 CamelCase將會轉換爲camel case
from django.db import models class Meta: # 按 Priority降序, order_date升序排列 get_latest_by = ['-priority', 'order_date'] # 自定義數據庫裏表格的名稱 db_table = 'music_album' # 按照什麼排序 ordering = ['pub_date'] # 定義APP的標籤 app_label = 'myapp' # 聲明此類是否抽象 abstract = True # 添加受權 permissions = (('Can deliver pizzas', 'Can deliver pizzas'))
假設咱們須要在模板中經過連接指向一篇具體的文字,下面哪一種方式更好?
方法1: 使用命名URL <a href="{% url 'article' id %}Article</a> 方法2:使用常規URL——不建議 <a href="blog/article/id">Article</a>
若是你尚未意識到方法1的好處,那麼想一想假設你須要把所有模板連接由 blog/article/id 改成blog/articles/id,那種方法更快?,改全部模板,仍是改URL配置裏的一個字母?
惋惜的是命名的URL通常只在模板裏使用,不能直接在視圖裏使用。若是咱們有了命名的URL,咱們如何把它轉化爲常規的URL在視圖裏使用呢?Django提供的reverse()方法很容易實現這點。假設不一樣的APP(好比news和blog)裏都有article這個命名URL,咱們怎麼樣區分呢?咱們只須要在article前面加上blog這個命名空間便可。
from django.urls import reverse # output blog/article/id reverse('blog:article', args=[id])
並且,咱們須要在urls.py 裏面,給動態連接 取名字,好比:
from django.urls import re_path from . import views app_name = 'blog' urlpatterns = [ re_path(r'^articles/$', views.articles_content, name='articles'), ]
這樣咱們就能夠在HTML模板中經過{% url 'arrticle' id %} 來調用這個連接了。
Django的模型(Model)的本質是類,並非一個具體的對象(object)。當你設計好模型後,你就能夠對Model進行實例化從而建立一個具體的對象。Django對於建立對象提供了兩種不一樣的save與create方法,下面來具體分析一下二者的不一樣。
咱們先來看一下下面的例子,咱們已經設計好了一個Person的模型:
from django.db import models class Person(models.Model): name = models.CharField(max_length=128) def __str__(self): return self.name
用save方法建立一個名爲 james 的具體對象,咱們能夠這麼作。記住你只有用了save()方法後,Django纔會將這個對象的信息存儲到數據庫中。
james_obj = Person(name="LeBron james") james_obj.save()
正由於用save方法建立對象有兩步,並且程序員容易忘記加上 save(),Django提供了一個更便捷的create方法,以下:若是你使用create方法,無需再加上save(),create方法不只建立了新的對象,並且直接將信息存儲到數據庫裏。
james_obj = Person.objects.create(name="LeBron james")
create只能用於建立新的對象,在數據庫層老是執行 insert 的操做。save不只用於建立新的對象,也能用於更新對象的現有數據,在數據庫老是先執行update,找不到具體對象後再執行 insert 的操做,對於建立全新的對象,二者均可以。若是更新已有對象信息,只能用save()方法。
若是你要用Auth自帶的User模型建立新對象,你須要使用create_user方法,而不是create方法,以下所示。(create_user方法頗有用,自動會給密碼加hash )。
user1 = User.objects.create_user(username=username, username=password)
當咱們註冊一個harden,註冊成功後會自動跳轉到登陸頁面。
下面咱們登陸harden的信息,登陸成功後跳轉到harden的用戶信息頁面。
進入詳細信息頁面,咱們會發現下面會有三個按鈕,分別是編輯,修改密碼,退出按鈕。首先咱們點擊編輯按鈕。進入編輯頁面。更新信息,結果以下:
下面咱們進入修改密碼頁面:
當咱們點擊退出,就會從新進入登陸頁面。再次進入我的信息頁面,咱們就會發現新的信息。
若是登陸的用戶名不存在,會出現下面報錯信息:
其餘的就很少作演示了。
請移步小編的GitHub:傳送門
參考文獻: https://blog.csdn.net/weixin_42134789/article/details/80194532
原文出處:https://www.cnblogs.com/wj-1314/p/10558765.html