1.创建一个项目

1.创建项目

在工作空间目录下执行django-admin startproject 名字

django-admin startproject 名字

2.创建app

在项目的目录下执行

python manage.py startapp 名字

运行 

python manage.py runserver

.
├── admin.py
├── apps.py
├── __init__.py
├── migrations
│   ├── 0001_initial.py
│   ├── __init__.py
│   └── __pycache__
│       ├── 0001_initial.cpython-37.pyc
│       └── __init__.cpython-37.pyc
├── models.py
├── tests.py
├── urls.py
└── views.py

 admin.py文件跟网站的后台管理站点配置相关
 apps.py文件用于配置当前子应用的相关信息
 migrations目录用于存放数据库迁移历史文件
 models.py文件用户保存数据库模型类
 testspy文件用于开发测试用例,编写单元测试
 viewspy文件用于编写web应用视图

3.将自己创建的app配置到项目中

在项目settings 文件

\blog\blog\settings.py

INSTALLED_APPS = [

    'django.contrib.admin',

    'django.contrib.auth',

    'django.contrib.contenttypes',

    'django.contrib.sessions',

    'django.contrib.messages',

    'django.contrib.staticfiles',

    'iot',

]

注意:iot也可以写成iot.apps.IotConfig

4.写程序view,py

在app应用中定义视图函数

\blog\iot\views.py

from django.shortcuts import render
from django.views import View
# Create your views here.

def led(request):
    # 小灯亮度
    print("哈哈")
    return render(request, "iot/led.html")

5.在项目下urls中配置url

 如果子app要在主app下添加url

\blog\blog\urls.py

from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static
from django.views.generic.base import RedirectView

urlpatterns = [
    path('admin/', admin.site.urls),
    # include 的参数首先设置一个元组,urlcon_module,app_name
    # url_module, 设置子应用路由
    # app_name 子应用名字
    # namespace 命名空间
    path('', include(('iot.urls', 'iot'), namespace='iot')),
    # django的 ckedit
    path('ckeditor/', include('ckeditor_uploader.urls')),
    # 设置ico网站图标
    path("favicon.ico", RedirectView.as_view(url='static/favicon.ico')),


] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

\python\blog\iot\urls.py

5.1.文件中引入自己appviews模块

from django.urls import path


from .import views

urlpatterns = [
    path('led', views.led, name='led'),

]

 

6.访问自定义视图函数

http://127.0.0.1:8000/led

 

7.模板页面

在aa应用中创建templates文件夹,在此文件夹创建html文件

python\blog\templates\iot\led.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
test
</body>
</html>

8.model.py写数据库模板

\python\blog\iot\models.py

from django.db import models

# Create your models here.


class MQTT(models.Model):
    event = models.CharField(max_length=20, blank=True)

    class Meta:
        db_table = 'mqtt'
        verbose_name = '灯的事件'
        verbose_name_plural = verbose_name

9. 上传数据库

生成迁移文件

python manage.py makemigrations

执行迁移文件 

python manage.py migrate

makemigrations和migrate 没生效有哪些原因

如果运行makemigrationsmigrate命令没有生效,即新的迁移文件没有生成或者模型变更没有反映在数据库中,可能有以下几个常见原因:

  1. 模型定义错误:如果模型定义中存在语法错误、字段类型错误或其他问题,Django可能无法正确生成迁移文件。检查模型定义是否正确,并确保所有字段和关联关系都正确设置。

  2. 应用未添加到INSTALLED_APPS:如果你的应用没有正确添加到Django项目的INSTALLED_APPS配置中,makemigrationsmigrate命令将不会对该应用生效。确认应用已经被正确添加到配置中。

  3. 未在正确的目录运行命令:确保在Django项目的根目录下运行makemigrationsmigrate命令。如果在应用目录或其他位置运行这些命令,可能导致不生效。

  4. 数据库配置问题:如果数据库配置存在问题,例如数据库连接失败或权限问题,migrate命令无法将迁移应用到数据库中。检查Django项目的数据库配置,确保数据库已正确配置且可以连接。

  5. 缓存问题:在某些情况下,可能由于缓存的原因导致迁移没有生效。尝试清除Django项目的缓存,并重新运行makemigrationsmigrate命令。

  6. 数据库版本问题:某些数据库系统可能需要特定版本的数据库客户端或驱动程序才能正确执行迁移。确保你使用的数据库客户端或驱动程序与Django和数据库系统的要求匹配。

  7. Django版本不兼容:如果你使用了较新版本的Django,并且应用中使用了不再支持的功能或语法,可能会导致迁移命令失效。确保使用的Django版本与应用代码兼容。

检查并排除上述问题,通常可以解决makemigrationsmigrate命令不生效的问题。如果仍然无法解决,可以进一步查看命令输出中的错误信息,以获取更多线索。如果需要更详细的帮助,请提供更多关于你的Django项目和应用的信息。

10.admin超级管理员管理员

python manage.py createsuperuser

 

2.排序得到不同的

tag = Article.objects.values('tags').order_by('tags').distinct()

3.流程图

4.Django的请求与响应

一、请求

利用HTTP协议向服务器传参有以下几种途径:

  • 提取URL的特定部分,如/weather/beijing/2018,可以在服务器端的路由中用正则表达式截取;
  • 查询字符串(query string),形如key1=value1&key2=value2;
  • 请求体(body)中发送的数据,比如表单数据、json、xml;
  • 在http报文的头(header)中。

1.URL路径参数获取

在定义路由URL时,可以使用正则表达式提取参数的方法从URL中获取请求参数,Django会将提取的参数直接传递到视图的传入参数中。示例如下:

(1)未命名参数按定义顺序传递

子应用url.py路由部分

url(r'^weather/([a-z]+)/(\d{4})/$', views.weather),

 

子应用视图函数部分

def weather(request, city, year):
    print('city=%s' % city)
    print('year=%s' % year)
    return HttpResponse('OK')

 

(2) 命名参数按名字传递,顺序可变,名字要正确

子应用url.py路由部分

url(r'^weather/(?P<city>[a-z]+)/(?P<year>\d{4})/$', views.weather),

 

子应用视图函数部分

def weather(request, year, city):
    print('city=%s' % city)
    print('year=%s' % year)
    return HttpResponse('OK')

2.查询字符串参数获取(query string)

获取请求路径中的查询字符串参数(形如?k1=v1&k2=v2),可以通过request.GET属性获取,返回QueryDict对象。

# ?a=1&b=2&a=3
def querystr(request):
    a = request.GET.get("a")
    b = request.GET.get("b")
    alist = request.GET.getlist("a")
    print(a)  # 3,一键多值获取的是最后一个
    print(b)  # 2
    print(alist)  # ['1', '3']
    return HttpResponse('OK')

重要:查询字符串不区分请求方式,即假使客户端进行POST方式的请求,依然可以通过request.GET获取请求中的查询字符串数据。

3.请求体数据查询(form表单、json、xml)

请求体数据格式不固定,可以是表单类型字符串,可以是JSON字符串,可以是XML字符串,应区别对待。

可以发送请求体数据的请求方式有POSTPUTPATCHDELETE

Django默认开启了CSRF防护,会对上述请求方式进行CSRF防护验证,在测试时可以关闭CSRF防护机制,方法为在settings.py文件中注释掉CSRF中间件

(1)表单类型form data

​ POST请求方式

前端POST方式发送的表单类型的请求体数据,可以通过request.POST属性获取,返回QueryDict对象。

def get_body(request):
    a = request.POST.get('a')
    b = request.POST.get('b')
    alist = request.POST.getlist('a')
    print(a)
    print(b)
    print(alist)
    return HttpResponse('OK')

重要:request.POST只能用来获取POST方式的请求体表单数据。

​ 非POST请求方式

表单格式 非POST请求

def get_body(request):
    # request.body打印结果: b'c=4&c=5&d=6'
    # data打印结果:<QueryDict: {'c': ['4', '5'], 'd': ['6']}>
    data = QueryDict(request.body,encoding='utf-8')
    c = data.get('c')
    d = data.get('d')
    clist = data.getlist('c')
    print(c)   
    print(d)
    print(clist)
    return HttpResponse('OK')

(2) 非表单类型 Non-Form Data

非表单类型的请求体数据,Django无法自动解析,可以通过request.body属性获取最原始的请求体数据,自己按照请求体格式(JSON、XML等)进行解析。request.body返回bytes类型

例如要获取请求体中的如下JSON数据

{"a": 1, "b": 2}
  • 1

可以进行如下方法操作:

import json

def get_body_json(request):
    json_bytes = request.body  # 得到的是二进制bytes类型
    json_str = json_bytes.decode()  # bytes类型转str类型,python3.6以后无需执行此步
    req_data = json.loads(json_str)  # json格式字符串转为字典
    print(req_data['a'])
    print(req_data['b'])
    return HttpResponse('OK')

4.请求头数据查询

可以通过request.META属性获取请求头headers中的数据,request.META为字典类型

常见的请求头如:

  • CONTENT_LENGTH – The length of the request body (as a string).
  • CONTENT_TYPE – The MIME type of the request body.
  • HTTP_ACCEPT – Acceptable content types for the response.
  • HTTP_ACCEPT_ENCODING – Acceptable encodings for the response.
  • HTTP_ACCEPT_LANGUAGE – Acceptable languages for the response.
  • HTTP_HOST – The HTTP Host header sent by the client.
  • HTTP_REFERER – The referring page, if any.
  • HTTP_USER_AGENT – The client’s user-agent string.
  • QUERY_STRING – The query string, as a single (unparsed) string.
  • REMOTE_ADDR – The IP address of the client.
  • REMOTE_HOST – The hostname of the client.
  • REMOTE_USER – The user authenticated by the Web server, if any.
  • REQUEST_METHOD – A string such as "GET" or "POST".
  • SERVER_NAME – The hostname of the server.
  • SERVER_PORT – The port of the server (as a string).

具体使用如:

def get_headers(request):
    print(request.META['CONTENT_TYPE'])
    return HttpResponse('OK')

5.其他常用HttpRequest对象属性

  • method:一个字符串,表示请求使用的HTTP方法,常用值包括:‘GET’、‘POST’。
  • user:请求的用户对象。
  • path:一个字符串,表示请求的页面的完整路径,不包含域名和参数部分。
  • encoding:一个字符串,表示提交的数据的编码方式。
    • 如果为None则表示使用浏览器的默认设置,一般为utf-8。
    • 这个属性是可写的,可以通过修改它来修改访问表单数据使用的编码,接下来对属性的任何访问将使用新的encoding值。
  • FILES:一个类似于字典的对象,包含所有的上传文件。
   	# 类文件对象,以form-data传递图片文件接收
   def getmediaformdata(request):
    # form-data的第一个参数
    f = request.POST.get("f")
    print("f:", f)
	# form-data上传的图片文件
    image = request.FILES.get("image")
    print(request.FILES)
    # <MultiValueDict: {'image': [<InMemoryUploadedFile: 325042.jpg (image/jpeg)>]}>
    print(image)
    # xxxx.jpg
    print(type(image))
    # <class 'django.core.files.uploadedfile.InMemoryUploadedFile'>
    with open("./slide.jpg", "wb") as f:
        f.write(image.read())

    return HttpResponse('OK')

二、响应

视图在接收请求并处理后,必须返回HttpResponse对象或子对象。

1.HttpResponse

可以使用django.http.HttpResponse来构造响应对象。

HttpResponse(content=响应体, content_type=响应体数据类型, status=状态码)

也可通过HttpResponse对象属性来设置响应体、状态码:

  • content:表示返回的内容。
  • status_code:返回的HTTP响应状态码。

响应头可以直接将HttpResponse对象当做字典进行响应头键值对的设置:

response = HttpResponse()
response['Itcast'] = 'Python'  # 自定义响应头Itcast, 值为Python

示例:

from django.http import HttpResponse

def demo_view(request):
    return HttpResponse('itcast python', status=400)
    或者
    response = HttpResponse('itcast python')
    response.status_code = 400
    response['Itcast'] = 'Python'
    return response

2 HttpResponse子类

Django提供了一系列HttpResponse的子类,可以快速设置状态码

  • HttpResponseRedirect 301
  • HttpResponsePermanentRedirect 302
  • HttpResponseNotModified 304
  • HttpResponseBadRequest 400
  • HttpResponseNotFound 404
  • HttpResponseForbidden 403
  • HttpResponseNotAllowed 405
  • HttpResponseGone 410
  • HttpResponseServerError 500

3 JsonResponse

若要返回json数据,可以使用JsonResponse来构造响应对象,作用:

  • 帮助我们将数据转换为json字符串
  • 设置响应头Content-Type为 application/json
from django.http import JsonResponse

def demo_view(request):
    return JsonResponse({'city': 'beijing', 'subject': 'python'})

注意:JsonResponse传递列表,需要设置safe=False

4 redirect重定向

from django.shortcuts import redirect

def demo_view(request):
    return redirect('/index.html')

三、cookie

Cookie,有时也用其复数形式Cookies,指某些网站为了辨别用户身份、进行session跟踪而储存在用户本地终端上的数据(通常经过加密)。Cookie最早是网景公司的前雇员Lou Montulli在1993年3月的发明。Cookie是由服务器端生成,发送给User-Agent(一般是浏览器),浏览器会将Cookie的key/value保存到某个目录下的文本文件内,下次请求同一网站时就发送该Cookie给服务器(前提是浏览器设置为启用cookie)。Cookie名称和值可以由服务器端开发自己定义,这样服务器可以知道该用户是否是合法用户以及是否需要重新登录等。服务器可以利用Cookies包含信息的任意性来筛选并经常性维护这些信息,以判断在HTTP传输中的状态。Cookies最典型记住用户名。

Cookie是存储在浏览器中的一段纯文本信息,建议不要存储敏感信息如密码,因为电脑上的浏览器可能被其它人使用。

Cookie的特点

  • Cookie以键值对的格式进行信息的存储。
  • Cookie基于域名安全,不同域名的Cookie是不能互相访问的,如访问itcast.cn时向浏览器中写了Cookie信息,使用同一浏览器访问baidu.com时,无法访问到itcast.cn写的Cookie信息。
  • 当浏览器请求某网站时,会将浏览器存储的跟网站相关的所有Cookie信息提交给网站服务器。

1 设置Cookie

可以通过HttpResponse对象中的set_cookie方法来设置cookie。

HttpResponse.set_cookie(cookie名, value=cookie值, max_age=cookie有效期)

  • max_age 单位为秒,默认为None。如果是临时cookie,可将max_age设置为None。

示例:

def demo_view(request):
    response = HttpResponse('ok')
    response.set_cookie('itcast1', 'python1')  # 临时cookie
    response.set_cookie('itcast2', 'python2', max_age=3600)  # 有效期一小时
    return response

2 读取Cookie

可以通过HttpRequest对象的COOKIES属性来读取本次请求携带的cookie值。request.COOKIES为字典类型

def demo_view(request):
    cookie1 = request.COOKIES.get('itcast1')
    print(cookie1)
    return HttpResponse('OK')

四、Session

1 启用Session

Django项目默认启用Session。

在settings.py文件中,可以设置session数据的存储方式,可以保存在数据库、本地缓存等。

2.1 数据库

存储在数据库中,如下设置可以写,也可以不写,这是默认存储方式

SESSION_ENGINE='django.contrib.sessions.backends.db'

如果存储在数据库中,需要在项INSTALLED_APPS中安装Session应用。

2.2 本地缓存

存储在本机内存中,如果丢失则不能找回,比数据库的方式读写更快。

SESSION_ENGINE='django.contrib.sessions.backends.cache'

2.3 混合存储

优先从本机内存中存取,如果没有则从数据库中存取。

SESSION_ENGINE='django.contrib.sessions.backends.cached_db'

5.传递form表单数据

csrf利用session和cookie的时效性进行攻击。他会获取请求的cookie,在session时效内进行请求。因此对于重要信息,重要功能进行单次请求处理。即请求一次失效。

注释了settings.py的csrf验证久不需要验证了,默认是验证的

C:\Users\yys53\OneDrive\python\blog\blog\settings.py

MIDDLEWARE = [
    # 'django.middleware.csrf.CsrfViewMiddleware',

]

 

五、图片压缩与格式转换(utils/storage.py)

import os
from io import BytesIO
from django.core.files.storage import FileSystemStorage
from django.core.files.base import ContentFile
from PIL import Image, ImageFile

# 允许 Pillow 处理大图中的部分损坏数据
ImageFile.LOAD_TRUNCATED_IMAGES = True

class CompressedImageStorage(FileSystemStorage):
    """
    对所有上传的图片(jpg/png/bmp/gif/webp)进行:
      1. 限制最长边 max_side(默认 2048px)
      2. 转 WebP(保留透明度) + 可调质量 quality(默认 80)
      3. 强制输出 .webp 后缀
    """
    def __init__(self, *args, max_side=2048, quality=80, **kwargs):
        super().__init__(*args, **kwargs)
        self.max_side = max_side
        self.quality = quality

    def _compress(self, img):
        # 按 max_side 等比例缩放,避免超大图
        img.thumbnail((self.max_side, self.max_side), Image.LANCZOS)

        buffer = BytesIO()
        params = {
            'format': 'WEBP',
            'quality': self.quality,
            'method': 6,   # 压缩强度 0(速度快) - 6(压缩最优)
        }
        # 如果有 alpha 通道,保留透明度
        if img.mode in ('RGBA', 'LA') or (img.mode == 'P' and 'transparency' in img.info):
            params['lossless'] = False  # 可选 lossless=True 试试无损体积
        img.save(buffer, **params)
        buffer.seek(0)
        return buffer

    def save(self, name, content, max_length=None):
        ext = os.path.splitext(name)[1].lower()
        # 仅处理常见图片类型
        if ext in ('.jpg', '.jpeg', '.png', '.bmp', '.gif', '.webp'):
            img = Image.open(content)
            # 确保是 RGB 或 RGBA 模式
            if img.mode not in ('RGB', 'RGBA'):
                img = img.convert('RGBA' if 'A' in img.getbands() else 'RGB')

            compressed_buffer = self._compress(img)
            # 强制后缀 .webp
            name = os.path.splitext(name)[0] + '.webp'
            content = ContentFile(compressed_buffer.read(), name)

        return super().save(name, content, max_length)

核心功能

  1. 限制分辨率,避免超大图浪费带宽

  2. 转 WebP 格式(相同质量下体积更小)

  3. 支持透明度

  4. 可调压缩质量及强度


Django 配置(settings.py)

  1. 仅针对 CKEditor 上传生效(有效果)

CKEDITOR_STORAGE_BACKEND = 'utils.storage.CompressedImageStorage'
  1. 全局生效(Model/ImageField、其他上传统一压缩,测试没效果)

DEFAULT_FILE_STORAGE = 'utils.storage.CompressedImageStorage'
  1. 可选:全局压缩参数(也可直接在存储类构造时传参):

COMPRESSED_IMAGE_MAX_SIDE = 2048  # 最大边长
COMPRESSED_IMAGE_QUALITY = 80     # WebP 压缩质量

如果需要在类中读取上述配置:

from django.conf import settings
# 在 __init__ 中: max_side = settings.COMPRESSED_IMAGE_MAX_SIDE

图片加个性化

/* 图片效果 */
img {
    position: relative;
    border: 6px solid #46bba9; /* 天空蓝的边框,给人一种轻盈自然的感觉 */
    border-radius: 15px; /* 圆润的边角 */
    padding: 5px;
    background: linear-gradient(135deg, #ffffff, #f0f8ff); /* 淡蓝渐变背景 */
    box-shadow: 0 4px 10px rgba(135, 206, 235, 0.5), 0 6px 15px rgba(173, 216, 230, 0.3); /* 柔和阴影 */
    transition: all 0.3s ease-in-out;
    cursor: pointer;
  }
  
  /* 鼠标悬停时 */
  img:hover {
    transform: scale(1.05) rotate(3deg); /* 轻微旋转,放大 */
    box-shadow: 0 8px 20px rgba(135, 206, 235, 0.7), 0 12px 25px rgba(173, 216, 230, 0.4);
    filter: brightness(1.2) saturate(1.5); /* 提亮和饱和度增加,增强视觉效果 */
  }
  
  /* 点击时的动态效果 */
  img:active {
    animation: butterfly-pulse 1.5s infinite ease-in-out; /* 动态脉动 */
    transform: scale(1.08) rotate(5deg); /* 轻微放大并旋转 */
    box-shadow: 0 10px 25px rgba(135, 206, 235, 0.7), 0 15px 30px rgba(173, 216, 230, 0.4);
  }