Django学习

1 项目初始化

1.1 项目结构

D:.
│  manage.py          【项目管理、启动项目、创建app、数据管理、不要动】
├─djangoProject1
│      asgi.py		【接收网络请求、不要动】
│      settings.py	【项目配置、==常常操作==】
│      urls.py		【URL和函数的对应关系、==常常操作==】
│      wsgi.py		【接收网络请求、不要动】
│      __init__.py
│
└─templates 【pycharm启动项目自动,实际项目一般不需要】

1.2 取消csrf验证

如果觉得默认的crsf繁琐的话可以取消:

  1. 在settings.py 文件中找到这一行注释掉

image-20240728160833492

  1. 也可以不取消,可以在不需要csrf验证的函数上加上

    @csrf_exempt

image-20240728161309105

1.3 解决前端出现跨域问题-cors

  1. 首先在setting.py 找到这两个列表,在列表末尾添加,如图所示:
"corsheaders"
"corsheaders.middleware.CorsMiddleware",

image-20240728161946612

  1. 在setting.py文件文末添加这些话
CORS_ALLOW_CREDENTIALS = True
CORS_ORIGIN_ALLOW_ALL = True
# CORS_ORIGIN_WHITELIST = (
#     'http://127.0.0.1:8080',
# )
CORS_ALLOWED_ORIGINS_REGEXES = [
    r'^http://.*?$',
]
# CORS_ORIGIN_REGEXES_WHITELIST = (
#         r'^http://.*?$',
# )
CORS_ALLOW_METHODS = (
    'DELETE',
    'GET',
    'OPTIONS',
    'PATCH',
    'POST',
    'PUT',
    'VIEW',
)

CORS_ALLOW_HEADERS = (
    'XMLHttpRequest',
    'X_FILENAME',
    'accept-encoding',
    'authorization',
    'content-type',
    'dnt',
    'origin',
    'user-agent',
    'x-csrftoken',
    'x-requested-with',
    'Pragma',
)
ALLOWED_HOSTS = ['*']

1.4 设置默认浏览器报错信息为中文

在setting.py文件中找到LANGUAGE_CODE,将其值改为zh-hans

# LANGUAGE_CODE = 'en-us'
LANGUAGE_CODE = 'zh-hans'

1.5 修改数据库默认配置

同样在setting.py文件中找到默认的注释掉

# Database
# https://docs.djangoproject.com/en/5.0/ref/settings/#databases
# 默认是sqllite3
# DATABASES = {
#     'default': {
#         'ENGINE': 'django.db.backends.sqlite3',
#         'NAME': BASE_DIR / 'db.sqlite3',
#     }
# }
# 改成mysql
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'django_project1',
        'USER': 'root',  # 账号
        'PASSWORD': 'root',  # 你的密码
        'HOST': '127.0.0.1',
        'PORT': '3306',
    }
}

1.6 配置上传文件保存目录

如果项目涉及到上传文件可能要配置media

  1. 创建media文件夹

在项目根目录下创建,如图:

image-20240730110259455

  1. 修改setting.py
  • 在文件中加上这几行
# 文件上传
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'
  1. 配置urls.py

加上这句话

re_path(r'^media/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT}, name='media'),
  1. models 示例

image-20240730111011539

  • 最后一行的avatar中upload_to,如果使用ModelForm上传则会自动将上传文件保存至项目根路径+‘/media’+‘/image/admin’+文件名

  • 这时如果需要更新头像需要再ModelForm实例化是传入files参数,如图

image-20240730111530100

2 常用指令

使用该方法可以简化命令的输入

image-20240728160224125

2.1 生成数据库表

  1. 安装模块
pip install mysqlclient

在使用manage tools工具后的指令为:

默认如果不指定app名称则生成所有app中models(自动生成或更新数据库表)

  1. makemigrations app名称

  2. migrate app名称

生成的表:

mysql> show tables;
+---------------------------+
| Tables_in_django_project1 |
+---------------------------+
| app01_department          |
| app01_employee            |
| django_migrations         |
+---------------------------+

2.2 启动Django项目

  1. 安装Django
pip install django
  1. 创建Django项目
 django-admin startproject 项目名
  1. 创建APP&注册
python manage.py startapp app名称

例如runserver 8080

image-20240728160407565

3 工具类

3.1 md5加密

哈希化不可逆,比较密码正确性需要先加密为密文再比较

代码:

import hashlib

from djangoProject1 import settings


def md5(password):
    #加盐
    #django提供了随机的
    obj = hashlib.md5(settings.SECRET_KEY.encode('utf-8'))
    # 哈希之前需要先转码
    obj.update(password.encode('utf-8'))
    return obj.hexdigest()

3.2 分页插件

  1. 代码:

range(page_start,page_end + 1)返回迭代器方便前端{{}}模版进行遍历

import math
class Pagination:
    """
    @:var
    entities: 为需要分页的所有实体
    self.page = page 当前页
    self.page_size = page_size 每页展示多少个实体
    self.parm_dict = parm_dict 为了后续对字典进行解包,在context中解包
    @:def
        def is_illegal(self): 如果遇到错误,该函数返回False
        def get_illegal_content(self): 返回错误信息
    """

    def __init__(self, request, entities):
        self.legal = True
        page = request.GET.get('page', '1')
        page_size = request.GET.get('page_size', '10')
        if page and str(page).isdecimal():
            page = int(page)
        if page_size and str(page_size).isdecimal():
            page_size = int(page_size)
        page_total = math.ceil(len(entities) / page_size)
        if page_total < page or page < 1:
            self.legal = False
            self.illegal_content = '页数不合理请重新输入!!'
        start = (page - 1) * page_size
        end = page * page_size
        page_entities = entities[start:end]

        if page_total >= 10:
            page_start = page - 5 if page - 5 >= 5 else 1
            page_end = page + 5 if page + 5 <= page_total else page_total
            if page_end == page_total:
                page_start = page_start - (10 - (page_end - page_start + 1))
            if page_start == 1:
                page_end = page_end + 10 - (page_end - page_start + 1)
        else:
            page_start = 1
            page_end = page_total
        parm_dict = {'pages': range(page_start,
                                    page_end + 1), 'current_page': page,
                     'page_size': page_size, 'page_total': page_total,
                     'entities': page_entities}
        self.page = page
        self.page_size = page_size
        self.parm_dict = parm_dict

    def page_parm(self):
        return self.parm_dict

    def is_illegal(self):
        return not self.legal

    def get_illegal_content(self):
        return self.illegal_content

  1. 使用案例:

应用于后台管理系统返回表格的分页功能

  • 后端渲染函数:
def depart_list(request):
    query = {'name__contains': request.GET.get('content', '')}
    departments = models.Department.objects.filter(**query)
    pagination = Pagination(request, entities=departments)
    if pagination.is_illegal():
        return error(request, pagination.get_illegal_content())
    return render(request=request, template_name='depart_manage/depart_list.html',
                  context={'entities': departments, **pagination.page_parm()}
                  )
  • 前端代码:
<nav aria-label="...">
    <ul class="pagination">

        <li class="page-item {% if current_page == 1 %}disabled{% endif %}">
            <a class="page-link" href="?page={{ current_page|add:-1 }}&content={{ content }}">Prev</a>
        </li>
        {% for page in pages %}
            <li class="page-item {% if page == current_page %}active{% endif %}">
                <a class="page-link"
                   href="?page={{ page }}&content={{ content }}">{{ page }}</a>
            </li>
        {% endfor %}
        <li class="page-item">
            <a class="page-link {% if current_page == page_total %}disabled{% endif %}"
               href="?page={{ current_page|add:1 }}&content={{ content }}">Next</a>
        </li>
        <li class="page-item" >
            <form class="input-group mb-3" method="get">
                <input type="text" class="form-control" placeholder="页码,共:{{ page_total }}页"
                       name="page" required
                       aria-label="Recipient's username" aria-describedby="button-addon2">
                <button class="btn btn-outline-success" type="submit" id="button-addon2">
                    跳转
                </button>
            </form>
        </li>
    </ul>
</nav>

3.3 Bootstrap样式的modelForm表单:

  1. 代码
  • 后端代码:
from django import forms
class BootstrapModelForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        for name, field in self.fields.items():
            # 如果是密码框则用passwordinput防止密码直接显示
            if str(name).lower().__contains__('password'):
                field.widget = forms.PasswordInput(attrs={'class': 'form-control'})
            #form-control 为Bootstrap样式类
            if not field.widget.attrs.get('class'):
                field.widget.attrs['class'] = 'form-control '
            elif field.widget.attrs.get('class'):
                field.widget.attrs['class'] += ' form-control '
            if not field.widget.attrs.get('placeholder'):
                field.widget.attrs['placeholder'] = field.label
            #防止一个页面多个表单(对话框存在多个)从而出现多个标签具有同一个id的情况
            if not field.widget.attrs.get('id'):
                field.widget.attrs['id'] = False
  • 前端代码
<div class="modal-body">
    <form method="post" action="/emp/add" novalidate>
        {% csrf_token %}
        {% for field in add_form %}
            <div class="mb-3">
                <label class="col-form-label">{{ field.label }}</label>
                {{ field }}
            </div>
        {% endfor %}
        <div class="modal-footer" style="display: flex;justify-content: space-evenly">
            <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">关闭
            </button>
            <button type="submit" data-bs-dismiss="modal" class="btn btn-primary">添加</button>
        </div>
    </form>

</div>
  • 演示:

image-20240728161420413

3.4 前端生成日期时间选择控件

  1. 首先引入css:
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css">
  1. 引入js:
<script src="https://cdn.jsdelivr.net/npm/flatpickr"></script>
  1. js代码:
// 设置Flatpickr中文语言选项
flatpickr.l10ns.zh = {
    weekdays: {
        shorthand: ["周日", "周一", "周二", "周三", "周四", "周五", "周六"],
        longhand: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"]
    },
    months: {
        shorthand: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"],
        longhand: ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"]
    },
    rangeSeparator: " 至 ",
    weekAbbreviation: "周",
    scrollTitle: "滚动切换",
    toggleTitle: "点击切换 12/24 小时时制"
};

// 使用中文语言选项初始化Flatpickr
flatpickr(".datetime", {
    enableTime: true,
    dateFormat: "Y-m-d H:i",
    defaultDate: new Date(),
    locale: "zh",
    monthSelectorType: "dropdown", // 使用下拉选择框选择月份
    shorthandCurrentMonth: true, // 使用缩写月份
    weekdays: {
        shorthand: ["日", "一", "二", "三", "四", "五", "六"],
        longhand: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"]
    }
});

效果演示:

image-20240728161656673

3.5 中间件middleWare

  1. 使用前需要再setting.py文件中声明:

下面列表的添加最易一行,值为该python文件路径

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    # 取消掉csrf验证
    # 'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    "corsheaders.middleware.CorsMiddleware",
    "app01.middleware.auth.AuthMiddleware",
]
  1. 代码:
from django.utils.deprecation import MiddlewareMixin

from app01.views.common_views import error


class AuthMiddleware(MiddlewareMixin):
    """
        Middleware1
        中间件1
        """

    def process_request(self, request):
        if request.path_info in ['/login/', '/register/', '/logout/', '/image/code']:
            return
        if str(request).split('/')[1] in ['emp', 'depart'] and str(request).split('/')[2].isdecimal():
            return
        info_dict = request.session.get('info')
        print('info_dict==')
        print(info_dict)
        if info_dict:
            return
        return error(request=request, content='请先登录账号!!', is_login=False)
   """

def process_request(self, request):
    if request.path_info in ['/login/', '/register/', '/logout/', '/image/code']:
        return
    if str(request).split('/')[1] in ['emp', 'depart'] and str(request).split('/')[2].isdecimal():
        return
    info_dict = request.session.get('info')
    print('info_dict==')
    print(info_dict)
    if info_dict:
        return
    return error(request=request, content='请先登录账号!!', is_login=False)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值