本章簡介:
- Django 簡介
- Django 基本配置
- Django url
- Django view
- Django 模板語言
- Django Form
Django 簡介
Django是一個開放源代碼的Web應用框架,由Python寫成。采用了MVC的軟件設計模式,即模型M,視圖V和控制器C。它最初是被開發來用於管理勞倫斯出版集團旗下的一些以新聞內容為主的網站的。並於2005年7月在BSD許可證下發布。這套框架是以比利時的吉普賽爵士吉他手Django Reinhardt來命名的。
Django的主要目標是使得開發復雜的、數據庫驅動的網站變得簡單。Django注重組件的重用性和“可插拔性”,敏捷開發和DRY法則(Don't Repeat Yourself)。在Django中Python被普遍使用,甚至包括配置文件和數據模型。
優點:
- 完美的文檔,Django的成功,我覺得很大一部分原因要歸功於Django近乎完美的官方文檔(包括Djangobook)。
- 全套的解決方案,Django象Rails一樣,提供全套的解決方案(full-stackframework + batteries included),基本要什么有什么(比如:cache、session、feed、orm、geo、auth),而且全部Django自己造,開發網站應手的工具Django基本都給你做好了,因此開發效率是不用說的,出了問題也算好找,不在你的代碼里就在Django的源碼里。
- 強大的URL路由配置,Django讓你可以設計出非常優雅的URL,在Django里你基本可以跟丑陋的GET參數說拜拜。
- 自助管理后台,admin interface是Django里比較吸引眼球的一項contrib,讓你幾乎不用寫一行代碼就擁有一個完整的后台管理界面。
缺點:
- 系統緊耦合,如果你覺得Django內置的某項功能不是很好,想用喜歡的第三方庫來代替是很難的,比如下面將要說的ORM、Template。要在Django里用SQLAlchemy或Mako幾乎是不可能,即使打了一些補丁用上了也會讓你覺得非常非常別扭。
- Django自帶的ORM遠不如SQLAlchemy強大,除了在Django這一畝三分地,SQLAlchemy是Python世界里事實上的ORM標准,其它框架都支持SQLAlchemy了,唯獨Django仍然堅持自己的那一套。
- Template功能比較弱,不能插入Python代碼,要寫復雜一點的邏輯需要另外用Python實現Tag或Filter。
Django流程介紹
Django采用MTV模式。所謂MVC就是把web應用分為模型(M),控制器(C),視圖(V)三層;他們之間以一種插件似的,松耦合的方式連接在一起。模型負責業務對象與數據庫的對象(ORM),視圖負責與用戶的交互(頁面),控制器(C)接受用戶的輸入調用模型和視圖完成用戶的請求。
- Django的MTV模式本質上與MVC模式沒有什么差別,也是各組件之間為了保持松耦合關系,只是定義上有些許不同,Django的MTV分別代表:
- Model(模型):負責業務對象與數據庫的對象(ORM)
- Template(模版):負責如何把頁面展示給用戶
- View(視圖):負責業務邏輯,並在適當的時候調用Model和Template
- 此外,Django還有一個url分發器,它的作用是將一個個URL的頁面請求分發給不同的view處理,view再調用相應的Model和Template
接下來就挨個說說每個模塊來構成的Django
Django 基本配置
一、創建django程序
- 終端命令:django-admin startproject sitename
- IDE創建Django程序時,本質上都是自動執行上述命令
1、終端命令
# 查看django版本 $ python -m django --version # 創建項目,名為mysite $ django-admin startproject mysite # 啟動django $ python manage.py runserver $ python manage.py runserver 8080 $ python manage.py runserver 0.0.0.0:8000 # 創建應用程序,確保和 manage.py 是同一目錄 $ python manage.py startapp polls # 運行創造模型變化遷移 $ python manage.py makemigrations # 運行應用模型變化到數據庫 $ python manage.py migrate # admin創建管理員用戶 $ python manage.py createsuperuser
2、IDE創建(PyCharm為例)
File --> New Project --> 選擇Django --> Appliocation Name 創建app
二、生成目錄結構如下:
三、配置文件(settings)
1、剛創建django project時,開始寫入程序,第一步先要在配置文件中注冊app
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'app01', # 注冊app ]
2、數據庫連接
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME':'數據庫名', 'USER': 'root', 'PASSWORD': 'xxx', 'HOST': '', 'PORT': '', } }
注:由於Django內部連接MySQL時使用的是MySQLdb模塊,而python3中還無此模塊,所以需要使用pymysql來代替
如下設置放置的與project同名的配置的 __init__.py文件中
import pymysql pymysql.install_as_MySQLdb()
3、靜態文件配置
STATICFILES_DIRS = ( os.path.join(BASE_DIR,'static'), )
注:需要在project下創建static文件夾
Django url
URL配置(URLconf)就像Django 所支撐網站的目錄。它的本質是URL模式以及要為該URL模式調用的視圖函數之間的映射表;你就是以這種方式告訴Django,對於這個URL調用這段代碼,對於那個URL調用那段代碼。URL的家在是從配置文件中開始。
1、先寫一個簡單的世界你好吧
url文件
from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^index/', views.index), ]
views文件
from django.shortcuts import render # Create your views here. def index(request): return render(request,'index.html')
templates文件夾下新建index.html文件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>Hello 張岩林</h1> </body> </html>
2、路由正則
urlpatterns = [ url(r'^index/(?P<pager>\d*)/,views.index,{'id':333}), ]
注:Django支持路由正則功能,同時想拿到值可以在view中的函數中把相對應得明明寫入即可接收到,{'id':333}傳入函數,通過key可以取到值
views中index函數
from django.shortcuts import render # Create your views here. def index(request,pager,id): print(pager,id) return render(request,'index.html')
由此看出正則這塊可以寫分頁功能
3、app對路由規則進行一次分類
需要在app01中新建一個urls文件,然后寫入,project下urls配置
from django.conf.urls import url from django.contrib import admin from app01 import views from django.conf.urls import include urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^buy/', include('app01.urls')), ]
app01下urls配置
#!/usr/bin/env python # -*- coding:utf-8 -*- from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^index/', views.index), ]
訪問url如下:
http://127.0.0.1/buy/index/
django中的路由系統和其他語言的框架有所不同,在django中每一個請求的url都要有一條路由映射,這樣才能將請求交給對一個的view中的函數去處理。其他大部分的Web框架則是對一類的url請求做一條路由映射,從而是路由系統變得簡潔。
Django views
http請求中產生兩個核心對象:
-
http請求:HttpRequest對象
- http響應:HttpResponse對象
一、HttpRequest對象
# 獲取提交方式 request.method if request.method == "POST": times = time.time() return render(request,'index.html') # 獲取前端post提交的數據 request.POST.get('username') # 獲取域名后路徑 get_full_path() 例:http://127.0.0.1:8000/index33/?name=123 ,req.get_full_path()得到的結果就是/index33/?name=123
二、HttpResponse對象
def test(request): # 往前端寫入字符串 return HttpResponse("xxx") # 跳轉路徑 return redirect('/index/') # 渲染HTML文件兩種方式 return render(reuqest, "test.html") return render_to_response('text.html') # 可以直接將函數中所有的變量傳給模板 return render(reuqest, "test.html",locals()) # 可以根據通過字典的方式往前端傳值,取值輸入key即可 return render(reuqest, "test.html",{'zhang':'好帥'})
Django 模板語言
1、if/else
{% if %}標簽計算一個變量值,如果是“true”,即它存在、不為空並且不是false的boolean值
系統則會顯示{% if %}和{% endif %}間的所有內容:
{% if today_is_weekend %} <p>Welcome to the weekend!</p> {% else %} <p>Get back to work.</p> {% endif %}
2、{% for %}
標簽允許你按順序遍歷一個序列中的各個元素,Python的for語句語法為for X in Y,X是用來遍歷Y的變量 ,每次循環模板系統都會渲染{% for %}和{% endfor %}之間的所有內容
例如,顯示給定athlete_list變量來顯示athlete列表:
<ul> {% for athlete in athlete_list %} <li>{{ athlete.name }}</li> {% endfor %} </ul>
forloop.counter # for循環個數
forloop.first # for循環第一個值
forloop.last # for循環最后一個值
3、母版,子版繼承,導入
母板:{% block title %}{% endblock %} 子板:{% extends "base.html" %} {% block title %}{% endblock %}
4、自定義模板simple_tag
a、在app中創建templatetags模塊
b、創建任意 .py 文件,如:xx.py
#!/usr/bin/env python #coding:utf-8 from django import template from django.utils.safestring import mark_safe from django.template.base import resolve_variable, Node, TemplateSyntaxError register = template.Library() @register.simple_tag def my_simple_time(v1,v2,v3): return v1 + v2 + v3 @register.simple_tag def my_input(id,arg): result = "<input type='text' id='%s' class='%s' />" %(id,arg,) return mark_safe(result)
注:事例中變量名不能變,必須是固定寫法
c、在使用自定義simple_tag的html文件中導入之前創建的 xx.py 文件名
{% load xx %}
d、使用simple_tag
{% my_simple_time 1 2 3%} {% my_input 'id_username' 'hide'%}
Django Form
有時候我們需要在前台用 get 或 post 方法提交一些數據,所以自己寫一個網頁,用到 html 表單的知識。
一、基礎form提交
比如寫一個計算 a和 b 之和的簡單應用,網頁上這么寫
<!DOCTYPE html> <html> <body> <p>請輸入兩個數字</p> <form action="/add/" method="POST"><input type="text" name="a"> <input type="text" name="b"> <input type="submit" value="提交"> </form> </body> </html>
把這些代碼保存成一個index.html,放在 templates 文件夾中。
網頁的值傳到服務器是通過 <input> 或 <textarea>標簽中的 name 屬性來傳遞的,在服務器端這么接收:
from django.http import HttpResponse from django.shortcuts import render def index(request): return render(request, 'index.html') def add(request): a = request.POST.GET('a') b = request.POST.GET('b') a = int(a) b = int(b) return HttpResponse(str(a+b))
但是,比如用戶輸入的不是數字,而是字母,就出錯了,還有就是提交后再回來已經輸入的數據也會沒了。
當然如果我們手動將輸入之后的數據在 views 中都獲取到再傳遞到網頁,這樣是可行的,但是很不方便,所以 Django 提供了更簡單易用的 forms 來解決驗證等這一系列的問題。
二、Django Forms應用
1、簡單案例一
在app01下新建一個文件forms.py
from django import forms class AddForm(forms.Form): a = forms.IntegerField() b = forms.IntegerField()
我們的視圖函數 views.py 中
#!/usr/bin/env python # -*- coding:utf-8 -*- from django.shortcuts import render,HttpResponse from app01.forms import AddForm def index(request): if request.method == 'POST':# 當提交表單時 # form 包含提交的數據 form = AddForm(request.POST) # 如果提交的數據合法 if form.is_valid(): a = form.cleaned_data['a'] b = form.cleaned_data['b'] return HttpResponse(str(int(a) + int(b))) # 當正常訪問時 else: form = AddForm() return render(request, 'index.html', {'form': form})
對應的模板文件 index.html
<form method='post'> {% csrf_token %} {{ form }} <input type="submit" value="提交"> </form>
這個簡單的案例,大家不知道有沒有看出其中的蹊蹺呢,仔細觀察,form類給我做了驗證,用戶輸入錯了會彈出報錯信息
2、進階案例二
models.py
from django.db import models # Create your models here. class BookType(models.Model): caption = models.CharField(max_length=64) class Book(models.Model): name = models.CharField(max_length=64) pages = models.IntegerField() price = models.DecimalField(max_digits=10,decimal_places=2) pubdate = models.DateField() book_type = models.ForeignKey('BookType')
views.py
#!/usr/bin/env python # -*- coding:utf-8 -*- from django.shortcuts import render from app01.forms import Form1 def form1(request): if request.method == 'POST': # 獲取請求內容做驗證 f = Form1(request.POST) if f.is_valid(): print(f.cleaned_data) else: print(type(f.errors),f.errors) return render(request,'form1.html',{'error':f.errors,'form':f}) else: f = Form1() return render(request,'form1.html',{'form':f})
在app01下新建一個文件forms.py
#!/usr/bin/env python # -*- coding:utf-8 -*- from django import forms from app01 import models class Form1(forms.Form): # 用戶名,給該標簽添加一個class屬性,還有空值的報錯信息修改 user = forms.CharField( widget=forms.TextInput(attrs={'class': 'c1'}), error_messages={'required': '用戶名不能為空'},) # 密碼定義最大長度和最小長度 pwd = forms.CharField(max_length=4,min_length=2) # 郵箱定義錯誤信息,required為空值錯誤信息,invalid為郵箱匹配錯誤信息 email = forms.EmailField(error_messages={'required': '郵箱不能為空', 'invalid': '郵箱格式錯誤'}) # 生成多行文本編輯框 memo = forms.CharField(widget=forms.Textarea()) # 下拉菜單實時更新數據庫 user_type_choice = models.BookType.objects.values_list('id','caption') book_type = forms.CharField(widget=forms.widgets.Select(choices=user_type_choice,attrs={'class': "form-control"})) def __init__(self,*args, **kwargs): super(Form1, self).__init__(*args, **kwargs) self.fields['book_type'] = forms.CharField( widget=forms.widgets.Select(choices=models.BookType.objects.values_list('id','caption'),attrs={'class': "form-control"}))
前端form1.html

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> .input-group{ position: relative; padding: 20px; width: 250px; } .input-group input{ width: 200px; display: inline-block; } .input-group span{ display: inline-block; position: absolute; height: 12px; font-size: 8px; border: 1px solid red; background-color: darksalmon; color: white; top: 41px; left: 20px; width: 202px; } </style> </head> <body> <form action="/form1/" method="post"> <div class="input-group"> {{ form.user }} {% if error.user.0 %} <span>{{ error.user.0 }}</span> {% endif %} </div> <div class="input-group"> {{ form.pwd }} {% if error.pwd.0 %} <span>{{ error.pwd.0 }}</span> {% endif %} </div> <div class="input-group"> {{ form.email }} {% if error.email.0 %} <span>{{ error.email.0 }}</span> {% endif %} </div> <div class="input-group"> {{ form.memo }} {% if error.memo.0 %} <span>{{ error.memo.0 }}</span> {% endif %} </div> <div class="input-group"> {{ form.book_type }} {% if error.book_type.0 %} <span>{{ error.book_type.0 }}</span> {% endif %} </div> <div> <input type="submit" value="提交"> </div> </form> </body> </html>