Django

文章目录

  • 安装CPython解释器
  • 下载Django
    • pytharm 方法
    • 命令方法
  • 创建项目
    • setting
      • 时间设置
        • 静态文件设置
    • 迁移项目
  • 运行Django项目
  • 创建应用
  • 把应用加入管理界面
    • 站点的标题修改
    • 应用标题修改
    • 字段加入管理
  • 增加证书
    • 一、使用Django-sslserver的方式
    • 二、使用自定义的证书
      • 1.如果需要https协议,需要以下3个库
      • 2.配置settings文件 在INSTALLED_APPS下添加
      • 3. 在终端使用命令运行
  • django字段
    • AutoField:
    • BooleanField:
    • CharField:
    • TextField:
    • CommaSeparatedIntegerField:
    • DateField:
    • DateTimeField:
    • EmailField:
    • FileField:
    • FilePathField:
    • FloatField:
    • ImageField:
    • IntegerField:
    • IPAddressField:
    • NullBooleanField:
    • PhoneNumberField:
    • PositiveIntegerField:
    • PositiveSmallIntegerField:
    • SlugField:
    • SmallIntegerField:
    • TimeField:
    • URLField:
    • USStateField:
    • XMLField:
    • 附:Field 选项
  • 模块中字段使用
    • 获取外键的值
    • 显示外键的值
    • related_name反向查询
    • 增加中文标识
    • 增加选择项
    • 增加筛选项
  • 增加富文本字段
    • 安装tinymce
    • 基本配置
    • 修改配置
    • 实现图片上传
    • 图片上传的问题
  • orm
  • 使用mysql
    • 安装MySQL
    • 配置默认编码为utf8
    • 创建mysql数据库
    • pycharm上安装pymysql
    • Django项目设置默认数据库为mysql
  • 模型数据迁移
  • 创建超级用户
    • 创建用户
    • 修改用户密码
  • 导入一个已存在的项目
    • 删除原有配置信息
    • 修改数据库连接处
    • 取消终端窗口高亮显示
  • 重建数据库记录
    • 更粗暴的方法
  • 请求方法
  • python开发的CBV和FBV
  • 跨站请求问题
    • 安装django-cors-headers
    • 配置settings.py
    • CORS_ORIGIN_ALLOW_ALL:
    • CORS_ORIGIN_WHITELIST:
    • CORS_ORIGIN_REGEX_WHITELIST:
    • CORS_URLS_REGEX:
    • CORS_ALLOW_METHODS:
    • CORS_ALLOW_HEADERS:
    • CORS_EXPOSE_HEADERS:
    • CORS_PREFLIGHT_MAX_AGE:
    • CORS_ALLOW_CREDENTIALS:
    • CSRF整合
    • CORS_REPLACE_HTTPS_REFERER
  • 其他问题
    • DEFAULT_AUTO_FIELD warnings
    • 报错:Forbidden (CSRF cookie not set.)

安装CPython解释器

可参考我的博文
https://blog.csdn.net/gsl371/article/details/120148727

下载Django

pytharm 方法

注意:如果是用pycharm开发,并且使用虚拟环境,这一步掠过。
可在pycharm中直接创建虚拟环境,项目和应用。
如下:
Django_第1张图片
然后在虚拟环境中使用pip安装需要的模块。
Django_第2张图片

命令方法

打开管理员命令窗口
指定版本为1.11.28,指定源为清华源

pip install django==1.11.28 -i https://pypi.tuna.tsinghua.edu.cn/simple

查看

C:\Users\gsl>pip list
Package    Version
---------- -------
Django     1.11.28
pip        21.0.1
pytz       2021.1
setuptools 28.8.0
C:\Users\gsl>django-admin

Type 'django-admin help ' for help on a specific subcommand.

Available subcommands:

[django]
    check
    compilemessages
    createcachetable
    dbshell
    diffsettings
    dumpdata
    flush
    inspectdb
    loaddata
    makemessages
    makemigrations
    migrate
    runserver
    sendtestemail
    shell
    showmigrations
    sqlflush
    sqlmigrate
    sqlsequencereset
    squashmigrations
    startapp
    startproject
    test
    testserver
Note that only Django core commands are listed as settings are not properly configured (error: Requested setting INSTALLED_APPS, but settings are not configured. You must either define the environment variable DJANGO_SETTINGS_MODULE or call settings.configure() before accessing settings.).

创建项目

创建项目testDjango

django-admin startproject testDjango

查看

C:\Users\gsl\testDjango>tree /F
卷 sys 的文件夹 PATH 列表
卷序列号为 0000006A 69B0:5632
C:.
│  manage.py
│
└─testDjango
        settings.py
        urls.py
        wsgi.py
        __init__.py

setting

时间设置

这个地方不设置会造成存储到数据库时间与当前时间不一致问题

首选需要对当前时区进行设置

在 settings.py 文件中 修改

TIME_ZONE = 'Asia/Shanghai'

然后还有一个非常重要的一点

USE_TZ = False

当两个地方都设置好了,此时存储到数据库的时间即为正确时间

静态文件设置
# 配置静态文件url
STATIC_URL = '/static/'

# 配置聚合静态文件存放目录,需要在根目录下事先创建这个目录
STATIC_ROOT = os.path.join(BASE_DIR, "static")

# 配置上传文件上传url
MEDIA_URL = "/media/"

# 配置上传文件上传存放目录,需要在根目录下事先创建这个目录
MEDIA_ROOT = os.path.join(BASE_DIR, "media")

迁移项目

迁移依赖
pip自动生成和安装requirements.txt

在原项目f生成requirements.txt文件

pip freeze > requirements.txt

在新项目安装requirements.txt依赖

pip install -r requirements.txt

运行Django项目

python manage.py runserver 

pycharm中运行项目
Django_第3张图片
修改配置
Django_第4张图片

可以修改启动端口
Django_第5张图片
如果是命令行创建项目,这里需要增加模板路径,pycharm可以帮助创建这些Django_第6张图片
setting文件

"""
Django settings for testDjango project.

Generated by 'django-admin startproject' using Django 1.11.28.

For more information on this file, see
https://docs.djangoproject.com/en/1.11/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.11/ref/settings/
"""

import os

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
# 项目的根目录
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '7w)f^*b^8nyy&1ep^4e9j!%c-g7#qd8^xd8zvw1@i_*9!hxt93'

# SECURITY WARNING: don't run with debug turned on in production!
# 生产环境要设成False
DEBUG = True

# 允许所有ip访问
ALLOWED_HOSTS = ['*']


# Application definition

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

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

ROOT_URLCONF = 'testDjango.urls'

# 模板,即html展示文件的模板
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',
            ],
        },
    },
]

WSGI_APPLICATION = 'testDjango.wsgi.application'


# Database
# https://docs.djangoproject.com/en/1.11/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}


# Password validation
# https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]


# Internationalization
# https://docs.djangoproject.com/en/1.11/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.11/howto/static-files/

STATIC_URL = '/static/'

static资源配置,名字不能错
Django_第7张图片
清楚缓存
Django_第8张图片

创建应用

方便模块化开发管理
进入项目文件夹

python manage.py startapp app01

生成的目录作用
Django_第9张图片

注册app
Django_第10张图片
优化代码
把业务逻辑从项目的urls移到app中的views
Django_第11张图片

Django_第12张图片

把应用加入管理界面

站点的标题修改

在这里插入图片描述

应用标题修改

Django_第13张图片

字段加入管理

Django_第14张图片

增加证书

django http转换为https
​​​​​​Django使用HTTPS有两种方式:

一、使用Django-sslserver的方式

安装django-sslserver

pip install django-sslserver  # 安装django-sslserver

INSTALLED_APPS = [

“sslserver”, # 在settings里面添加sslserver
]

python3 manage.py runsslserver 0.0.0.0:443 # 启动的时候使用runsslserver即可

这一种会报不是安全站点提示,因为证书不是受信任机构颁发的。

二、使用自定义的证书

首先要购买证书。

1.如果需要https协议,需要以下3个库

pip install django-extensions
pip install django-werkzeug-debugger-runserver
pip install pyOpenSSL

2.配置settings文件 在INSTALLED_APPS下添加

‘werkzeug_debugger_runserver’,
‘django_extensions’,

3. 在终端使用命令运行

python manage.py runserver_plus --cert server.crt 0.0.0.0:443
或
python manage.py runserver_plus --cert server.pem 0.0.0.0:443

django字段

Django model字段类型清单
Django 通过 models 实现数据库的创建、修改、删除等操作,本文为模型中一般常用的类型的清单,便于查询和使用:

AutoField:

一个自动递增的整型字段,添加记录时它会自动增长。你通常不需要直接使用这个字段;如果你不指定主键的话,系统会自动添加一个主键字段到你的model。(参阅自动主键字段)

BooleanField:

布尔字段,管理工具里会自动将其描述为checkbox。

CharField:

字符串字段,单行输入,用于较短的字符串,如要保存大量文本, 使用 TextField,CharField有一个必填参数:

CharField.max_length:字符的最大长度,django会根据这个参数在数据库层和校验层限制该字段所允许的最大字符数。

TextField:

一个容量很大的文本字段, admin 管理界面用 多行编辑框表示该字段数据。

CommaSeparatedIntegerField:

用于存放逗号分隔的整数值。类似 CharField,必须maxlength 参数。

DateField:

日期字段,admin 用一个文本框 来表示该字段数据(附带一个 JavaScript 日历和一个”Today”快捷按键。有下列额外的可选参数:

auto_now:当对象被保存时,自动将该字段的值设置为当前时间.通常用于表示 “last-modified” 时间戳;
auto_now_add:当对象首次被创建时,自动将该字段的值设置为当前时间.通常用于表示对象创建时间。

DateTimeField:

类似 DateField 支持同样的附加选项。

EmailField:

一个带有检查 Email 合法性的 CharField,不接受 maxlength 参数。

FileField:

一个文件上传字段。 要求一个必须有的参数: upload_to, 一个用于保存上载文件的本地文件系统路径。 这个路径必须包含 strftime formatting, 该格式将被上载文件的 date/time 替换(so that uploaded files don’t fill up the given directory)。在一个 model 中使用 FileField 或 ImageField 需要以下步骤:在你的 settings 文件中, 定义一个完整路径给 MEDIA_ROOT 以便让 Django在此处保存上传文件。 (出于性能考虑,这些文件并不保存到数据库。) 定义 MEDIA_URL 作为该目录的公共 URL。 要确保该目录对 WEB 服务器用户帐号是可写的。在你的 model 中添加 FileField 或 ImageField, 并确保定义了 upload_to 选项,以告诉 Django 使用 MEDIA_ROOT 的哪个子目录保存上传文件。你的数据库中要保存的只是文件的路径(相对于 MEDIA_ROOT)。 出于习惯你一定很想使用 Django 提供的 get__url 函数。举例来说,如果你的 ImageField 叫作 mug_shot, 你就可以在模板中以 {{ object。get_mug_shot_url }} 这样的方式得到图像的绝对路径。

FilePathField:

选择指定目录按限制规则选择文件,有三个参数可选, 其中”path”必需的,这三个参数可以同时使用, 参数描述:

path:必需参数,一个目录的绝对文件系统路径。 FilePathField 据此得到可选项目。 Example: “/home/images”;
match:可选参数, 一个正则表达式, 作为一个字符串, FilePathField 将使用它过滤文件名。 注意这个正则表达式只会应用到 base filename 而不是路径全名。 Example: “foo。*\。txt^”, 将匹配文件 foo23.txt 却不匹配 bar.txt 或 foo23.gif;
recursive:可选参数, 是否包括 path 下全部子目录,True 或 False,默认值为 False。
match 仅应用于 base filename, 而不是路径全名。 如:FilePathField(path=”/home/images”, match=”foo.*”, recursive=True)…会匹配 /home/images/foo.gif 而不匹配 /home/images/foo/bar.gif

FloatField:

浮点型字段。 必须提供两个 参数, 参数描述:

max_digits:总位数(不包括小数点和符号)
decimal_places:小数位数。如:要保存最大值为 999 (小数点后保存2位),你要这样定义字段:models.FloatField(…,max_digits=5decimal_places=2),要保存最大值一百万(小数点后保存10位)的话,你要这样定义:models.FloatField(…,max_digits=19decimal_places=10)

ImageField:

类似 FileField, 不过要校验上传对象是否是一个合法图片。它有两个可选参数:height_field 和 width_field,如果提供这两个参数,则图片将按提供的高度和宽度规格保存。 该字段要求 Python Imaging 库。

IntegerField:

用于保存一个整数。

IPAddressField:

一个字符串形式的 IP 地址, (如 “202.1241.30″)。

NullBooleanField:

类似 BooleanField, 不过允许 NULL 作为其中一个选项。 推荐使用这个字段而不要用 BooleanField 加 null=True 选项。 admin 用一个选择框 (三个可选择的值: “Unknown”, “Yes” 和 “No” ) 来表示这种字段数据。

PhoneNumberField:

一个带有合法美国风格电话号码校验的 CharField(格式:XXX-XXX-XXXX)。

PositiveIntegerField:

类似 IntegerField, 但取值范围为非负整数(这个字段应该是允许0值的…可以理解为无符号整数)

PositiveSmallIntegerField:

正小整型字段,类似 PositiveIntegerField, 取值范围较小(数据库相关)

SlugField:

是一个报纸术语. slug 是某个东西的小小标记(短签), 只包含字母,数字,下划线和连字符.它们通常用于URLs。

SmallIntegerField:

类似 IntegerField, 不过只允许某个取值范围内的整数。(依赖数据库)

TimeField:

时间字段,类似于 DateField 和 DateTimeField。

URLField:

用于保存 URL。 若 verify_exists 参数为 True (默认), 给定的 URL 会预先检查是否存在(即URL是否被有效装入且没有返回404响应)。

USStateField:

美国州名缩写,由两个字母组成(天朝人民无视)。

XMLField:

XML字符字段,校验值是否为合法XML的 TextField,必须提供参数:
schema_path:校验文本的 RelaxNG schema 的文件系统路径。

附:Field 选项

null :缺省设置为false.通常不将其用于字符型字段上,比如CharField,TextField上.字符型字段如果没有值会返回空字符串。
blank:该字段是否可以为空。如果为假,则必须有值
choices:一个用来选择值的2维元组。第一个值是实际存储的值,第二个用来方便进行选择。如SEX_CHOICES= ((‘F’,'Female’),(‘M’,'Male’),)
core:db_column,db_index 如果为真将为此字段创建索引
default:设定缺省值
editable:如果为假,admin模式下将不能改写。缺省为真
help_text:admin模式下帮助文档
primary_key:设置主键,如果没有设置django创建表时会自动加上:
radio_admin:用于admin模式下将select转换为radio显示。只用于ForeignKey或者设置了choices
unique:数据唯一
unique_for_date:日期唯一,如下例中系统将不允许title和pub_date两个都相同的数据重复出现
title = meta.CharField(maxlength=30,unique_for_date=’pub_date’)
unique_for_month / unique_for_year:用法同上
validator_list:有效性检查。非有效产生 django.core.validators.ValidationError 错误

模块中字段使用

获取外键的值

Django_第15张图片

Django_第16张图片

显示外键的值

当将对象类别表示为字符串时,必须告诉django要显示什么。例如
Django_第17张图片

Django_第18张图片

related_name反向查询

模型中外键字段,多的一方,添加related_name属性。
Django_第19张图片
序列化中,做子的序列化。可获得子的内容,否则,只能获得一个占位值。
Django_第20张图片
结果
Django_第21张图片
不做子序列化结果
Django_第22张图片

增加中文标识

Django_第23张图片

增加选择项

对于简单的选择,可以不用通过建表外键关联实现选择。简洁快速。
Django_第24张图片

增加筛选项

Django_第25张图片
其他的方法


class ProductListByCategoryView(generics.ListAPIView):
    '''产品类别列表'''
    serializer_class = ProductListSerializer
    permissin_classes = (permissions.AllowAny,)
    filter_backends = (OrderingFilter, SearchFilter)
    ordering_fields = ('category', 'manufacturer', 'created', 'sold', 'stock', 'price',)
    search_fields = ('description',)
    ordering = ('id',)
    '''查询集根据条件获取'''

    def get_queryset(self):
        category = self.request.query_params.get('category', None)

        if category is not None:
            queryset = Product.objects.filter(category=category)
        else:
            queryset = Product.objects.all()

        return queryset


class ProductListByCategoryManufacturerView(generics.ListAPIView):
    '''产品按类别品牌列表'''
    serializer_class = ProductListSerializer
    permissin_classes = (permissions.AllowAny,)
    filter_backends = (OrderingFilter, SearchFilter)
    ordering_fields = ('category', 'manufacturer', 'created', 'sold', 'stock', 'price',)
    search_fields = ('description',)
    ordering = ('id',)

    def get_queryset(self):
        category = self.request.query_params.get('category', None)
        manufacturer = self.request.query_params.get('manufacturer', None)

        if category is not None:
            queryset = Product.objects.filter(category=category, manufacturer=manufacturer)
        else:
            queryset = Product.objects.all()

        return queryset


class ProductRetrieveView(generics.RetrieveAPIView):
    queryset = Product.objects.all()
    serializer_class = ProductRetrieveSerializer
    permission_classes = (permissions.AllowAny,)


class UserInfoView(APIView):
    '''用户基本信息'''
    permission_classes = (permissions.IsAuthenticated,)

    def get(self, request, format=None):
        user = self.request.user
        serializer = UserInfoSerializer(user)
        return Response(serializer.data)


class UserProfileRUView(generics.RetrieveUpdateAPIView):
    '''用户其他信息'''
    serializer_class = UserProfileSerializer
    permission_classes = (permissions.IsAuthenticated,)  # 需要认证

    ''' 只能当前用户'''

    def get_object(self):
        user = self.request.user
        obj = UserProfile.objects.get(user=user)
        return obj


class UserCreateView(generics.CreateAPIView):
    '''用户创建'''
    serializer_class = UserSerializer


class DeliveryAddressLCView(generics.ListCreateAPIView):
    '''收货地址LC'''
    serializer_class = DeliveryAddressSerilizer  # 没有加LC,因为较简单
    permission_classes = (permissions.IsAuthenticated,)  # 需要登陆认证

    def get_queryset(self):
        user = self.request.user
        queryset = DeliveryAddress.objects.filter(user=user)  # 模型来的对象
        return queryset

    def perform_create(self, serializer):
        user = self.request.user
        s = serializer.save(user=user)
        profile = user.profile_of  # profile_of 反向关系,从models来
        profile.delivery_address = s  # 把新创建的收货地址设为默认地址存入用户扩展信息中
        profile.save()


class DeliveryAddressRUDView(generics.RetrieveUpdateDestroyAPIView):
    '''收货地址RUD'''
    serializer_class = DeliveryAddressSerilizer
    permission_classes = (permissions.IsAuthenticated,)

    def get_object(self):
        user = self.request.user
        # obj =DeliveryAddress.objects.get(user=user)
        try:
            obj = DeliveryAddress.objects.get(id=self.kwargs['pk'], user=user)  # id由前端传来,一个用户有多个id
        except Exception as e:
            raise NotFound('no found')
        return obj


class CartListView(generics.ListAPIView):
    '''购物车列表'''
    serializer_class = OrderListSerializer  # 可以和订单公用一个序列器
    permissin_classes = (permissions.IsAuthenticated,)

    def get_queryset(self):
        user = self.request.user
        queryset = Order.objects.filter(user=user, status='0')  # 订单状态为零的,表示在购物车
        return queryset


class OrderListView(generics.ListAPIView):
    '''订单列表'''
    serializer_class = OrderListSerializer  # 和cart公用一个序列化器
    permissin_classes = (permissions.IsAuthenticated,)

    def get_queryset(self):
        user = self.request.user
        queryset = Order.objects.filter(user=user, status__in=['1', '2', '3', '4'])  # status__in 是django用法,表示值在。。范围
        return queryset


class OrderCreateView(generics.CreateAPIView):
    '''创建订单'''
    queryset = Order.objects.all()
    serializer_class = OrderCreateSerializer
    permission_classes = (permissions.IsAuthenticated,)

    def perform_create(self, serializer):
        user = self.request.user
        product = serializer.validated_data.get('product')
        serializer.save(user=user, price=product.price, address=user.profile_of.delivery_address, )

        logging.info('user %d cart changed,product %d related.Time is %s.', user.id, product.id,
                     str(datetime.datetime.now()))


class OrderRUDView(generics.RetrieveUpdateDestroyAPIView):
    '''OrderRUD'''
    serializer_class = OrderRUDSerializer
    permission_classes = (permissions.IsAuthenticated,)

    def get_object(self):
        user = self.request.user
        obj = Order.objects.get(user=user, id=self.kwargs['pk'])
        return obj

    def perform_update(self, serializer):
        user = self.request.user
        serializer.save(user=user, status='1')

增加富文本字段

安装tinymce

Install django-tinymce using pip (or any other way to install python package) from PyPI. If you need to use a different way to install django-tinymce you can place the tinymce module on your Python path. You can put it into your Django project directory or run python setup.py install from a shell.

pip install django-tinymce

在虚拟环境下,包或者应用被安装为如下位置。
Django_第26张图片

基本配置

在项目设置中修改。
Add tinymce to INSTALLED_APPS in settings.py for your project:

INSTALLED_APPS = (
    ...
    'tinymce',
    ...
)

Add tinymce.urls to urls.py for your project:

urlpatterns = patterns('',
    ...
    path('tinymce/', include('tinymce.urls')),
    ...
)

修改配置

修改配置以满足需要。
Django_第27张图片
项目的配置能覆盖掉虚拟环境中安装的tinymce setting.py中的配置。
前者修改比较方便。
修改后的界面
Django_第28张图片

实现图片上传

要使TinyMCE能够上传图片,需要如下几步:

第1步:上传图片,首先要启用图片插件

在plugins参数中把image加进去。

第2步:在工具栏显示图片工具按钮

在toolbar参数中把image加进去。

此时,点图片按钮是没有上传选项的,只能添加图片地址。

第3步:加入配置参数images_upload_url

此参数用于指定一个接受上传文件的后端处理程序地址,例如:

'images_upload_url': '/upload_image/',

如果返回的地址是相对路径,还有一个参数images_upload_base_path,可以给出访问的基本路径。

'images_upload_base_path': '你的网站的地址,域名或ip'

修改后如下:
Django_第29张图片

后端处理程序代码

# 图片上传
@csrf_exempt
def upload_image(request):
    if request.method == "POST":
        file_obj = request.FILES['file']
        file_name_suffix = file_obj.name.split(".")[-1]
        if file_name_suffix not in ["jpg", "png", "gif", "jpeg", ]:
            return JsonResponse({"message": "错误的文件格式"})

        upload_time = timezone.now()
        path = os.path.join(
            settings.MEDIA_ROOT,
            'tinymce',
            str(upload_time.year),
            str(upload_time.month),
            str(upload_time.day)
        )
        # 如果没有这个路径则创建
        if not os.path.exists(path):
            os.makedirs(path)

        file_path = os.path.join(path, file_obj.name)

        file_url = f'{settings.MEDIA_URL}tinymce/{upload_time.year}/{upload_time.month}/{upload_time.day}/{file_obj.name}'

        if os.path.exists(file_path):
            return JsonResponse({
                "message": "文件已存在",
                'location': file_url
            })

        with open(file_path, 'wb+') as f:
            for chunk in file_obj.chunks():
                f.write(chunk)

        return JsonResponse({
            'message': '上传图片成功',
            'location': file_url
        })
    return JsonResponse({'detail': "错误的请求"})

后端处理程序位置
Django_第30张图片

图片上传的问题

在真机环境中,需要访问的图片地址是域名地址,http协议即可,不必https。
tinymce的配置需要更改下,否则上传后,在django后台一保存,即转换为相对路径,不是域名地址。
在这里插入图片描述
另外,微信对域名的解析的辨识也是比较慢的,一开始以为有问题,过了会自己正常了。

orm

在models.py中创建类,对应在数据库中生成表和字段

对应关系
类—》表
对象—》数据行
属性—》字段
Django_第31张图片Django_第32张图片

下载驱动
Django_第33张图片
Django_第34张图片

使用mysql

下载
https://downloads.mysql.com/archives/community/
Django_第35张图片

安装MySQL

在输入框内输入cmd,以管理员的身份运行,注意这里一定一定一定要以管理员的身份运行,否则在安装过程中会出现因为管理权限不够而导致的Install/Remove of the Service Denied!(安装/卸载服务被拒绝),这一点非常重要!

输入安装命令:mysqld -install,若出现Service successfully installed,证明安装成功;如出现Install of the Service Denied,则说明没有以管理员权限来运行cmd:

Django_第36张图片
下载 VC redist packages for x64,下载完成,点击运行即可
在这里插入图片描述
然后继续输入命令:mysqld --initialize,如果执行mysqld --initialize-insecure则不会创建密码。此时不会有任何提示:
再输入启动命令:net start mysql,出现以下提示证明MySQL启动成功:
Django_第37张图片

设置MySQL密码
在MySQL解压文件下的data文件夹下的.err文件中查看错误日志,找到root用户默认初始化密码。
在这里插入图片描述

进入mysql安装目录的bin文件夹

mysql -uroot -pzR3ENye8o.dW;      
alter user 'root'@'localhost' identified by '123';

配置默认编码为utf8

修改前

mysql> show variables like '%character%';
+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | utf8                       |
| character_set_connection | utf8                       |
| character_set_database   | latin1                     |
| character_set_filesystem | binary                     |
| character_set_results    | utf8                       |
| character_set_server     | latin1                     |
| character_set_system     | utf8                       |
| character_sets_dir       | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
8 rows in set (0.01 sec)

修改/etc/my.cnf配置文件,在[mysqld]下添加编码配置,如下所示:

[mysqld]
character_set_server=utf8
init_connect='SET NAMES utf8'

windows版免安装没有这个文件,可以创建一个
Django_第38张图片

重新启动mysql服务,查看数据库默认编码如下所示

mysql> show variables like '%character%';
+--------------------------+----------------------------+
| Variable_name            | Value                      |
+--------------------------+----------------------------+
| character_set_client     | utf8                       |
| character_set_connection | utf8                       |
| character_set_database   | utf8                       |
| character_set_filesystem | binary                     |
| character_set_results    | utf8                       |
| character_set_server     | utf8                       |
| character_set_system     | utf8                       |
| character_sets_dir       | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
8 rows in set (0.00 sec)

创建mysql数据库

create database login;
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| login              |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
5 rows in set (0.00 sec)

pycharm上安装pymysql

Django_第39张图片

Django项目设置默认数据库为mysql

Django_第40张图片
习惯上把后俩个行写入项目初始化文件中__init__.py中

import pymysql
pymysql.install_as_MySQLdb()

# 

模型数据迁移

Django可以通过类创建表,然后迁移到数据库中。
制作迁移文件,或检查所有app下的models.py的变化,记录变化

python manage.py makemigrations

Django_第41张图片
执行迁移,同步model.py中变化到数据库

python manage.py migrate

Django_第42张图片
Django_第43张图片
Django_第44张图片
优化判断
在这里插入图片描述

创建超级用户

创建用户

C:\djproject\helloworld>python manage.py createsuperuser
Username (leave blank to use 'administrator'): admin
Email address: [email protected]
Password:123
Password (again):123
This password is too short. It must contain at least 8 characters.
This password is too common.
This password is entirely numeric.
Bypass password validation and create user anyway? [y/N]: y
Superuser created successfully.

user表中增加了一条记录
在这里插入图片描述

修改用户密码

python manage.py changepassword username

导入一个已存在的项目

删除原有配置信息

删除这个文件夹
Django_第45张图片
如果不删除,有标记,原来的环境配置信息。
Django_第46张图片

修改数据库连接处

Django_第47张图片

取消终端窗口高亮显示

Django_第48张图片

重建数据库记录

django删除数据库表后重建表总共分为四步

1.在数据库中删除对应的表
Django_第49张图片
2.删除表django_migrations中要删除表所在项目的记录

Django_第50张图片
3.删除此表对应的app目录下所有的临时生成的文件,除了__init__.py 外。
删除项目的migrations文件夹中的所有 文件,除了__init__.py 文件
Django_第51张图片
这两个文件夹,及其子文件夹
Django_第52张图片
4.重新执行数据库迁移命令

python manage.py makemigrations
python manage.py migrate
D:\djproject\bookmanager>python manage.py makemigrations
Migrations for 'app01':
  app01\migrations\0001_initial.py
    - Create model Author
    - Create model Book
    - Create model Publisher
    - Add field publisher to book
    - Add field books to author

D:\djproject\bookmanager>python manage.py migrate
Operations to perform:
  Apply all migrations: admin, app01, auth, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying app01.0001_initial... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying sessions.0001_initial... OK

Django中删除和重建数据库中关于models类的映射数据库表的正确方法:

在Django中删除models类的映射数据库表需要在models.py中剪切或删除对应的models类:然后在控制台中执行:

python manage.py makemigrations(Django会重新对照你的models类与数据库中的映射表,如果你的model类被删除,则Django会生成一个删除迁移)
python manage.py migrate(执行删除迁移,删除数据库中对应的model映射表)

数据库迁移问题:
在执行python manage.py makemigrations迁移命令之后,正常输出并生成迁移文件,但执行python manage.py migrate之后显示,No migrations to apply

,且查看数据库并没有生成对应的表;
解决办法:
1、首先删除migrations目录下的迁移文件
2、执行 python manage.py makemigrations your-app-name
3、mysql中执行delete from django_migrations where app = “your-app-name”;
4、重新执行迁移命令:python manage.py makemigrations your-app-name;python manage.py migrate your-app-name

更粗暴的方法

解决:“外键约束失败”,可能是数据迁移操作过程中出问题了,导致数据表里的对应关系混乱,简单粗暴的方法就是手动删除自己创建的App的migrations文件夹下除了__init__.py的所有文件(包括pycache文件夹),然后再手动删除根目录下的db.sqlite3文件(这里面存了数据库表)

运行数据迁移语句

python manage.py makemigrations
python manage.py migrate

此后,那些删除的东西都会重建,此时你会发现创建的管理员和用户,都被注销了(搜索会显示不存在),还有之前发送给服务端的数据也都消失了,得重新来过

# 创建管理员账号
(venv) E:\>python manage.py createsuperuser # 回车后出现如下语句
Username (leave blank to use 'administrator'): # 
Password: # 输入密码,此处无显示,也就是你输入了但没反应,直接回车就行
Password (again): # 重新输入密码确认,老规矩,不显示
# 此处可能弹出密码过于简单的提示,如果只是用来测试的账户,直接忽略继续就好了
# 然后就创建完成

# 创建普通用户
(venv) E:\>python manage.py shell
Python 3.8.1 (default, Mar  2 2020, 13:06:26) [MSC v.1916 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from django.contrib.auth.models import User
>>> user = User.objects.create_user('user1', '[email protected]', '123456')
>>> user.save()
>>> exit() # 退出终端

请求方法

post 和get
request.GET url上携带的参数 例如 ?k1=v1&k2=v2
request.POST post请求提交的数据的编码方式是URLencode,才有值
request.info 路径信息 不包含ip和端口 也不包含参数
request.body 请求体 bytes类型

Django_第53张图片

python开发的CBV和FBV

视图形式

FBV function based view

CBV class based view
CBV写法

引入已经存在的类
from django.views import View

class Xxx(View):     #定义一个类继承之
    # 定义函数,处理逻辑
    def get(self,request)
    	# 专门处理get请求
        return response
    
	def post(self,request)
    	# 专门处理post请求
        return response

执行流程中通过url引入类
通过类引入方法

url(r'xx/',Xxx.as_view())

as_view()的流程

  1. 项目运行时加载urls.py的文件,执行类.as_view()方法

  2. as_view()执行后,内部定义了一个view函数,并且返回。

  3. 请求到来的时候,执行view函数:

    1. 实例化类 —— 》 self

    2. self.request = request

    3. 执行self.dispatch(request, *args, **kwargs)的方法

      1. 判断请求方式是否被允许

        1. 允许:

          通过反射获取请求方式对应的请求方法 ——》 handler

          获取不到 self.http_method_not_allowed ——》 handler

        2. 不允许:

          self.http_method_not_allowed ——》 handler

      2. 执行handler,返回结果

跨站请求问题

跨站请求伪造(英语:Cross-site request forgery),也被称为 one-click attack 或者 session riding,通常缩写为 CSRF 或者 XSRF, 是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法
简单的说,就是为了防止CSRF攻击,需要一个cookie。

退出登录,回到登录界面,打开开发者工具(我用的是谷歌浏览器),追踪一下网络请求,发现登录的时候,除了用户名密码,还有一个 csrfmiddlewaretoken 参数,而 csrfmiddlewaretoken 参数来自于 cookie 中的 csrftoken。
  Django_第54张图片

安装django-cors-headers

C:\djproject\eshop>pip install django-cors-headers
Defaulting to user installation because normal site-packages is not writeable
Collecting django-cors-headers
  Downloading django_cors_headers-3.7.0-py3-none-any.whl (12 kB)
Requirement already satisfied: Django>=2.2 in c:\users\administrator\appdata\roaming\python\python38\site-packages (from django-cors-headers) (3.1.7)
Requirement already satisfied: sqlparse>=0.2.2 in c:\users\administrator\appdata\roaming\python\python38\site-packages (from Django>=2.2->django-cors-headers) (0.4.1)
Requirement already satisfied: asgiref<4,>=3.2.10 in c:\users\administrator\appdata\roaming\python\python38\site-packages (from Django>=2.2->django-cors-headers) (3.3.1)
Requirement already satisfied: pytz in c:\program files\python38\lib\site-packages (from Django>=2.2->django-cors-headers) (2021.1)
Installing collected packages: django-cors-headers
Successfully installed django-cors-headers-3.7.0

配置settings.py

INSTALLED_APPS = [
    ...
    'corsheaders',
    ...
]

MIDDLEWARE = [
    'corsheaders.middleware.CorsMiddleware',	# 放最前面
    ...
]

以下为可选配置

CORS_ORIGIN_ALLOW_ALL:

添加允许执行跨站点请求的主机

# 如果为True,则将不使用白名单,并且将接受所有来源。默认为False
CORS_ORIGIN_ALLOW_ALL = True	

CORS_ORIGIN_WHITELIST:

授权进行跨站点HTTP请求的来源列表。默认为[]

CORS_ORIGIN_WHITELIST = [
	"https://example.com""https://sub.example.com""http//localhost:8080",
    "http://127.0.0.1:9000",
]

CORS_ORIGIN_REGEX_WHITELIST:

代表正则表达式的字符串列表

CORS_ORIGIN_REGEX_WHITELIST = [
	r"^https://\w+\.example\.com$",
]

CORS_URLS_REGEX:

只需要在网站的一部分上使用CORS时很有用,例如位于的API /api/。

CORS_URLS_REGEX = r'^/api/.*$'

CORS_ALLOW_METHODS:

实际请求所允许的HTTP动词列表。

# 默认为
# CORS_ALLOW_METHODS = [
#     'DELETE',
#     'GET',
#     'OPTIONS',
#     'PATCH',
#     'POST',
#     'PUT',
# ]

# 自定义所允许的http动词列表
from corsheaders.defaults import default_methods
CORS_ALLOW_METHODS = list(default_methods) + [
    'POKE',
]

CORS_ALLOW_HEADERS:

发出实际请求时可以使用的非标准HTTP标头的列表。

# 默认为:
CORS_ALLOW_HEADERS = [
    'accept',
    'accept-encoding',
    'authorization',
    'content-type',
    'dnt',
    'origin',
    'user-agent',
    'x-csrftoken',
    'x-requested-with',
]

# 自定义http标头
from corsheaders.defaults import default_headers
CORS_ALLOW_HEADERS = list(default_headers) + [
    'my-custom-header',
]

CORS_EXPOSE_HEADERS:

将向浏览器公开的HTTP标头列表。默认为 []。

CORS_PREFLIGHT_MAX_AGE:

客户端/浏览器可以缓存预检响应的秒数。如果该值为0(或任何错误值),则不会发送最大期限标头。默认为 86400(一天)。

注意:预检请求是在发出“不太简单”的请求(例如Content-Type,不是 application/x-www-form-urlencoded)时确定的,它是确定服务器实际接受的请求的额外请求。

CORS_ALLOW_CREDENTIALS:

如果为True,则将允许将cookie包含在跨站点HTTP请求中。默认为False
在Django 2.1中,添加了SESSION_COOKIE_SAMESITE设置,'Lax’默认情况下设置为 ,这将防止Django的会话cookie跨域发送。更改它以None绕过此安全限制。

CSRF整合

大多数站点都需要利用Django提供的跨站点请求伪造保护。CORS和CSRF是分开的,并且Django无法使用您的CORS配置免除网站Referer对安全请求所做的检查。做到这一点的方法是使用其CSRF_TRUSTED_ORIGINS设置。例如:

CORS_ORIGIN_WHITELIST = [
    'http://read.only.com',
    'http://change.allowed.com',
]

CSRF_TRUSTED_ORIGINS = [
    'change.allowed.com',
]

CORS_REPLACE_HTTPS_REFERER

CSRF_TRUSTED_ORIGINS是Django 1.9中引入的,因此早期版本的用户将需要替代解决方案。如果CORS_REPLACE_HTTPS_REFERER为 True,CorsMiddleware则将Referer标头更改为每当CORS检查通过时将通过Django的CSRF检查的内容。默认为 False。

请注意,与不同CSRF_TRUSTED_ORIGINS,此设置不允许您区分CORS 信任读取资源的域和避免CSRF保护而信任更改资源的域。

启用此功能corsheaders.middleware.CorsPostCsrfMiddleware后django.middleware.csrf.CsrfViewMiddleware,还应该在之后 添加,MIDDLEWARE_CLASSES以撤消Referer替换:

MIDDLEWARE_CLASSES = [
    ...
    'corsheaders.middleware.CorsMiddleware',
    ...
    'django.middleware.csrf.CsrfViewMiddleware',
    'corsheaders.middleware.CorsPostCsrfMiddleware',
    ...
]

其他问题

DEFAULT_AUTO_FIELD warnings

当您在Django中定义一个没有指定主键的model时,Django将自动为您创建一个主键。主键设置为整数类型(integer)。如果要覆盖该字段类型,可以在每个模型(model)的基础上执行此操作。

从Django 3.2开始,您现在可以在您的设置(settings)中自定义自动创建的主键的类型。

在Django 3.2中开始新项目时,主键的默认类型设置为BigAutoField,这是一个64位整数(64 bit integer)。但是,早期版本将隐式主键的类型设置为整数(integer)。

这意味着当您升级到3.2版本时,您将开始看到有关您没有显式定义的主键类型的警告。满足Django对显式设置主键类型的要求很容易,但您还需要选择是否要将主键字段类型从整数升级到64位整数。

升级到3.2后,官方文档中的建议是运行以下代码:

python -Wa manage.py test

有几种方法可以解决这个问题。一般说来,它们分为两类:不需要迁移的和需要迁移的。

(一)不需要迁移的解决办法:No migrations
如果您想要最简单的升级路径而不需要迁移,则需要告诉Django将DEFAULT_AUTO_FIELD设置为Autofield,这在幕后是一个IntegerField。有几个地方可以做到这一点

(方法一)Configure DEFAULT_AUTO_FIELD in settings
打开项目的settings.py并在文件底部添加新行,本例用的此法。

DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'

(方法二)Setting on a per app basis
如果您更喜欢在每个应用程序(app)的基础上设置字段类型,而不是整个项目(project),您可以在apps.py中指定这一点。

如果您希望每个应用程序使用不同的自动字段类型,则可能需要执行此操作。对于带有博客应用程序的假设项目,在apps.py中添加default_auto_field行就可以了:

from django.apps import AppConfig
 
class BlogConfig(AppConfig):
    default_auto_field = 'django.db.models.AutoField'
    name = 'blog'

(二)迁移的解决办法:Migrations
如果您不介意创建和运行迁移,那么您可以使用新的BigAutoField。同样,有几种方法可以实现这一点:

(1)Configure DEFAULT_AUTO_FIELD in settings to use BigAutoField
打开项目的settings.py并将以下内容添加到底部:

DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

然后,您需要创建并运行迁移以更新数据库以使用新的字段类型。迁移将改变model上的id字段。要在名为blog的假想应用程序中创建并运行迁移,您需要运行以下命令:

python manage.py makemigrations blog
 
python manage.py sqlmigrate blog <migration_number>

(2)Set default_auto_field to BigAutoField on a per app basis
如上所述,您可以针对每个应用程序(app)配置该设置,因此在apps.py中,您可以将DEFAULT_AUTO_FIELD设置为BigAutoField:

from django.apps import AppConfig
 
class BlogConfig(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'my_app'

并再次为您的应用程序创建和运行迁移。

(3)Set AutoField or BigAutoField on a per model basis
如果您喜欢更细粒度的控制,可以设置每个model的id字段。例如:Blog app可能有一个BlogPost model。您可以在每个model上显式设置一个id字段。
在假设的博客应用程序中,您可以修改blog/models.py

class BlogPost(models.Model):
    id = models.BigAutoField(primary_key=True)
    # ...other fields

如果您愿意,也可以将公共基础模型子类化。如果您有大量的model,或许可以省去一些打字工作。在假设的blog应用程序中,您将定义一个CommonBaseModel ,然后在每个Model中继承它

from django.db import models
 
class CommonBaseModel(models.Model):
    id = models.BigAutoField(primary_key=True)
 
    class Meta:
        abstract = True
 
 
# Create your models here.
class BlogPost(CommonBaseModel):
   # ...other fields

在前面两个示例中,如果您希望将主键保留为integer,则可以使用Autofield而不是BigAutoField。但是,您仍然需要进行并运行迁移以保持完全最新,因为您已经更改了模型定义。

报错:Forbidden (CSRF cookie not set.)

对使用django框架开发的web网页作接口测试时,使用POST方法请求数据时
出现报错: Forbidden (CSRF cookie not set.): ****

解决办法:项目文件中的setting.py中将csrf语句注释掉
Django_第55张图片

你可能感兴趣的:(django,python,python,django,后端)