Django(4.1版本)基础学习

1.安装django

       python不同版本安装不同的django版本

python版本: 3.10.8

django版本: 4.1.3

安装 django指定版本或最新版本

pip install django==4.1.3
pip install Django

卸载

 pip uninstall django

查看安装版本 

django-admin --version

2.启动Django

检查Django环境并使用django-admin命令创建Django项目(项目名称为jiangopro)。

django-admin --version
django-admin startproject djangopro

生成目录

pycharm 配置django启动环境

(如使用django环境需设置setting.py的上级目录为根目录)

或执行使用命令启动(cd 到项目目录 manage.py 同级),运行项目

python manage.py runserver

3.创建项目

        在PyCharm的终端中执行下面的命令,创建名为polls的应用。

python manage.py startapp polls

       生成项目结构

        

4.使用html模板

打开polls下的views.py添加

from django.shortcuts import render

from random import sample

def index(request):
    fruits = [
        'Apple', 'Orange', 'Pitaya', 'Durian', 'Waxberry', 'Blueberry',
        'Grape', 'Peach', 'Pear', 'Banana', 'Watermelon', 'Mango'
    ]
  
    selected_fruits = sample(fruits, 3)
 
    return render(request, 'polls/index.html', {'fruits': selected_fruits})

创建templates文件夹

        

        index.hml 内容 

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>首页</title>
        <style>
            #fruits {
                font-size: 1.25em;
            }
        </style>
    </head>
    <body>
        <h1>今天推荐的水果是3:</h1>
        <hr>
        <ul id="fruits">
            {% for fruit in fruits %}
            <li>{{ fruit }}</li>
            {% endfor %}
        </ul>
    </body>
</html>

在polls目录下添加urls.py文件

from django.urls import path

from . import views

urlpatterns = [
    path('', views.index, name='index'),
]

打开jiangopro目录下的urls.py 添加

from django.contrib import admin
from django.urls import path, include

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

打开settings.py,找到 INSTALLED_APPS,把应用添加,刷新页面就可以看到Html模板的内容,并设置项目时区,

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'polls',
]
# 修改为如下
LANGUAGE_CODE = 'zh-hans'

TIME_ZONE = 'Asia/Shanghai'

4.链接数据库

         引用文章

        先在数据库设计好表,修改settings.py的 DATABASES,设置好以后,在项目跟目录下执行命令 python manage.py inspectdb > [your app name]\models.py。 他的作用即使根据已经存在对的mysql数据库表来反向映射结构到models.py中.

DATABASES = {
    'default': {
        # 'ENGINE': 'django.db.backends.sqlite3',
        # 'NAME': BASE_DIR / 'db.sqlite3',
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'basename',
        'USER': 'youruser',
        'PASSWORD': 'yourpassword',
        'HOST': '127.0.0.1',
        'PORT': '3306',
        # 数据库使用的字符集
        'CHARSET': 'utf8',
        # 数据库时间日期的时区设定
        'TIME_ZONE': 'Asia/Shanghai',
    }
}
python manage.py inspectdb > polls\models.py

打开models.py调整模型,如果 报错 ValueError:source code string cannot contain null bytes ,需把models.py文件,在pcharm右下角把utf-16改成utf-8

from django.db import models


class Subject(models.Model):
    no = models.AutoField(primary_key=True, verbose_name='编号')
    name = models.CharField(max_length=50, verbose_name='名称')
    intro = models.CharField(max_length=1000, verbose_name='介绍')
    is_hot = models.BooleanField(verbose_name='是否热门')

    class Meta:
        managed = False
        db_table = 'tb_subject'


class Teacher(models.Model):
    no = models.AutoField(primary_key=True, verbose_name='编号')
    name = models.CharField(max_length=20, verbose_name='姓名')
    sex = models.BooleanField(default=True, verbose_name='性别')
    birth = models.DateField(verbose_name='出生日期')
    intro = models.CharField(max_length=1000, verbose_name='个人介绍')
    photo = models.ImageField(max_length=255, verbose_name='照片')
    good_count = models.IntegerField(default=0, db_column='gcount', verbose_name='好评数')
    bad_count = models.IntegerField(default=0, db_column='bcount', verbose_name='差评数')
    subject = models.ForeignKey(Subject, models.DO_NOTHING, db_column='sno')

    class Meta:
        managed = False
        db_table = 'tb_teacher'

也可以代码创建数据表,同步到数据库,在 polls/models.py :

from django.db import models


class Question(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField("date published")


class Choice(models.Model):
    question = models.ForeignKey(Question, on_delete=models.CASCADE)
    choice_text = models.CharField(max_length=200)
    votes = models.IntegerField(default=0)

        确保在setting.py添加了该应用

INSTALLED_APPS = [
    # Polls
    "polls.apps.PollsConfig",

    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
]

在 Django 项目会包含 polls 应用。接着运行下面的命令,通过运行 makemigrations 命令,花在migrations文件夹中生产迁移文件,Django 会检测你对模型文件的修改(在这种情况下,你已经取得了新的),并且把修改的部分储存为一次 迁移

python manage.py makemigrations polls

sqlmigrate 命令接收一个迁移的名称,执行这个迁移名称,会生成如下信息。

python manage.py sqlmigrate polls 0001
BEGIN;
--
-- Create model Question
--
CREATE TABLE "polls_question" (
    "id" bigint NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY,
    "question_text" varchar(200) NOT NULL,
    "pub_date" timestamp with time zone NOT NULL
);
--
-- Create model Choice
--
CREATE TABLE "polls_choice" (
    "id" bigint NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY,
    "choice_text" varchar(200) NOT NULL,
    "votes" integer NOT NULL,
    "question_id" bigint NOT NULL
);
ALTER TABLE "polls_choice"
  ADD CONSTRAINT "polls_choice_question_id_c5b4b260_fk_polls_question_id"
    FOREIGN KEY ("question_id")
    REFERENCES "polls_question" ("id")
    DEFERRABLE INITIALLY DEFERRED;
CREATE INDEX "polls_choice_question_id_c5b4b260" ON "polls_choice" ("question_id");

COMMIT;

请注意以下几点:

  • 输出的内容和你使用的数据库有关,上面的输出示例使用的是 PostgreSQL。
  • 数据库的表名是由应用名(polls)和模型名的小写形式( question 和 choice)连接而来。(如果需要,你可以自定义此行为。)
  • 主键(IDs)会被自动创建。(当然,你也可以自定义。)
  • 默认的,Django 会在外键字段名后追加字符串 "_id" 。(同样,这也可以自定义。)
  • 外键关系由 FOREIGN KEY 生成。你不用关心 DEFERRABLE 部分,它只是告诉 PostgreSQL,请在事务全都执行完之后再创建外键关系。
  • 它是为你正在使用的数据库定制的,因此特定于数据库的字段类型,例如“auto_increment”(MySQL)、“bigint PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY”(PostgreSQL)或“integer primary key autoincrement” `` (SQLite) 会自动为您处理。 字段名称的引用也是如此——例如,使用双引号或单引号。
  • 这个 sqlmigrate 命令并没有真正在你的数据库中的执行迁移 - 相反,它只是把命令输出到屏幕上,让你看看 Django 认为需要执行哪些 SQL 语句。这在你想看看 Django 到底准备做什么,或者当你是数据库管理员,需要写脚本来批量处理数据库时会很有用。
  • 如果你感兴趣,你也可以试试运行 python manage.py check ;这个命令帮助你检查项目中的问题,并且在检查过程中不会对数据库进行任何操作。

现在,再次运行 migrate 命令,在数据库里创建新定义的模型的数据表,在models.py更改业务代码

python manage.py migrate

6.静态文件管理

        在项目目录settings.py中添加

# 各自app的静态
STATIC_URL = 'static/'
# 项目根目录的静态文件
STATICFILES_DIRS = [
    BASE_DIR / "static",
    # "/var/www/static/",
]


# 生产环境 执行  python manage.py collectstatic 这将会把静态目录下的所有文件拷贝至 STATIC_ROOT 目录。
# STATIC_ROOT = "/var/www/example.com/static/"

7. session,cookie管理

        在项目目录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',
]
# 配置会话的超时时间为1天(86400秒)
SESSION_COOKIE_AGE = 86400

# 设置为True在关闭浏览器窗口时session就过期
SESSION_EXPIRE_AT_BROWSER_CLOSE = True

# 配置将会话对象放到缓存中存储
SESSION_ENGINE = 'django.contrib.sessions.backends.cache'
# 配置使用哪一组缓存来保存会话
SESSION_CACHE_ALIAS = 'default'

# 修改session数据默认的序列化方式,可以将默认的JSONSerializer修改为PickleSerializer。
SESSION_SERIALIZER = 'django.contrib.sessions.serializers.PickleSerializer'

8.redis缓存

使用 django-redis并修改settins.py配置

 pip install django-redis
CACHES = {
    'default': {
        # 指定通过django-redis接入Redis服务
        'BACKEND': 'django_redis.cache.RedisCache',
        # Redis服务器的URL
        'LOCATION': ['redis://1.2.3.4:6379/0', ],
        # Redis中键的前缀(解决命名冲突)
        'KEY_PREFIX': 'vote',
        # 其他的配置选项
        'OPTIONS': {
            'CLIENT_CLASS': 'django_redis.client.DefaultClient',
            # 连接池(预置若干备用的Redis连接)参数
            'CONNECTION_POOL_KWARGS': {
                # 最大连接数
                'max_connections': 512,
            },
            # 连接Redis的用户口令
            'PASSWORD': 'foobared',
        }
    },
}

声明式缓存

from django.views.decorators.cache import cache_page


@api_view(('GET', ))
@cache_page(timeout=86400, cache='default')
def show_subjects(request):
    """获取学科数据"""
    queryset = Subject.objects.all()
    data = SubjectSerializer(queryset, many=True).data
    return Response({'code': 20000, 'subjects': data})

类使用缓存

from django.utils.decorators import method_decorator
from django.views.decorators.cache import cache_page


@method_decorator(decorator=cache_page(timeout=86400, cache='default'), name='get')
class SubjectView(ListAPIView):
    """获取学科数据的视图类"""
    queryset = Subject.objects.all()
    serializer_class = SubjectSerializer

编程缓存

def show_subjects(request):
    """获取学科数据"""
    redis_cli = get_redis_connection()
    # 先尝试从缓存中获取学科数据
    data = redis_cli.get('vote:polls:subjects')
    if data:
        # 如果获取到学科数据就进行反序列化操作
        data = json.loads(data)
    else:
        # 如果缓存中没有获取到学科数据就查询数据库
        queryset = Subject.objects.all()
        data = SubjectSerializer(queryset, many=True).data
        # 将查到的学科数据序列化后放到缓存中
        redis_cli.set('vote:polls:subjects', json.dumps(data), ex=86400)
    return Response({'code': 20000, 'subjects': data})

缓存相关问题

缓存数据的更新

在使用缓存时,一个必须搞清楚的问题就是,当数据改变时,如何更新缓存中的数据。通常更新缓存有如下几种套路,分别是:

  1. Cache Aside Pattern
  2. Read/Write Through Pattern
  3. Write Behind Caching Pattern

第1种方式的具体做法就是,当数据更新时,先更新数据库,再删除缓存。注意,不能够使用先更新数据库再更新缓存的方式,也不能够使用先删除缓存再更新数据库的方式,大家可以自己想一想为什么(考虑一下有并发的读操作和写操作的场景)。当然,先更新数据库再删除缓存的做法在理论上也存在风险,但是发生问题的概率是极低的,所以不少的项目都使用了这种方式。

第1种方式相当于编写业务代码的开发者要自己负责对两套存储系统(缓存和关系型数据库)的操作,代码写起来非常的繁琐。第2种方式的主旨是将后端的存储系统变成一套代码,对缓存的维护封装在这套代码中。其中,Read Through指在查询操作中更新缓存,也就是说,当缓存失效的时候,由缓存服务自己负责对数据的加载,从而对应用方是透明的;而Write Through是指在更新数据时,如果没有命中缓存,直接更新数据库,然后返回。如果命中了缓存,则更新缓存,然后再由缓存服务自己更新数据库(同步更新)。刚才我们说过,如果自己对项目中的Redis操作再做一次封装,就可以实现“Read Through”和“Write Through”模式,这样做虽然会增加工作量,但无疑是一件“一劳永逸”且“功在千秋”的事情。

第3种方式是在更新数据的时候,只更新缓存,不更新数据库,而缓存服务这边会异步的批量更新数据库。这种做法会大幅度提升性能,但代价是牺牲数据的强一致性。第3种方式的实现逻辑比较复杂,因为他需要追踪有哪数据是被更新了的,然后再批量的刷新到持久层上。

缓存穿透

缓存是为了缓解数据库压力而添加的一个中间层,如果恶意的访问者频繁的访问缓存中没有的数据,那么缓存就失去了存在的意义,瞬间所有请求的压力都落在了数据库上,这样会导致数据库承载着巨大的压力甚至连接异常,类似于分布式拒绝服务攻击(DDoS)的做法。解决缓存穿透的一个办法是约定如果查询返回为空值,把这个空值也缓存起来,但是需要为这个空值的缓存设置一个较短的超时时间,毕竟缓存这样的值就是对缓存空间的浪费。另一个解决缓存穿透的办法是使用布隆过滤器,具体的做法大家可以自行了解。

缓存击穿

在实际的项目中,可能存在某个缓存的key某个时间点过期,但恰好在这个时间点对有对该key的大量的并发请求过来,这些请求没有从缓存中找到key对应的数据,就会直接从数据库中获取数据并写回到缓存,这个时候大并发的请求可能会瞬间把数据库压垮,这种现象称为缓存击穿。比较常见的解决缓存击穿的办法是使用互斥锁,简单的说就是在缓存失效的时候,不是立即去数据库加载数据,而是先设置互斥锁(例如:Redis中的setnx),只有设置互斥锁的操作成功的请求,才能执行查询从数据库中加载数据并写入缓存,其他设置互斥锁失败的请求,可以先执行一个短暂的休眠,然后尝试重新从缓存中获取数据,如果缓存还没有数据,则重复刚才的设置互斥锁的操作,大致的参考代码如下所示。

data = redis_cli.get(key)
while not data:
    if redis_cli.setnx('mutex', 'x'):
        redis.expire('mutex', timeout)
        data = db.query(...)
        redis.set(key, data)
        redis.delete('mutex')
    else:
        time.sleep(0.1)
        data = redis_cli.get(key)
缓存雪崩

缓存雪崩是指在将数据放入缓存时采用了相同的过期时间,这样就导致缓存在某一时刻同时失效,请求全部转发到数据库,导致数据库瞬时压力过大而崩溃。解决缓存雪崩问题的方法也比较简单,可以在既定的缓存过期时间上加一个随机时间,这样可以从一定程度上避免不同的key在同一时间集体失效。还有一种办法就是使用多级缓存,每一级缓存的过期时间都不一样,这样的话即便某个级别的缓存集体失效,但是其他级别的缓存还能够提供数据,避免所有的请求都落到数据库上。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Django Channels是一个基于Django开发的扩展,用于处理实时的、异步的网络通信。它使得开发者可以在Django应用中处理WebSockets、长轮询以及其他异步任务。 Django Channels的最新版本4.1。这个版本带来了许多改进和新特性。 首先,Channels 4.1增加了对WebSocket Server-Sent Events(SSE)的支持。SSE是一种基于HTTP的实时消息传输协议,通过将响应保持打开的方式,服务器可以持续地向客户端发送事件。这使得开发者可以使用SSE来实现服务器向客户端实时推送数据的功能。 其次,Channels 4.1还提供了一个新的channels-graphql插件,用于在Django Channels中处理GraphQL订阅。GraphQL是一种用于API开发的查询语言,通过订阅机制,可以实现实时更新数据的功能。channels-graphql插件使得开发者可以在Django应用中轻松地处理GraphQL订阅。 另外,Channels 4.1还改进了性能和可扩展性。它引入了一个新的并发模型,通过使用asyncio的事件循环来处理IO操作,提高了处理消息的效率。同时,Channels 4.1还支持在分布式系统中进行水平扩展,可以通过添加更多的worker节点来处理更多的请求。 总的来说,Django Channels 4.1是一个强大的工具,可以帮助开发者构建实时的、异步的网络应用。它提供了对WebSocket、SSE、GraphQL等实时通信协议的支持,同时还改进了性能和可扩展性。使用Channels 4.1,开发者可以轻松地构建具有实时功能的Web应用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值