Django小白开发指南

news2025/1/16 13:44:47

文章目录

    • HTTP协议
    • socket实现一个web服务器
    • WSGI实现一个web服务器
    • WSGI实现支持多URL的web服务器
    • WSGI实现图片显示的web服务器
    • MVC && MTV
      • 1.MVC
      • 2.MTV
      • 3.总结
    • 一、创建Django项目
      • 1.创建项目
      • 2.创建app
      • 3.第一次django 请求
    • 二、模板
      • 1.配置settings.py
      • 2.模板语法
      • 3.继承模板
    • 三、models模型
      • 1.常用字段&属性
    • 四、设置数据库
      • 1.设置mysql库
      • 2.mysqldb替换mysql
      • 3.数据迁移
    • 五、URL路由匹配
      • 1.正则匹配
      • 2.路由匹配&传参
      • 3.管理多个URL文件
        • 1.去除重复url路径
        • 2.视图传参数
    • 六、View视图
      • 1.HttpRequest对象
      • 2.HttpResponse对象
      • 3.CBV-类方法
      • 4.通过HttpResponse下载文件
      • 5.分页功能
    • 七、ORM的增删改查语句
      • 1.创建语句
      • 2.查询语句
      • 3.修改语句
      • 4.删除语句
      • 5.Filter过滤条件
      • 6.多模块关联关系
      • 7.Queryset对象方法
      • 8.ORM对象操作
        • 1.单表对象操作
        • 2.外键关联操作
        • 3.外键反向关联操作
        • 4.多对多操作
        • 5.多对多反向操作
    • 八、Django会话技术
      • 1、cookie工作原理
      • 2.Cookie
      • 2、CSRF
        • 防止CSRF
    • 九、ORM-admin后台管理
      • 1.管理app下的表(模型)
      • 2.自定制admin(管理界面)
    • 返回上级目录

HTTP协议

HTTP协议(HyperText Transfer Protocol,超文本传输协议)是用于从WWW服务器传输超文本到本地浏览器的传送协议。它可以使浏览器更加高效,使网络传输减少。它不仅保证计算机正确快速地传输超文本文档,还确定传输文档中的哪“部分,以及哪部分内容首先显示(如文本先于图形)等。

socket实现一个web服务器

# -*- coding:utf-8 -*-
# created by Alex Li - 路飞学城


import socket


def main():
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    sock.bind(('localhost', 8000))
    sock.listen(5)

    while True:
        # 等待浏览器访问
        conn, addr = sock.accept()
        # 接收浏览器发送来的请求内容
        data = conn.recv(1024)
        print(data)

        # 给浏览器返回内容
        conn.send(b"HTTP/1.1 200 OK\r\nContent-Type:text/html; charset=utf-8\r\n\r\n")
        conn.send("<h1 style='color:blue'>电脑前的你长的真好看!</h1>".encode("utf-8"))

        # 关闭和浏览器创建的socket连接
        conn.close()


if __name__ == "__main__":
    main()


WSGI实现一个web服务器

  • WSGI (Web Server Gateway lnterface) 是一种规范,它定义了使用python编的web app (应用程序) 与web server (socket服务端)之间接口格式,实现web app与web server间的解耦
  • 通俗的说:当规范建立后,程序就不再重复编写web server (socket服务端),而是直接使用现成的实现WSGI的模块 (例如:wsgiref、uwsgiwerkzeug),从而让程序员更加专注与业务代码与其重复造轮子,不如直接用现成的。
from wsgiref.simple_server import make_server

def run_server(environ,start_response):
    """

    :param environ: 请求相关内容,比如浏览器类型、版本、来源地址、url等
    :param start_response: 响应相关
    :return:
    """
    start_response("200 OK",[('Content-Type','text/html;charset=utf-8')])
    return [bytes('<h1>Hello world!</h1>',encoding='utf-8')]

if __name__ == '__main__':
    httpd = make_server('localhost',8000,run_server)
    httpd.serve_forever() # 死循环

WSGI实现支持多URL的web服务器

from wsgiref.simple_server import make_server

def book(environ,start_response):
    start_response("200 OK", [('Content-Type', 'text/html;charset=utf-8')])
    return [bytes('<h1  style="color:pink">book page!</h1>', encoding='utf-8')]

def cloth(environ,start_response):
    start_response("200 OK", [('Content-Type', 'text/html;charset=utf-8')])
    return [bytes('<h1  style="color:yellow">cloth page!</h1>', encoding='utf-8')]
    pass

def url_dispacher():
    urls = {
        '/book':book,
        '/cloth':cloth,
    }
    return urls

def run_server(environ,start_response):
    """

    :param environ: 请求相关内容,比如浏览器类型、版本、来源地址、url等
    :param start_response: 响应相关
    :return:
    """

    request_url = environ.get("PATH_INFO") # 获取用户请求的url
    url_list = url_dispacher() # 拿到所有url

    if request_url in url_list:
        func_data = url_list[request_url](environ,start_response)
        return func_data # 真正返回数据给用户
    else:
        start_response("404 ",[('Content-Type','text/html;charset=utf-8')])
        return [bytes('<h1 style="font-size:50px">404,Page not found!</h1>',encoding='utf-8')]

if __name__ == '__main__':
    httpd = make_server('localhost',8000,run_server)
    httpd.serve_forever() # 死循环

WSGI实现图片显示的web服务器

from wsgiref.simple_server import make_server
import re
import os

BASE_DIR = os.path.dirname(os.path.abspath(__file__))

def book(environ,start_response):
    start_response("200 OK", [('Content-Type', 'text/html;charset=utf-8')])

    data = """
        <h1>欢迎来到日本人专区</h1>
            <img src='/static/imgs/testimg.gif' />
        <p>上路飞学城,看尽天下小片</p>
    """

    return [bytes(data, encoding='utf-8')]

def cloth(environ,start_response):
    start_response("200 OK", [('Content-Type', 'text/html;charset=utf-8')])
    return [bytes('<h1  style="color:yellow">cloth page!</h1>', encoding='utf-8')]
    pass

def url_dispacher():
    urls = {
        '/book':book,
        '/cloth':cloth,
    }
    return urls

def img_handler(request_url):
    """

    :param request_url: static/imgs/testimg.gif
    :return:
    """
    img_path = re.sub('/static','/static_data',request_url)
    img_abs_path = "%s%s"% (BASE_DIR,img_path)
    if os.path.isfile(img_abs_path):
        f = open(img_abs_path,"rb")
        data = f.read() # 读取文件内容数据
        return [data,0] # 0:成功读取,1:没有读取
    return [None,1]


def run_server(environ,start_response):
    """

    :param environ: 请求相关内容,比如浏览器类型、版本、来源地址、url等
    :param start_response: 响应相关
    :return:
    """

    request_url = environ.get("PATH_INFO") # 获取用户请求的url
    url_list = url_dispacher() # 拿到所有url

    if request_url in url_list:
        func_data = url_list[request_url] (environ,start_response) # 调用相应的url函数
        return func_data # 真正返回数据给用户
    elif request_url.startswith("/static/"): # 表示图片
        img_data,img_status = img_handler(request_url)
        if img_status == 0: # 读取到图片数据
            start_response("200 OK", [('Content-Type', 'text/html;charset=utf-8')])
            return [img_data]
    else:
        start_response("404 ",[('Content-Type','text/html;charset=utf-8')])
        return [bytes('<h1 style="font-size:50px">404,Page not found!</h1>',encoding='utf-8')]

if __name__ == '__main__':
    httpd = make_server('localhost',8001,run_server)
    httpd.serve_forever() # 死循环

MVC && MTV

1.MVC

MVC 是一种使用 MVC (Model View Controller 模型-视图-控制器)设计创建 Web 应用程序的模式

  • Model(模型)一般对应数据库操作、纪录的存取
  • View (视图)决定着如何展示数据
  • Controller (控制器) 负现处理用户交互的部分·控制器负责从视图读取数据,控制用户输入,并向模型发送数据。(urls)

2.MTV

Django是一个MTV框架,其架构模板看上去与传统的MVC架构并没有太大的区别。

Django将MVC中的视图进一步分解为 Django视图(views.py)Django模板(html文件)两个部分,分别决定“展现哪些数据”和“如何展现”,使得Django的模板可以根据需要随时替换,而不仅仅限制于内置的模板,至于MVC控制器部分,由Django框架的URLconf(urls.py)来实现。

3.总结

MVC VIEWS 负责 业务逻辑处理+数据展示
MTV Views 业务逻辑处理
Templates 数据展示

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传



一、创建Django项目

  • 要在终端中使用Django创建一个项目,可以按照以下步骤进行操作:
  1. 打开终端(命令行界面)

  2. 确保你已经安装了Django。可以通过运行以下命令来检查Django是否已安装:

    django-admin --version
    

    如果没有安装Django,可以使用以下命令安装:

    pip install django
    
  3. 创建项目。在终端中使用以下命令创建一个Django项目:

    django-admin startproject project_name
    

    把 “project_name” 替换为你想要的项目名称。这将在当前目录下创建一个名为 “project_name” 的文件夹,其中包含用于构建Django项目所需的文件和目录。

    创建应用。在项目目录中使用以下命令创建一个Django应用:

    django-admin startapp app_name
    

    把 “app_name” 替换为你想要的应用名称。这将在项目目录下创建一个名为 “app_name” 的文件夹,其中包含用于构建Django应用的文件和目录。

  4. 进入项目目录。使用以下命令进入刚创建的项目目录:

    cd project_name
    

    这会将终端的当前工作目录切换到你的项目目录中。

  5. 运行开发服务器。在项目目录中,运行以下命令来启动Django的开发服务器:

    python manage.py runserver 0.0.0.0:8000
    

    这将运行开发服务器,默认在本地的8000端口上。

  6. 现在,你可以在浏览器中访问 http://localhost:8000/ 来查看新创建的Django项目的初始页面。

这样就完成了在终端中创建一个Django项目的步骤。你可以根据需要在项目中添加应用、模型、视图等。

1.创建项目

django-admin startproject my_site

项目目录结构

mysite
├── manage.py		# 管理程序的文件,启动和结束等。
└── my_site
    ├── __init__.py
    ├── settings.py		# 程序的配置文件
    ├── urls.py		# 程序的路由系统,即:url和处理其函数的对应的关系
    └── wsgi.py		# 指定框架的wsgi

2.创建app

django-admin startapp app01
├── __init__.py 包
├── admin.py 数据库后台
├── apps.py   #django 把项目和app 关联起来的一个文件
├── migrations  #数据库相关
│   └── __init__.py
├── models.py  # 数据库操作地方
├── tests.py    # 单元测试
└── views.py    # 业务逻辑代码

3.第一次django 请求

  1. 匹配路由, 路由分发器查找用户请求的url 对应关系,
    1. 找到了业务函数,就调用
    2. 找不到就报404
  2. 业务函数,执行业务逻辑
  3. 返回数据给浏览器
1。  urls.py 编写路由
2.   在views.py 写一个业务函数
    2.1 编写业务 代码
    2.2 通过HttpResponse 方法返回数据给前端

3. python manage.py runserver 0.0.0.0:8000

二、模板

1.配置settings.py

  • TEMPLATES 配置Html文件,即配置该文件的路径,以便运行程序查找
  • 配置jinja引擎,需在该项目下新建一个文件:jinja2_env.py,并添加代码:
# 安装模块:pip install jinja2

from django.templatetags.static import static
from django.urls import reverse
from jinja2 import Environment

def environment(**options):
    env = Environment(**options)
    env.globals.update({
        'static': static,
        'url': reverse,
    })
    return env
# 项目默认配置django引擎
# 若需配置jinja引擎,需添加
'BACKEND': 'django.template.backends.jinja2.Jinja2', 
'environment':'django4.jinja2_env.environment', # django4-项目名称,jinja2_env-该项目下新建的jinja2_env.py

TEMPLATES = [ # 模版,html文件
    # jinja2模板引擎 (在html文件中可以引用函数)
    {
        'BACKEND': 'django.template.backends.jinja2.Jinja2',
        'DIRS': [BASE_DIR/'templates'],
        'APP_DIRS': True,
        'OPTIONS': {
            # 添加environment,并指定到jinja2_env文件中的environment
            
            '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模板引擎
    {
        
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [BASE_DIR/"templates"], # html 文件夹的位置
        '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',
            ],
        },
    },
]

2.模板语法

  • 在templates目录下的html文件
"""注释"""
{# 单行注释 #}
{% comment %}
	多行注释
{% endcomment %}
    
    
    
"""变量"""
<p>{{ name }}</p> 
<p>{{ boddy.2 }}</p> # 列表:索引号取值
<p>{{ addr.city }}</p> # 字典
    
    
    
"""if语句"""
{% if age < 18 %}
    ...
{% elif age > 60 %}
    ...
{% else %}
    ...
{% endif %}  
   
    
    
 """结合运算符"""
{% if age >= 18 and  age < 60%}
{% if age >= 18 or  age < 60%}
    
"""in"""
{% if 'movie' in boddy %}
    ...
{% endif %}
    
    
    
"""for循环语句"""
{% for b in boddy %}
       ...
{% endfor %}
"""empty用法"""
{% for b in boddy2 %}
    ...
{% empty %}   
    <p>boddy2为空或不存在</p>
{% endfor %}
    
    

"""下标"""
{% for foo in boddy %}
    <p>
        counter_{{ forloop.counter }} # 下标从1开始
        counter0_{{ forloop.counter0 }} # 下标从0开始
        revcounter_{{ forloop.revcounter }} # 下标颠倒从大到小
        revcounter0_{{ forloop.revcounter0 }} # 下标颠倒从大到小(0)
    </p>
{% endfor %}
    
    
    
"""嵌套语句"""
<table border="2" width="400">
    {% for star in stars %}
    	{% for s in star %}
            {{ s }}-
            {{ forloop.parentloop.counter }}- # 父循环的下标
            {{ forloop.counter }} # 本次循环下标
    	{% endfor %}
    {% endfor %}  
</table>
    
    
    
"""过滤器"""
<p>{{ age }}</p>
<p>{{ age|add:5 }}</p> # add:变量+5
<p>{{ age|add:-5 }}</p> # add:变量-5
    
<p>{{ name|first|upper }}</p> # 将变量name第一个字符串大写
<p>{{ name|last|lower }}</p> # 将变量name最后一个字符串小写
<p>{{ name|title }}</p> 
<p>{{ name|truncatechars:3 }}</p> # 将变量name第三个字符串开始截断

<p>{{ boddy|join:'+' }}</p> # 列表转字符串
    
<p>{{ boddy2|default:'默认值' }}</p> # 若变量boddy2无值则设置默认值
    
<p>{{ dt|date:'y-m-d' }}</p> # 转成日期格式
<p>{{ dt|date:'Y-M-d' }}</p> 
    
 
    
"""HTML转义"""
<p>{{ code|safe }}</p> # safe:将变量code字符串转义成html格式

{% autoescape on %} # 关闭自动转义
   		... # 自动转义字符串内容
{% endautoescape %}

{% autoescape off %} # 开启自动转义
   		...
{% endautoescape %}
  • 若使用 jinja模板引擎,则可以调用python的函数
<body>
    <h2>jinja2模板语言</h2>
    <hr>

    {# 可调用python函数range #}
    {% for i in range(1,10) %}
        {{ i }}
    {% endfor %}

</body>
</html>

3.继承模板

# 模板快
{% block xxx%}
	...
{% endblock %}


# 继承模板
{% extends 'xxx.html' %}



# 继承模板内容:block.super
{% block content %}
{# 默认情况下,子模板会覆盖父模板内容 #}
{# 若想继承父模板内容,需使用block.super #}
	{{ block.super }}
        <div>
            <button>content</button>
        </div>
{% endblock %}



# 导入其他模板文件:include
{% block head %}
{# 导入其他模板文件 #}
	{% include 'xxx.html' %}
		<div>
			<button>head</button>
		</div>
{% endblock %}

三、models模型

  • django使用对象关系映射 (0bject Relational Mapping,简称ORM)框架去操控数据库。

models ==> ORM

模型 -> 表

类结构 -> 表结构

对象 -> 表的一条数据

类属性 -> 表的字段


1.常用字段&属性

# 常用字段
CharField:用于存储字符串,可指定最大长度。

TextField:用于存储长文本字段,没有长度限制。

IntegerField:用于存储整数。

FloatField:用于存储浮点数。

BooleanField:用于存储布尔值,TrueFalse。

DateField:用于存储日期。

DateTimeField:用于存储日期和时间。

FileField:用于存储文件,文件会被上传到指定目录。

ImageField:与FileField类似,但特定于存储图像文件。
# 常用属性
max_length:用于指定字段的最大长度。适用于CharField和TextField等字符串字段类型。

null:指定字段是否允许为空。默认为False,即不允许为空。对于关联字段(ForeignKey、OneToOneField等),默认值是True。

blank:指定字段在表单中是否可以为空。默认为False,即不能为空。对于关联字段,如果null=True,则默认值为True。

default:指定字段的默认值。

choices:用于定义字段的选项列表。适用于CharField和IntegerField等字段类型。例如:choices=[(1, ‘男’), (2, ‘女’)]

verbose_name:指定字段在后台管理界面中显示的名称。

related_name:用于指定反向关系的名称。适用于关联字段(ForeignKey、ManyToManyField等)。

unique:指定字段的值是否在数据库中唯一,默认为False。

help_text:用于在后台管理界面中显示字段的帮助文本。

auto_now:指定每次保存对象时自动更新字段的值为当前时间。适用于DateTimeField和DateField等日期时间字段类型。

auto_now_add:指定在创建对象时将字段的值设置为当前时间。适用于DateTimeField和DateField等日期时间字段类型。

editable:指定字段是否可编辑。默认为True,表示字段可以在后台管理界面中被编辑。

primary_key:指定字段是否为主键。默认为False。

db_index:指定是否在数据库中为字段创建索引。默认为False。

choices:定义了一个包含键-值对的元组,作为下拉菜单。

name / db_column:数据库中的字段名称。

upload_to:用于定义上传文件的存储路径。
  • models.py
# 注:每次写完模型或添加一个字段都需要进行一次数据迁移,将数据迁移到数据库中!

from django.db import models

class UserModel(models.Model):
    # uid 会成为主键,原来默认的id不会创建
    uid = models.AutoField(auto_created=True,primary_key=True)
    # CharField:字符串类型
    #   unique:唯一
    #   db_index:数据库索引
    name = models.CharField(max_length=20,unique=True,db_index=True)
    # IntegerField:整数类型
    #   default:默认值
    age = models.IntegerField(default=18)
    # BooleanFieldL:bool类型
    sex = models.BooleanField(default=True)
    # TextField:文本框
    #   null=True:表示可以为空
    #   blank=True:在admin管理页面可以为空
    info = models.TextField(null=True,blank=True)
    # FloatField:小数
    salary = models.FloatField(default=100000.521)
    # DecimalField:十进制小数
    #   max_digits:最大长度
    #   decimal_places:小数点是几位
    money = models.DecimalField(max_digits=4,decimal_places=2,default=10.52)

四、设置数据库

  • 对象关系映射(Object Relational Mapping),它的实质就是将关系数据(库中的业务数据用对象的形式表示出来并通过面向对象 (Object-Oriented)的方式将这些对象组织起来,实现系统业务逻辑的过程。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

1.设置mysql库

# settings.py

# 设置mysql
DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.mysql",
        "NAME": "myBlog", # 数据库名
        "USER": "root",
        "PASSWORD": "12345678",
        "HOST": "127.0.0.1",
        "PORT": "3306",
    }
}

2.mysqldb替换mysql

  • python3连接mysql的得使用pymysql,MysqlDB模块300年没更新了,但django默认调用的还是MysQLdb,因此 pymysq有个功能可以让django以为是用了MySQLdb.即在项目目录下的 init.py中加上句代码就好
  • 或者直接安装mysqlclient则无需使用该方法:pip install mysqlclient
# __init__.py(项目文件)
import pymysql


pymysql.version_info = (1, 4, 13, "final", 0) # mysqlclient版本问题
pymysql.install_as_MySQLdb()

3.数据迁移

  • 同步ORM表结构到数据库(Models.py文件每次写完就需要进行迁移)

  • 在项目中如果添加了一个字段,需手动同步到数据库,否则数据库报错没有该字段

  • 数据库同步工具:migrations

  • 1、生成迁移文件

# app01表示指定的app,若第一次执行,则可以默认不写
python manage.py makemigrations app01
  • 2、执行迁移
python manage.py migrate
# settings.py
# 同步app设置,最后写入同步的app名

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

五、URL路由匹配


1.正则匹配

  • Django的路由本质上是通过正则表达式来对用户请求的url进行匹配(Django2.0版本前使用正则匹配)
# urls.py

from django.urls import path,re_path
from app02 import views


urlpatterns = [
    re_path(r'^articles/2003/$',views.article_archive1),
    # year,month被封装为字典,所以函数形参需写该键值接收
    re_path(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$',views.article_archive2),
    # slug:匹配任意字符串
    re_path(r'^articles/(?P<arg1>[0-9]{4})/(?P<arg2>[0-9]{2})/(?P<slug>[\w-]+)/$',views.article_archive3),
]
# views.py

def article_archive1(request):
    return HttpResponse('静态article_2003')

def article_archive2(request,year,month):
    return HttpResponse('动态article %s-%s'%(year,month))

def article_archive3(request,arg1,arg2,slug):
    return HttpResponse('动态article %s-%s-%s'%(arg1,arg2,slug))

2.路由匹配&传参

  • Django2.0新用法path
  • 自定义方法调用 register_converter()
# urls.py

from django.urls import path
from app02 import views

# path匹配
urlpatterns = [
    path('articles/<int:year>',views.new_article1),
    # str:除了'/'外都能匹配
    path('articles/<int:year>/<str:date>',views.new_article2),
    path('articles/<int:year>/<int:month>/<slug:arg>',views.new_article3),
    # path:'/'也能匹配
    path('articles/<path:arg>',views.new_article4),
]
# views.py

def new_article1(request,year):
    return HttpResponse('新用法Path %s'%year)

def new_article2(request,year,date):
    return HttpResponse('新用法Path %s %s'%(year,date))

def new_article3(request,year,month,arg):
    return HttpResponse('新用法Path %s %s %s'%(year,month,arg))

def new_article4(request,arg):
    return HttpResponse('新用法Path %s'%(arg))
  • 路由传参
# urls.py
urlpatterns = [
    path('userdetail/<int:uid>',userdetail,name='myuserdetail'),
]


# views.py
def userdetail(request,uid):
    user = userModel.objects.get(pk=uid) # pk:主键
    return render(request,'userdetail.html',{'user':user}) # 将user参数传入html文件的user变量


# userdetail.html
<body>
    <p>名字:{{ user.name }}</p>
    <p>年龄:{{ user.age }}</p>
</body>
  • 命名空间
    • 若路径有命名空间,则该命名空间下所有相关的路径都需要添加该命名空间
# urls.py
urlpatterns = [
	path('app01/',include(('app01.urls','app01'),namespace='app01')),
]


# app01:urls.py
urlpatterns = [
    path('userlist/',userlist,name='myuserlist'), # 
    path('userdetail/<int:uid>',userdetail,name='myuserdetail'),
]

# userlist.html
<body>
 	# 跳转到命名空间为app01下的myuserdetail的html( url/userdetail/id )
    <a href="{%  url 'app01:myuserdetail' user.id %}"></a> 
</body>
  • 重定向
# views.py
from django.shortcuts import redirect,reverse

# 重定向
def myredirect(request):
    # return redirect('https://www.baidu.com')
    
    # 反向解析
    # redirect(reverse('myuserdetail'),args=(2,)) ==> 'userdetail/2/'
    return redirect(reverse('myuserdetail',args=(2,))) # args传参
    return redirect(reverse('myuserdetail',kwargs={'uid':2})) # 关键字传参

	# 命名空间
    return redirect(reverse('app01:myuserdetail',args=(2,))) # args传参
    return redirect(reverse('app01:myuserdetail',kwargs={'uid':2})) # 关键字传参

3.管理多个URL文件

  • 当有多个app时,每个app可以有自己的urls.py,只需在顶级urls.py(项目下的urls)中include一下就可以
# urls.py

from django.urls import path,include

urlpatterns = [
    # 包括了app01和app02项目的urls
    path('app01/',include("app01.urls")),
    path('app02/',include("app02.urls"))
]
1.去除重复url路径
# urls.py

# 去除重复的部分url
extra_urls = [
    path('<int:year>/<str:date>', views.new_article2),
    path('<int:year>/<int:month>/<slug:arg>', views.new_article3),
    path('<path:arg>', views.new_article4),
]

urlpatterns = [
    # 去除url重复的路径"articles"部分,匹配结果相同
    path('articles',include(extra_urls))
]
2.视图传参数
# urls.py
urlpatterns = [
    # 写一个字典,键表示实参名,值表示传入实参值
    path('articles/<int:year>',views.new_article1,{'version':'v1.0'}),
]
# views.py
# 获取参数version
def new_article1(request,year,version):
    return HttpResponse('新用法Path %s-%s'%(year,version))

六、View视图


1.HttpRequest对象

  • **request.scheme:**返回请求协议(http/https)
  • **request.path:**返回请求页的路径
  • **request.method:**返回http请求的方法(get/post/put/delete…)
  • **request.GET/request.POST:**返回http请求的参数(方法由HTML文件决定)
  • **request.content_type:**返回http请求的类型
  • **request.FILES:**返回上传的文件数据
    • 获取文件数据,需在HTML文件加上属性 enctype=“multipart/form-data” 告知后台这个表单有文件,将文件单独处理。
  • **request.META:**包含所有可用 HTTP头的字典
  • **request.get_host():**返回网站服务器地址
  • **request.get_port():**返回服务器主机端口
  • **request.get_full_path():**返回相对路径(相当于request.path)
  • **request.build_absolute_uri(‘location’):**返回url的绝对路径,若添加位置,则附加
  • **request.COOKIES:**会话技术
  • **request.session:**会话技术
  • **request.META[‘REMOTE_ADDR’]😗*客户端的ip地址
# views.py
from django.shortcuts import render,HttpResponse

def index(request):
    print(request.scheme) # http
    print(request.path) # /app02/index
    print(request.method) # get
    print(request.content_type) # text/plain
    print(request.GET,request.POST) # <QueryDict: {'username': ['xiaof'], 'password': ['lsf20010929']}>
    print(request.GET.get('username'),request.POST.get('username')) # 获取字典数据
    print(request.FILES) # <MultiValueDict: {'my_file': [<InMemoryUploadedFile: CSS.jpeg (image/jpeg)>]}>
    print(request.META['REMOTE_ADDR']) # 127.0.0.1
    print(request.META) 
    for k,v in request.META.items():
        print(k,v)
    print(request.get_host()) # localhost:8000
    print(request.get_port()) # 8000
    print(request.get_full_path()) # /app02/index
    print(request.build_absolute_uri('user=abc/pwd=123')) # http://localhost:8000/app02/user=abc/pwd=123
    print(request.COOKIES) # 浏览器cookies数据
    print(request.session)
    return render(request,'form.html')
  • 中间件(防火墙)
    • url->中间件->view,中间件相当于防火墙,需关闭相应的安全过滤,才能修改浏览器的请求方法
# 项目的settings.py

MIDDLEWARE = [ # 中间件(防火墙)
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    # 'django.middleware.csrf.CsrfViewMiddleware', # 注释即关闭防火墙,使网页可以进行其他请求操作
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

2.HttpResponse对象

# 响应
from django.http import JsonResponse

# 1.返回字符串
return HttpResponse('OK')
# 2.返回模板:前后端不分离使用
return render(request,'index.html')
# 3.重定向:跳转页码	
return HttpResponseRedirect("/")
# 4.返回JSON:前后端分离使用
return JsonResponse({"data":"hello"})
  • **content_type:**用于填充HTTP的数据类型

    • 默认情况下为: “ text/html; charset = utf-8”。
  • **status:**HTTP的状态码

# views.py

from django.shortcuts import HttpResponse

def index(request):
	html = """
    <form method="POST" enctype="multipart/form-data">
    <input type="text" name="username">
    <input type="password" name="password">
    <input type="file" name="my_file">
    <input type="submit" value="登录">
    </form>
    """
    res = HttpResponse(html,content_type="text/plain",status=404)
  • **HttpResponseRedirect:**状态码:302,临时重定向一个新的位置
  • **HttpResponsePermanentRedirecttt:**状态码:301,永久定向到一个新的位置
from django.shortcuts import HttpResponseRedirect,HttpResponsePermanentRedirecttt

def test(request):
    return HttpResponseRedirect("/") # 临时定向到首页
	return HttpResponsePermanentRedirecttt("/") # 永久定向到首页

3.CBV-类方法

  • CBV(Class-Based-View),CBV就是在视图里使用处理请求。
  • 即可以让我们用类写View。这样做的优点主要下面两种:
    • 提高了代码的复用性,可以使用面向对象的技术,比如Mixin(多继承)
    • 可以用不同的函数针对不同的HTTP方法处理,而不是通过很多if判断,提高代码可读性
# views.py
from django.views import View

# 该类会自动判断调用方法
class TestView(View):
    def get(self,request):
        return HttpResponse("Class View get request")
    def post(self,request):
        return HttpResponse("Class View post request")
    pass
  • url处理是需要一个可调用的函数,class-based-view提供了一个 as_view() 静态方法
# urls.py

urlpatterns = [
    path('class_view',views.TestView.as_view()) # 对于类需调用as_view方法
]
  • 类继承
# views.py 

# 类继承
class TestView2(TestView):
    time = 10

4.通过HttpResponse下载文件

  • MIME参考手册:https://www.w3school.com.cn/media/media_mimeref.asp
  • 对于文件类型,需参考MIME手册,然后修改 content_type
# views.py

def download_file(request):
    f = open('static_data/data.xls','rb')
    res = HttpResponse(f.read(),content_type='application/vnd.ms-excel') # 文件类型为xls
    res['Content-Disposition'] = 'attachment; filename="my_data.xls"' # 对下载的文件进行处理
    return res

5.分页功能

# views.py
from django.core.paginator import Paginator

def paginate(request,page=1):
    per_page = 10
    all_data = PersonModel.objects.all()
    # 分页器
    paginator = Paginator(all_data,per_page)

    persons = paginator.page(page) # 获取第page页的数据
    pages = range(1,per_page+1) # 页面范围,供遍历
    data = {'persons':persons,'pages':pages}
    
    return render(request,'paginate.html',data)
# urls.py
urlspattern = [
    path('paginate/<int:page>/',paginate,name='paginate'),
]

七、ORM的增删改查语句


1.创建语句

  • 方法1:在终端执行以下命令,进入django的数据库环境
python manage.py shell
  • 创建数据
from app01 import models

# 方法1,object.create创建对象,创建完后数据将自动提交保存到数据库
models.Account.object.create(
	username = '小枫',
    email='1848148016@qq.com',
    password='12345678',
)
# 方法2,先创建数据,再通过save方法提交数据
new_obj = models.Account(
	username = '小枫',
    email='1848148016@qq.com',
    password='12345678',
)
new_obj.save()
  • 外键关联 models.ForeignKey(“Account”)
# 方法1,直接在对象里关联 account_id = id值
models.Article.objects.create(
    title = '如何学Python',
    content = '日复一日,坚持学习',
    # 关联的键值必须加上_id
    account_id = 1,
    pub_date = '2023-7-31',
)
# 方法2,先各自创建表,再进行关联 a1.account = m1对象
# 先创建用户表
m1 = models.Account(
	username='王五',
	email='123132@qq.com',
	password='213123',
)
m1.save()
# 再创建文章表
a1 = models.Article(
    title='什么是chatggpt',
    content='人工智能chatgpt',
    pub_date='2022-10-12',
)
# 关联表
a1.account = m1
a1.save()
  • 多对多关联 models.ManyToManyField (“Tag”)
a1 = models.Article(
    title='什么是chatggpt',
    content='人工智能chatgpt',
    account_id = 1,
    pub_date='2022-10-12',
)
# tags.set,赋值tags对象id为1,3,5
a1.tags.set([1,3,5])
# tags.add,在原记录上加新值tags对象id为1,2,3
a1.tags.add(1,2,3)
articles = models.Article.objects.filter(content__contains='技术')  # 过滤出含有关键词的文章
tag = models.Tag.objects.get(id=2)  # 获取要关联的标签对象

for article in articles:
    article.tags.add(tag)  # 将标签关联到每篇过滤后的文章中

2.查询语句

# __gt:大于
# 查询id大于5的Account对象
models.Account.objects.filter('id__gt=5')
# startswith:以什么开头
# 查询以密码为a开头的Account对象                              
models.Account.objects.filter('password__startswith='a')
# , : 和                              
# 查询id大于5的Account对象并且psw是123
models.Account.objects.filter('id__gt=5,password='123')                          

3.修改语句

# 批量修改
models.Account.objects.filter(id__gt=1).update(password='1234556')

# 单条修改
a = models.Account.objects.get(id=1)
a.username = 'job'
a.save()

4.删除语句

  • 相关联的表数据也会被删除
# 批量删除
models.Account.objects.filter(id__gt=1).delete()

# 单条删除
a = models.Account.objects.get(id=1)
a.delete()

5.Filter过滤条件

  • 一般在前面加上is表示对字母大小写不敏感,可返回多个对象

gt:大于

it:小于

ite:小于等于

gte:大于等于

statswith:以什么开头

endswith:以什么结尾

contains:包含

models.Account.objects.filter(password__contains="1")

in:判断是否存在并返回

models.Account.objects.filter(id__in=(2,3))

range:区间过度,可对数字、日期进行过滤

import datetime
start_date = datetime.date(2022,12,15)
end_date = datetime.date(2023,8,1)
models.Account.objects.filter(register_date__range=(start_date,end_date))

date:查具体哪一天内容

models.Account.objects.filter(register_date__date="2023-7-31")
models.Account.objects.filter(register_date__date__gt="2023-7-31") # 配合gt使用

year、month、day:查哪一年、哪一月份、哪一天

models.Account.objects.filter(register_date__year="2023")
models.Account.objects.filter(register_date__month="12")
models.Account.objects.filter(register_date__day="15")

week:查询一年的第几周(52)

week_day:查星期几,从1(星期日)到7(星期六)

models.Account.objects.filter(register_date__week_day=2) # 星期一

hour、mintue、second:查每天的哪小时、哪分钟、哪一秒

models.Account.objects.filter(register_date__hour=8)
models.Account.objects.filter(register_date__mintue=15)
models.Account.objects.filter(register_date__second=15)

regex:正则表达式

models.Account.objects.filter(password__regex=r"^(1)")
  • 方法2:在views.py 里写函数,对模型对象进行操作
    • 同时需配置路由url
from django.shortcuts import render,HttpResponse
from django.db.models import Max,Min,Sum,Avg,Count
from app01.models import *

# Create your views here.
def add_person(request):
    # 方式1
    # p = PersonModel()
    # try:
    #     p.name='xiaoM'
    #     p.age=21
    #     p.save()
    # except Exception as e:
    #     return HttpResponse('add fail')
    # return HttpResponse('add success!')

    # 方式2
    # try:
    #     p = PersonModel(name='xiaoK',age=22)
    #     p.save()
    # except Exception as e:
    #     return HttpResponse('add fail')
    # return HttpResponse('add success!')

    # 方式3
    try:
       PersonModel.objects.create(name='ku',age=23)
    except Exception as e:
        return HttpResponse('add fail')
    return HttpResponse('add success!')

def del_person(request):
    try:
        PersonModel.objects.filter(age__gt=20).delete()
    except Exception as e:
        return HttpResponse('delete fail')
    return HttpResponse('delete success!')

def update_person(request):
    try:
        # p = PersonModel.objects.filter(age__gt=23).update(age=100)
        p = PersonModel.objects.get(id=5)
        p.age = 18
        p.save()
    except Exception as e:
        print(e)
        return HttpResponse('update fail')
    return HttpResponse('update success!')


def get_person(request):
    try:
        # p = PersonModel.objects.get(id=5)
        # print(p.name,p.age)

        p = PersonModel.objects.all()
        for o in p:
            print(o.name,o.age)
    except Exception as e:
        print(e)
        return HttpResponse('get fail')
    return HttpResponse('get success!')


# 聚合函数
def aggregate(request):
    p = PersonModel.objects.aggregate(Max('age'))
    p = PersonModel.objects.aggregate(Min('age'))
    p = PersonModel.objects.aggregate(Sum('age'))
    p = PersonModel.objects.aggregate(Count('age'))
    p = PersonModel.objects.aggregate(Avg('age'))
    print(p)
    # 排序
    p = PersonModel.objects.all().order_by('age') # 升序
    p = PersonModel.objects.all().order_by('age','id')
    p = PersonModel.objects.all().order_by('-age')  # 降序
    print(p)
    return HttpResponse('Success!')

6.多模块关联关系

  • 1.关联分类

    • ForeignKey:一对多,将字段定义在多的端中
    • ManyToManyField:多对多,将字段定义在两端的任意一端中
    • OneToOneField:一对一,将字段定义在任意一端中
  • 2.外键关联

    • ForeignKey:一对多关系
    • OneToOneField:一对一关系
from django.db import models

# 创建模型A
class ModelA(models.Model):
    name = models.CharField(max_length=100)

# 创建模型B
class ModelB(models.Model):
    name = models.CharField(max_length=100)
    model_a = models.ForeignKey(ModelA, on_delete=models.CASCADE)  # 建立一对多关系	
    model_a = models.OneToOneField(ModelA, on_delete=models.CASCADE)  # 建立一对一关联
  • on_delete参数
# 注意:修改on_delete参数之后需要重新同步数据库
user_type = models.ForeignKey(UserType,on_delete=models.CASCADE)

models.CASCADE默认值(Django1.11) # 表示级联删除,即删除UserType时胡关联的User也会被删除
models.PROTECT # 保护模式,阻止级联删除。(若无外键关联可删除)
models.SET_NULL # 置空模式,设为null,nuLL=True参数必须具备
modeLs.SET_DEFAULT # 置默认值设为默认值,default参数必须具备
models.SET() # 删除的时候重新动态指向一个安体访问对应元素,可传两数
modeLs.DO_NOTHING什么也不做。(Django1.11) # 有外键约束
  • 外键查询
# 正向查询:直接调用关联的键查询
print(user.user_type.name)
print(user.user_type.id)
# 反向查询
#	内部自动生成 user_set 属性供反向查询
print(user_type.user_set.all()) # 返回QuerySet
print(user_type.user_set.filter(id=1))

# reLated_name:关联名称,设置反向查询的名称,原本使用user_set改为users
user_type = models.ForeignKey(UserType,,reLated_name=users)
print(user_type.users.all())
  • 3.多对多关联
from django.db import models

# 创建模型A
class ModelA(models.Model):
    name = models.CharField(max_length=100)
    model_b = models.ForeignKey('ModelB', on_delete=models.CASCADE)

# 创建模型B
class ModelB(models.Model):
    name = models.CharField(max_length=100)
    model_a = models.ForeignKey(ModelA, on_delete=models.CASCADE)
# 使用
m1 = ModelA.object.get(id=1)
m1.model_b.all()

m2 = ModelB.object.get(id=1)
m2.model_a.all()

7.Queryset对象方法

all():返回所有数据

  • 可在models.py 文件中的类加上__ str __方法,在该方法中写上初始化的字符串,调用all方法时将自动调用该初始化字符串
# models.py
class Account(models.Model):
    """账户表"""

    username = models.CharField(max_length=64,unique=True)
    email = models.EmailField(unique=True)
    password = models.CharField(max_length=255)
    register_date = models.DateTimeField(auto_now_add=True)
    signature = models.CharField("签名",max_length=255,null=True)
    # str方法在调用all方法时自动调用
    def __str__(self):
        return self.username
    
# python manage.py shell
modles.Account.objects.all() # 自动返回该类的初始化str方法

exclude():使用方法与filter()相同,结果与filter相反;排除符合条件的数据

models.Account.objects.exclude(register_date__date='2023-6-15')

values():将数据都封装成一个字典

a = models.Account.objects.all()
a.values()
# 通过键直接取该相应的值(字典)
a.values('username')

order_by():多字段排序

# 通过id进行顺序排序
a.values('id','register_date').order_by('id')
# 通过id进行逆序排序
a.values('id','register_date').order_by('id')

# 通过register_date进行顺序,若相同则根据id进行排序
a.values('id','register_date').order_by('register_date','id')

reverse():反转顺序,使用前必须先进行排序

a.values('id','register_date').reverse()
a.order_by('id').reverse()

get():精确查询一条数据(必须存在的数据),返回一个对象

a = models.Account.objects.get(id=1)
a = models.Account.objects.get(id__id=1) # 必须只存在一条大于1的数据
# 直接调用
a.username

8.ORM对象操作


1.单表对象操作
o = models.Artilce.objects.all()[0]
o.title
2.外键关联操作
o = models.Artilce.objects.all()[0]
o.account.username
3.外键反向关联操作
  • article_set是动态生成的,被外键关联的类,会自动根据关联的类名加上 _set,通过该属性可以反向查找
a = models.Account.objects.get(name='job')
a.article_set.all()
a.article_set.select_related() # 使用效果与all相同
4.多对多操作
a = models.Article.objects.get(id=5)
a.tags.all()
a.tags.select_related() # 使用效果与all相同
5.多对多反向操作
t = models.Tag.objects.get(name='科技')
t.article_set.all()
a.article_set.select_related()

八、Django会话技术

1、cookie工作原理

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2.Cookie

  • 使用response的方法
import datetime

from django.shortcuts import render,HttpResponse,redirect,reverse
from app01.models import *

# 获取cookie
def index(request):
    # cookie
    # 获取该页面的cookie为userid的值,若无则设为0
    userid = request.COOKIES.get('userid',0)
    # 获取登录的用户
    user = userModel.objects.filter(id=userid).first()
    return render(request,'index.html',{'user':user})


# 设置cookie
def login(request):
    if request.method == 'GET':
        return render(request, 'login.html')
    elif request.method == 'POST':
        # 1、接收前端提交过来的数据
        uname = request.POST.get('uname') # 参数为html的name属性值
        passwd = request.POST.get('passwd')

        # 2、登录验证
        users = userModel.objects.filter(username=uname,password=passwd)
        if users.exists():
            # 获取当前登录的用户对象
            user = users.first()
            response = redirect(reverse('index'))

            # 3、设置cookie
            response.set_cookie('userid',user.id) # 创建cookie
            # 设置过期时间
            # response.set_cookie('userid',user.id,max_age=7*24*3600) # max_age:秒
            # response.set_cookie('userid',user.id,
            #                     expires=datetime.datetime(2023,9,5))
            response.set_cookie('userid', user.id, # timedelta:时间差
                                 expires=datetime.datetime.now()+datetime.timedelta(days=10))
            # 跳转到登录页面
            return response

    return HttpResponse("当前账户不存在或账户密码有误,请重新输入或注册!")


# 删除cookie
def logout(request):
    response = redirect(reverse('index'))
    # 注销、删除cookie
    response.delete_cookie('userid')
    request.session.delete(session_key)

    return response
  • session
    • 使用request的方法
import datetime
from django.shortcuts import render,HttpResponse,redirect,reverse
from app01.models import *

# 获取session
def index(request):
    # session
    userid = request.session.get('userid',0)
    # 获取登录的用户
    user = userModel.objects.filter(id=userid).first()
    return render(request,'index.html',{'user':user})


# 设置session
def login(request):
    if request.method == 'GET':
        return render(request, 'login.html')
    elif request.method == 'POST':
        # 1、接收前端提交过来的数据
        uname = request.POST.get('uname') # 参数为html的name属性值
        passwd = request.POST.get('passwd')

        # 2、登录验证
        users = userModel.objects.filter(username=uname,password=passwd)
        if users.exists():
            # 获取当前登录的用户对象
            user = users.first()
            response = redirect(reverse('index'))

            # 3.设置session
            request.session['userid'] = user.id
            request.session.set_expiry(7*24*3600) # 设置过期时间

            return response

    return HttpResponse("当前账户不存在或账户密码有误,请重新输入或注册!")



# 删除session
def logout(request):
    response = redirect(reverse('index'))
    # 注销、删除session
    session_key = request.session.session_key
    request.session.delete(session_key)

    return response

2、CSRF

  • CSRF全拼为Cross Site Request Forgery,跨站请求伪造
  • CSRF指攻击者盗用了你的身份,以你的名义发送恶意请求
    • 包括:以你名义发送邮件,发消息,盗取你的账号,甚至于购买商品,虚拟货币转账…
  • 造成的问题:个人隐私泄露以及财产安全

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

防止CSRF
  • Django下的CSRF预防机制
    django第一次响应来自某个客户端的请求时,会在服务器端随机生成一个 token,把这个token 放在 cookie里。然后每次 POST请求都会带上这个 token,这样就能避免被CSRF攻击。
  • 在Post请求时,表单中添加 {% csrf_token %}
<form action="" method="post">
    {# 禁止csrf安全验证 #}
    {% csrf_token %}
	...
</form>

九、ORM-admin后台管理

  • 创建一个admin,用于登录 ‘localhost:8000/admin’
# 在项目的目录下执行
python manage.py createsuperuser

1.管理app下的表(模型)

  • 注册对应的模型,在该app项目的admin.py上写
# app01/  admin.py
from app01 import models

admin.site.register(models.Account)
admin.site.register(models.Article)
admin.site.register(models.Tag)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2.自定制admin(管理界面)

# app01 --admin.py
# admin自定制
class AccountAdmin(admin.ModelAdmin):
    list_display = ('username','email','register_date','signature') # 显示列表
    search_fields = ('username','email') # 搜索内容
    list_filter = ('register_date',) # 过滤
    list_per_page = 5 #分页,每页几条数据
    list_editable = ['signature',] # 可在列表修改的属性

class ArticleAdmin(admin.ModelAdmin):
    list_display = ('title','pub_date','account')
    fields = ('title','content',('pub_date','tags'))# 可自定义显示范围
    exclude = ('account',) # 与fields相反,不显示某字段
    date_hierarchy = 'pub_date' # 按日期分类显示
    fieldsets = (
        ('文章内容',
         {'fields':('title','content'),
          'classes':('wide','extrapretty'), # 样式
         }
        ),
        ('发布相关',
         {'fields':('account','pub_date'),
          'classes':('collapse',), # 可折叠
         }
        )
    )
    # 只能针对多对多
    # filter_vertical = ('tags',)
    filter_horizontal = ('tags',)
    radio_fields = {'account':admin.HORIZONTAL} # 由下拉框变单选框
    autocomplete_fields = ['account',] # 外键自动补全,可用于查询数据
    
admin.site.register(models.Account,AccountAdmin) #模型与管理类相关联
admin.site.register(models.Article,ArticleAdmin)
admin.site.register(models.Tag)
  • 在admin管理后台,如果添加的字段可为空时,需在models.py 在该字段添加属性 blank=True
    • 一般null和blank同时使用(null作用于数据库)
class Account(models.Model):
    """账户表"""
    signature = models.CharField("签名",max_length=255,null=True,blank=True) # blank与admin配合使用
  • 将多对多关联显示到列表
    • 在 models.py 上自定义方法,在admin.py引入(若不自定义方法无法显示)
# admin.py
class Article(models.Model):
    def get_tags(self):
        return ', '.join([i.name for i in self.tags.all()])
    

# admin.py
class ArticleAdmin(admin.ModelAdmin):
    list_display = ('title','pub_date','account','get_tags')
  • 添加HTML样式

    • 在 models.py 上写该属性的html样式,在admin.py上显示
    • 注意:添加新字段需要手动将数据同步到数据库,否则数据库没有该数据报错
      • python manage.py makemigrations app01
      • python mange.py migrate
    # models.py
    from django.utils.html import format_html
    
    class Tag(models.Model):
        color_code = models.CharField(max_length=6)
        def colored_name(self):
            return format_html(
                '<span style="color:#{};">{}</span>',
                self.color_code,
                self.name,
            )
            
    # admin.py
    class TagAdmin(admin.ModelAdmin):
        list_display = ['name','colored_name']
    
    
  • 自定义表单名称

    • 在 models.py 各表类中添加类 Meta,添加属性 verbose_name_plural
      • 在各表字段自定义名称,直接在字段添加属性 verbose_name
# models.py

class Account(models.Model):
    class Meta:
        # verbose_name = '账户' # 存在复数形式
        verbose_name_plural = '账户'
        
class Article(models.Model):
    tags = models.ManyToManyField("Tag",verbose_name='标签')
    class Meta:
        verbose_name_plural = '文章'
        
class Tag(models.Model):       
        class Meta:
        verbose_name_plural = '标签'

返回上级目录

import sys
sys.path.append('..') # 返回上级目录

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1111432.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[云原生1.]Docker数据管理与Cgroups资源控制管理

文章目录 1. Docker的数据管理1.1 数据卷1.1.1 示例 1.2 数据卷容器 2. 容器互联3. Cgroups资源控制管理3.1 简介3.2 cgroups的主要功能3.3 cpu时间片的简单介绍3.4 对CPU使用的限制3.4.1 对CPU使用的限制&#xff08;基于单个容器&#xff09;3.4.2 对CPU使用的限制&#xff0…

MySQL高可用架构学习

MHA&#xff08;Master HA&#xff09;是一款开源的由Perl语言开发的MySQL高可用架构方案。它为MySQL 主从复制架构提供了 automating master failover 功能。MHA在监控到 master 节点故障时&#xff0c;会提升其中拥有最新数据的 slave 节点成为新的 master 节点&#xff0c;在…

基于Java的农资采购销售管理系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09; 代码参考数据库参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者&am…

(转)STR 内核做了什么

参考这篇文章&#xff1a; Linux电源管理(6)_Generic PM之Suspend功能 写的很清晰

了解SUI质押和发行计划

SUI是Sui链上的原生资产&#xff0c;总供应量100亿个&#xff0c;并非所有SUI token在一开始就完全流通。相反&#xff0c;随着Sui生态的发展&#xff0c;新token将逐步解锁以奖励生态的早期支持者。质押补贴用于支持网络当前的运营&#xff0c;并由Sui基金会分发给Sui的构建者…

<C++> 模拟实现string

目录 前言 一、模拟实现string 1. 成员变量 2. 构造函数 2.1 构造函数 2.2 重载默认构造 2.3 合并 3. 析构函数 4. 拷贝构造函数 5. c_str 6. size 7. operator[ ] 7.1 普通版 7.2 const版本 8. 迭代器—iterator 8.1 普通版iterator 8.2 const版本iterator 9. 尾插 10. …

数学笔记——直角坐标方程转参数方程

目录 背景第一步&#xff0c;原式转换成参数方程第二步&#xff0c;将参数方程绕x轴旋转一周结果程序与图形注 背景 学习matlab三维作图时遇到的一道题&#xff0c;搞不懂为什么要将直角方程转换成参数方程&#xff0c;在经过多次直角作图失败后&#xff0c;还是决定老老实实学…

Redis入门到实战(四、原理篇)RESP协议

目录 2、Redis内存回收-过期key处理3、Redis内存回收-内存淘汰策略 Redis是一个CS架构的软件&#xff0c;通信一般分两步&#xff08;不包括pipeline和PubSub&#xff09;&#xff1a; 客户端&#xff08;client&#xff09;向服务端&#xff08;server&#xff09;发送一条命令…

【LeetCode-数组】-- 寻找数组的中心索引

寻找数组的中心索引 class Solution {public int pivotIndex(int[] nums) {int n nums.length,sum 0;for(int i 0;i<n;i){ //计算所有元素之和sumnums[i];}int sum_l 0; //统计左边元素之和for(int i 0;i<n;i){sum - nums[i];if(sum_l sum){return i;}sum_l nums…

Django中ORM框架的各个操作

我们会好奇&#xff0c;python这么简洁的语言&#xff0c;数据查询是如何做的呢&#xff1f;我将进一步详细和深入地介绍Django中ORM框架的各个方面&#xff0c;包括MySQL的增删改查和复杂查询。让我们分步骤进行。 ORM框架介绍 Django的ORM框架是一个用于与数据库进行交互的工…

基于java的校园论坛系统,ssm+jsp,Mysql数据库,前台用户+后台管理,完美运行,有一万多字论文

目录 演示视频 基本介绍 论文目录 功能架构 系统截图 演示视频 基本介绍 基于java的校园论坛系统&#xff0c;Mysql数据库&#xff0c;系统整体采用ssmjsp设计&#xff0c;前台用户后台管理&#xff0c;完美运行&#xff0c;有一万多字论文。 用户功能&#xff1a; 1.系统…

分类预测 | MATLAB实现基于GRU-AdaBoost门控循环单元结合AdaBoost多输入分类预测

分类预测 | MATLAB实现基于GRU-AdaBoost门控循环单元结合AdaBoost多输入分类预测 目录 分类预测 | MATLAB实现基于GRU-AdaBoost门控循环单元结合AdaBoost多输入分类预测预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 1.MATLAB实现基于GRU-AdaBoost门控循环单元结…

【四:httpclient的使用】

目录 1、Demo案例2、请求一个带cookies的get请求3、请求一个带cookies的post请求案例一&#xff0c;案例二的properties的配置 1、Demo案例 public class MyHttpClient {Testpublic void test1() throws IOException {//用来存放我们的结果String result;HttpGet get new Htt…

小黑子—Maven基础

Maven基础 一 小黑子的Maven学习1. Mavn的介绍2. Maven基础概念2.1 仓库2.2 坐标2.3 仓库配置 3. 手动写一个maven项目3.1 Maven项目构建命令3.2 插件创建工程 4. IDEA下的maven项目5. 依赖管理5.1 依赖配置5.2 依赖传递5.3 可选依赖&#xff08;不透明&#xff09;5.4 排除依赖…

【AI视野·今日Sound 声学论文速览 第二十七期】Tue, 17 Oct 2023

AI视野今日CS.Sound 声学论文速览 Tue, 17 Oct 2023 Totally 15 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Sound Papers LocSelect: Target Speaker Localization with an Auditory Selective Hearing Mechanism Authors Yu Chen, Xinyuan Qian, Zexu Pan, Ka…

Python逆向爬虫案例: 某网站AES逆向解密

前言 嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 环境使用: Python 3.8 Pycharm &#x1f447; &#x1f447; &#x1f447; 更多精彩机密、教程&#xff0c;尽在下方&#xff0c;赶紧点击了解吧~ python源码、视频教程、插件安装教程、资料我都准备好了&#xff0…

了解 AI :了解 AI 方面的一些术语 (中英文对照)

本心、输入输出、结果 文章目录 了解 AI &#xff1a;了解 AI 方面的一些术语 &#xff08;中英文对照&#xff09;前言AI 方面的一些术语 &#xff08;中英文对照&#xff09;AI 方面的一些术语 &#xff08;中英文对照&#xff09; - 文字版弘扬爱国精神 了解 AI &#xff1a…

网工内推 | IT主管、高级网工,上市公司,必须持有HCIE认证

01 深圳市飞荣达科技股份有限公司 招聘岗位&#xff1a;高级网络工程师 职责描述&#xff1a; 1. 参与、负责集团公司IT基础技术架构的规划设计、实施及维护、性能优化&#xff0c;包括数据中心机房、网络架构、虚拟化平台、信息安全设备及灾备系统等&#xff1b; 2. 负责集团…

如何给Github上的开源项目提交PR?

前言 对于一个热爱开源的程序员而言&#xff0c;学会给GitHub上的开源项目提交PR这是迈出开源的第一步。今天我们就来说说如何向GitHub的开源项目提交PR&#xff0c;当然你提交的PR可以是一个项目的需求迭代、也可以是一个Bug修复、再或者是一些内容文本翻译等等&#xff0c;并…

安装VSCode,提升工作效率!iPad Pro生产力进阶之路

文章目录 前言1. 本地环境配置2. 内网穿透2.1 安装cpolar内网穿透(支持一键自动安装脚本)2.2 创建HTTP隧道 3. 测试远程访问4. 配置固定二级子域名4.1 保留二级子域名4.2 配置二级子域名 5. 测试使用固定二级子域名远程访问6. iPad通过软件远程vscode6.1 创建TCP隧道 7. ipad远…