Django 是一个文档很全的框架,学习的时候老是遇到一些坑,这里就顺便记录一下,以便后面使用,同时也希望本文可以帮助到其他的朋友。

开发环境

操作系统:macOS Cataline 10.15.3

Pythonpyenv 安装的 pypy3.6-7.3.0 (PyPy解释器平均比我们平时使用的CPython快4.4倍)

Django:Django 3.0.3

相关依赖

MySQL

macOS 下 Django3 在连接 MySQL 会出一些问题,解决如下:

# 确保 pip 是最新版本
$ pip install --upgrade pip

# 临时在当前的shell环境中配置一个 openssl 变量
export LDFLAGS="-L/usr/local/opt/openssl/lib $LDFLAGS"
export CPPFLAGS="-I/usr/local/opt/openssl/include $CPPFLAGS"

$ pip install mysqlclient

pillow

models.py中含有ImageField图片类型的时候,如果pillow没有安装好的话 会报错:

image = models.ImageField(upload_to='avatar/%Y/%m', verbose_name='头像', max_length=100)

解决方法是 macOS 下安装配置好zlib即可:

# 安装 zlib
$ brew install zlib

# 链接 zlib 会提示
$ brew link zlib --force

Warning: Refusing to link macOS-provided software: zlib
For compilers to find zlib you may need to set:
  export LDFLAGS="-L/usr/local/opt/zlib/lib"
  export CPPFLAGS="-I/usr/local/opt/zlib/include"

根据上述提示,进行如下操作:

# 临时在当前的shell环境中配置一个 zlib 变量
export LDFLAGS="-L/usr/local/opt/zlib/lib"
export CPPFLAGS="-I/usr/local/opt/zlib/include"

$ pip install pillow

目录配置

templates

模板目录 Python 命令行创建的 Django 项目默认是没有自动生成这个目录的,首先项目目录下新建templates文件夹,然后配置一下 settings:

settings.py

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')], # 将 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

该目录存放一些 css js 之类的静态文件,也得手动到 settings.py 添加配置一下:

settings.py

STATIC_URL = '/static/'
STATICFILES_DIRS = [(os.path.join(BASE_DIR, 'static'))]

apps

当项目下的app太多的时候,项目的目录结构看上去就会比较混乱,一个解决办法就是将项目下的所有app都放到一个apps的文件夹中,首先项目下新建apps文件夹,接着手动到 settings.py 添加配置一下:

settings.py

import os
import sys

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, os.path.join(BASE_DIR, 'apps')) # 将 apps 文件夹添加到 BASE_DIR中

media

media 文件夹用来存放用户上传的图片资料等,首先配置下 settings.py

settings.py

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(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',
                'django.template.context_processors.media', # 添加 media 模板
            ],
        },
    },
]

接着配置 media 根目录变量:

settings.py

MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

配置好之后在 urls.py 里面配置下 media 的路由规则:

urls.py

from django.urls import path, re_path
from django.views.static import serve
from project.settings import MEDIA_ROOT

urlpatterns = [
    path('admin/', admin.site.urls),
      # 配置 media 的处理
    re_path('media/(?P<path>.*)', serve, {'document_root': MEDIA_ROOT}, name='org_list'),  
]

下面看一下 简单的 引用 meida 中图片文件的实例:

models.py

class CourseOrg(models.Model):
    ...
    image = models.ImageField(upload_to='org/%Y/%m', verbose_name='logo', max_length=100)
    ...

前端调用显示 media 里的文件

<img width="200" height="120" class="scrollLoading" data-url="{{ MEDIA_URL }}{{ course_org.image }}"/>

实用插件

验证码

项目地址https://github.com/mbi/django-simple-captcha

$ pip install django-simple-captcha

安装好之后,在settings.py引用即可:

settings.py

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'captcha',  # 引用验证码插件
]

引用完成后,更新下数据库的信息,因为这个验证码信息是存放在本地数据库中的:

$ python manage.py makemigrations
$ python manage.py migrate 

数据库更新成功后可以在数据库下看到 captcha_captchastore 表名,接着得配置下验证码的url路由规则:

urls.py

urlpatterns = [
    path('admin/', admin.site.urls),
    path('captcha/', include('captcha.urls')),
]

Form 表单中定义如下:

forms.py

from django import forms
from captcha.fields import CaptchaField

class RegisterForm(forms.Form):
    email = forms.EmailField(required=True)
    password = forms.CharField(required=True, min_length=5)
    captcha = CaptchaField(error_messages={'invalid': '验证码错误'})

Views 里面实例化这个表单类:

views.py

class RegisterView(View):
    def get(self, request):
        register_form = RegisterForm()
        return render(request, 'register.html', {
            'register_form': register_form
        })

views.py 里面 返回了register_form到前端,接着前端可以直接调用 验证码:

<div class="form-group marb8 captcha1">
<label>验证码</label>
{{ register_form.captcha }}
</div>

分页

项目地址https://github.com/jamespacileo/django-pure-pagination

$ pip install django-pure-pagination

安装好之后,在settings.py引用即可:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
      'pure_pagination',
]

views 里面的基本用法:

views.py

from pure_pagination import Paginator, EmptyPage, PageNotAnInteger

class OrgView(View):
    """
    课程机构列表功能显示
    """
    def get(self, request):
        # 课程机构
        all_orgs = CourseOrg.objects.all()

        # 官方提倡的写法
        try:
            page = request.GET.get('page', 1)
        except PageNotAnInteger:
            page = 1

        # 将数据库中 查询的 all_orgs 分页 每页显示5个
        p = Paginator(all_orgs, 5, request=request)
        orgs = p.page(page)
        return render(request, 'org-list.html', {
            'all_orgs': orgs,  # 分页的结果传给前端
        })

前端分页的引用:

<div class="pageturn">
<ul class="pagelist">
<!-- 判断是是否有上一页 -->
  {% if all_orgs.has_previous %}
  <li class="long"><a href="?{{ all_orgs.previous_page_number.querystring }}">上一页</a></li>
  {% endif %}

<!-- 显示中间页数 和 高亮 当前页 -->
  {% for page in all_orgs.pages %}
  {% if page %}
  {% ifequal page all_orgs.number %}
  <li class="active"><a href="?{{ page.querystring }}" class="page">{{ page }}</a></li>
  {% else %}
  <li><a href="?{{ page.querystring }}" class="page">{{ page }}</a></li>
  {% endifequal %}
  {% else %}
  <li class="none"><a href="">...</a> </li>
  {% endif %}
  {% endfor %}

<!-- 判断是是否有下一页 -->
  {% if all_orgs.has_next %}
  <li class="long"><a href="?{{ all_orgs.next_page_number.querystring }}">下一页</a></li>
  {% endif %}
</ul>
</div>

最后的分页效果如下:

Django分页效果

导入导出

项目地址https://github.com/django-import-export/django-import-export

$ pip install django-import-export

安装好之后,在settings.py引用即可:

settings.py

INSTALLED_APPS = [
    'import_export',  # 引用导入导出插件
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

接着可以直接在 Django Admin后台引用:

admin.py

from import_export.admin import ImportExportActionModelAdmin

@admin.register(CourseOrg)
class CourseOrgAdmin(ImportExportActionModelAdmin):
    list_display = ['name', 'image_data', 'address']
    search_fields = ['name', 'city', 'address', 'desc']
    list_filter = ['city', 'add_time']

最后配合 Simple UI 的效果如下:

Simple UI 导入导出

Admin 配置

修改后台名称

在 urls.py 里面添加 如下即可:

admin.site.site_header = '后台管理'
admin.site.site_title = 'Django 后台管理'

核心原理就是在引用 这个模块的文件里面添加配置即可生效:

from django.contrib import admin

最后效果如下:

Django自定义后台名称

图片显示

Django Admin 的列表中图片只显示 URL 地址,却不能直接显示出来:

Django Admin图片不显示

Django Admin图片不显示

解决方法就是重写 Django Admin 后台图片的显示。

models.py

from django.utils.html import format_html

class CourseOrg(models.Model):
    image = models.ImageField(upload_to='org/%Y/%m', verbose_name='logo', max_length=100)

    # 定义 image_data 将 url 手动 通过 img 表情显示出来
    def image_data(self):
        return format_html(
            '<img src="{}" width="200px" height="90px"/>',
            self.image.url,
        )
        # 设置标题
    image_data.short_description = '图片'  

admin.py

from django.contrib import admin

@admin.register(CourseOrg)
class CourseOrgAdmin(admin.ModelAdmin):
      # 显示里面 传入 我们自定义的 image_data
    list_display = ['name', 'image_data', 'address']
    search_fields = ['name', 'city', 'address', 'desc']
    list_filter = ['city', 'add_time']

    # 设置该列不可编辑
    readonly_fields = ('image_data',)

最后显示效果如下:

Django Admin 图片显示

支持一下

本文可能实际上也没有啥技术含量,但是写起来还是比较浪费时间的,在这个喧嚣浮躁的时代,个人博客越来越没有人看了,写博客感觉一直是用爱发电的状态。如果你恰巧财力雄厚,感觉本文对你有所帮助的话,可以考虑打赏一下本文,用以维持高昂的服务器运营费用(域名费用、服务器费用、CDN费用等)

微信
支付宝

没想到文章加入打赏列表没几天 就有热心网友打赏了 于是国光我用 Bootstrap 重写了一个页面用以感谢支持我的朋友,详情请看 打赏列表 | 国光