dummersoul

创建框架

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\'),
]

分类:

技术点:

相关文章: