用Django框架開發一個簡單的企業網站


創建框架

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  

打開后台管理平台

http://127.0.0.1:8000/admin/

一些簡單的后台修改可以在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'),
]


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM