創建框架
django-admin startproject testdj # 創建一個Django項目 cd testdj python manage.py startapp my_app # 創建一個app
配置文件
在urls.py下添加app的路徑
from django.contrib import admin from django.urls import path, re_path, include urlpatterns = [ path('admin/', admin.site.urls), re_path(r'^', include('my_app.urls')), ]
在app目錄下新建urls.py ,用於配置這個app下所有的路由
from django.urls import path, re_path from my_app import views urlpatterns = [ re_path(r'^', views.index), ]
在app內的views.py文件中寫一個index處理函數
from django.shortcuts import render, HttpResponse def index(request): return HttpResponse('你好啊')
在項目目錄下的settings.py內添加創建的app
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'my_app', # 新加入的一行 ]
測試一下
python manage.py runserver 0.0.0.0:8000
查看網頁
加入數據庫
新創建一個名叫my_app的mysql數據庫,之后開啟MySQL服務並在settings.py內配置數據庫連接信息
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', # 數據庫引擎 'NAME': 'my_app', # 數據庫名,事先要創建 'USER': 'root', # 數據庫用戶名 'PASSWORD': '123456', # 密碼 'HOST': 'localhost', # 主機 'PORT': '3306', # 數據庫使用的端口 } }
配置好之后,運行manage命令更新數據表,Django會生成一些默認的表(原本是沒有一張表的)
python manage.py migrate
結果報錯
raise MigrationSchemaMissing("Unable to create the django_migrations table (%s)" % exc)
原因是:Django2.1不再支持MySQL5.5,必須5.6版本以上
解決辦法二選一:
(1)Django降級到2.0
pip install Django==2.0.0 -i https://pypi.douban.com/simple
(2)MySQL升級
我選擇降級之后再更新表
auth_user表示是保存后台管理員用戶信息的
現在創建一個超級管理員
python manage.py createsuperuser
按照命令行的提示,依次輸入用戶名,郵箱,密碼(兩次),其中郵箱可以為空(直接回車跳過)
數據表中已經可以看到管理員的信息了
在settings.py指定語音
LANGUAGE_CODE = 'zh-hans' # 指定語言(注意不要寫錯,否則無法啟動服務器) TIME_ZONE = 'Asia/Shanghai'
運行
python manage.py runserver
打開后台管理平台
一些簡單的后台修改可以在admin.py內設置,例如標題和網頁的title:
from django.contrib import admin # Register your models here. admin.site.site_header = '我的后台管理' admin.site.site_title = '后台管理'
如果涉及到更復雜的后台定制,例如模板布局,樣式等就需要小折騰一番了,首先修改settings.py:
TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', # 優先使用項目模板路徑 'DIRS': [BASE_DIR + "/templates"], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, }, ]
# 優先使用項目路徑 STATIC_URL = '/static/' STATICFILES_DIRS = (os.path.join(BASE_DIR, 'static'),)
Django默認在當前項目目錄static路徑下查找靜態文件(js,css等),templates路徑下查找模板文件(html文件),例如后台的模板頁面和樣式文件;沒有找到文件就會在Django的安裝目錄下調用。
把static,templates兩個文件夾復制到項目目錄下
加入數據模型類
后台和數據庫已經搞定,現在可以寫我們網站的功能了;就寫一個最簡單的功能,發布企業新聞。打開app內的models.py文件,寫兩個數據模型類:
from django.db import models class NewsClass(models.Model): name = models.CharField('分類名稱', max_length=10) def __str__(self): return self.name class Meta: verbose_name = '資訊類別' verbose_name_plural = '資訊類別' class News(models.Model): # 默認添加 # id = models.AutoField(primary_key=True) title = models.CharField('文章標題', max_length=30) content = models.TextField('文章內容') date = models.DateTimeField('發布時間') show = models.BooleanField('是否顯示') news_class = models.ForeignKey( NewsClass, verbose_name='文章分類', on_delete=models.CASCADE) def __str__(self): return self.title class Meta: verbose_name = '資訊' verbose_name_plural = '資訊'
關於數據模型類,可以理解為一張數據表,類里面的屬性就是表的字段;id字段如果沒有特殊要求可以不寫,Django會自動創建。為了后台顯示美觀,這里我給字段和類都設置了中文別名;更多關於django的models模型類的常用數據類型和選項,留個鏈接https://www.jianshu.com/p/651aa9fe5d1a,有點數據庫基礎應該不難理解。
寫好數據模型類,運行manage命令,會在app目錄migrations/和migrations/__pycache__/路徑下各生成一個記錄文件:
python manage.py makemigrations
運行更新數據表會多出兩個
python manage.py migrate
對數據模型做了任何修改都要執行上面兩個manage命令,同步數據庫;如果直接在數據庫里修改字段,刪除表或者刪除了之前的數據模型記錄文件,可能會導致python manage.py migrate命令無法從數據模型更新表,不過也沒關系,運行下面的命令:
python manage.py sqlmigrate 'your_app_name' 0001查看框架自動生成的sql語句
控制台顯示0001記錄文件轉化的sql語句,復制sql語句可以直接在數據庫中操作。
現在有了新聞分類和新聞內容2張數據表,在后台注冊這兩個數據模型類,這樣就能直接通過后台向數據表里添加數據了,打開app內admin.py:
from web_app.models import * admin.site.register(News) admin.site.register(NewsClass)
然后python manage.py runserver,打開后台
點擊添加咨詢
這里Django默認的大容量文本字段是通過一個textarea作為輸入方式,所以我們還需要引入一個富文本編輯器,這里我推薦KindEditor(http://kindeditor.net/demo.php),配置簡單,功能也齊全。
下載KindEditor,將此靜態文件放入static中,
config.js內容
KindEditor.ready(function(k) { window.editor = k.create('#id_content', { resizeType: 1, allowPreviewEmoticons: false, allowImageRemote: false, width: '700px', height: '400px', }); })
然后打開admin.py寫入一個配置類,之后再與相關模型一起注冊,然后現在的admin.py文件為
from django.contrib import admin from my_app.models import * class NewsAdmin(admin.ModelAdmin): # 寫一個配置類 list_display = ('title', 'news_class', 'date', 'show') class Media: # 在管理后台的相關HTML文件中加入js文件 js = ( '/static/kindeditor/kindeditor-all-min.js', '/static/kindeditor/lang/zh-CN.js', '/static/kindeditor/config.js', ) admin.site.site_header = '我的后台管理' admin.site.site_title = '后台管理' admin.site.register(News, NewsAdmin) # 與相關模型一起注冊(必須寫一起才行) admin.site.register(NewsClass)
然后運行網站,打開后台就會發現,那個文本編輯器已經換成我們添加進去的KindEditor了,如下圖
編輯器自帶的上傳圖片和文件選項還不能使用,我們需要配置一個post上傳url;首先在項目settings.py內添加兩個配置,設置上傳文件目錄:
首先在項目settings.py內添加兩個配置,設置上傳文件目錄:
# 上傳設置 MEDIA_URL = '/static/upload/' MEDIA_ROOT = os.path.join(BASE_DIR, 'static/upload')
在app文件夾內新建一個upload.py處理文件上傳:
import os import uuid import json import datetime from django.http import HttpResponse from django.conf import settings # 上傳post請求地址 # http://127.0.0.1:8000/upload_file/?dir=media def upload(request): # kindeditor圖片上傳返回數據格式說明: # {'error': 1, 'message': '出錯信息'} # {'error': 0, 'url': '圖片地址'} result = {'error': 1, 'message': '上傳失敗'} # input type="file" 中name屬性對應的值為imgFile files = request.FILES.get('imgFile', None) type = request.GET['dir'] # 獲取資源類型 if files: result = process_upload(files, type) # 結果以json形式返回 return HttpResponse(json.dumps(result), content_type='application/json') def is_ext_allowed(type, ext): # 根據類型判斷是否支持對應的擴展名 ext_allowed = {} ext_allowed['image'] = ['jpg', 'jpeg', 'bmp', 'gif', 'png'] ext_allowed['flash'] = ['swf', 'flv'] ext_allowed['media'] = ['swf', 'flv', 'mp3', 'wav', 'wma', 'wmv', 'mid', 'avi', 'mpg', 'asf', 'rm', 'rmvb', 'mp4'] ext_allowed['file'] = ['doc', 'docx', 'xls', 'xlsx', 'ppt', 'htm', 'html', 'txt', 'zip', 'rar', 'gz', 'bz2', 'pdf'] return ext in ext_allowed[type] def get_relative_file_path(): # 獲取相對路徑 dt = datetime.datetime.today() relative_path = '%s/%s/' % (dt.year, dt.month) absolute_path = os.path.join(settings.MEDIA_ROOT, relative_path) print(absolute_path) if not os.path.exists(absolute_path): os.makedirs(absolute_path) return relative_path def process_upload(files, type): dir_types = ['image', 'flash', 'media', 'file'] # 判斷是否支持對應的類型 if type not in dir_types: return {'error': 1, 'message': '上傳類型不支持[必須是image,flash,media,file]'} cur_ext = files.name.split('.')[-1] # 當前上傳文件的擴展名 # 判斷是否支持對應的擴展名 if not is_ext_allowed(type, cur_ext): return {'error': 1, 'message': '擴展名不支持 %s類型不支持擴展名%s' % (type, cur_ext)} relative_path = get_relative_file_path() # linux中一切皆文件 file_name = str(uuid.uuid1()) + '.' + cur_ext base_name = os.path.join(settings.MEDIA_ROOT, relative_path) # windows中的路徑以\分隔 file_full_path = os.path.join(base_name, file_name).replace('\\', '/') file_url = settings.MEDIA_URL + relative_path + file_name with open(file_full_path, 'wb') as f: if files.multiple_chunks() == False: # 判斷是否大於2.5M f.write(files.file.read()) else: for chunk in files.chunks(): f.write(chunk) return {'error': 0, 'url': file_url}
注意返回的json數據格式不要寫錯,否則KindEditor編輯器上傳會報錯。上傳的文件我們保存在static/upload目錄內,有了上傳處理函數后,就可以在app的url.py內配置路由了:
from web_app import upload as u # app url 配置 urlpatterns = [ re_path(r'^$', views.index), re_path(r'^upload_file/$', u.upload, name='upload'), ]
在KindEditor的參數js內(config.js)添加上傳url參數:
// 上傳請求路徑 uploadJson: '/upload_file/',
完整config.js
KindEditor.ready(function(k) { var csrf_token = document.getElementsByName('csrfmiddlewaretoken')[0].value; window.editor = k.create('#id_content', { resizeType: 1, allowPreviewEmoticons: false, allowImageRemote: false, // 上傳請求路徑 uploadJson: '/upload_file/', width: '700px', height: '400px', // 處理csrf驗證 extraFileUploadParams: { csrfmiddlewaretoken: csrf_token }, }); })
由於Django自帶CSRF驗證(有興趣的同學可以了解下:https://www.jianshu.com/p/a178f08d9389),所以上傳圖片失敗了,但是有2種方法解決:
- 在settings.py內注釋掉'django.middleware.csrf.CsrfViewMiddleware',關閉CSRF驗證。
- post上傳請求頭內添加CSRF參數(推薦方法)
我選擇了第一張方法,然后上傳圖片成功了
前台數據展現
views.py內寫一個處理函數
from django.shortcuts import render, HttpResponse from my_app.models import * def news_content(request): # http://127.0.0.1:8000/news/?id=1 id_num = request.GET.get('id') context = {} try: context['News'] = News.objects.get(id=id_num) context['title'] = context['News'].title except News.DoesNotExist: context['News'] = '404' context['title'] = '404' return render(request, 'my_app/article.html', context) return render(request, 'my_app/article.html', context)
根據url內id參數查詢新聞內容,然后返回一個模板文件與dict對象;接着在templates路徑下創建我們的html模板文件:
(這里我用Bootstrap可視化布局系統簡單演示一下)
這些網頁布置文件全在templates下的my_app內
{% include "my_app/head.html" %} <div class="container-fluid"> <div class="row-fluid"> <div class="span12"> <h3>{{News.title}}</h3> {% autoescape off %} {{News.content}} {% endautoescape %} </div> </div> </div> {% include "my_app/foot.html" %}
head.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>{{title}}</title> <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.min.css"> <link rel="stylesheet" href="/static/bootstrap/css/bootstrap-combined.min.css"> </head> <body>
url.py中加上路由:
from django.urls import path, re_path
from my_app import views
from my_app import upload as u
urlpatterns = [
re_path(r'^$', views.index),
re_path(r'^news/$', views.news_content),
re_path(r'^upload_file/$', u.upload, name='upload'),
]