广东外语外贸大学南国商学院的pythonweb大作业

yangyi 1ca1f78629 #config:dockerfile文件更新 hace 1 semana
pythonweb fbae85547e # db:数据维护 hace 1 mes
文章 4331173c98 # static:收集教师团队资料 hace 1 mes
.gitignore c97fd6408d # init:项目初始化 hace 2 meses
dockerfile 1ca1f78629 #config:dockerfile文件更新 hace 1 semana
readme.md 80828ca722 #doc:readme文件更新 hace 1 semana
requirements.txt c00d2fbe4a # config:环境依赖配置文件 hace 2 meses
图片素材.md def6a4f236 # static:学院简介模块的文章进行修正;并储存到数据库中 hace 1 mes

readme.md

广东外语外贸大学南国商学院-pythonweb大作业

参考IP:47.103.207.39

python版本3.7.x

项目代码仓库

参考网站:计算机学院官网

参考教程

名称 地址
Django https://www.runoob.com/django/django-tutorial.html
Bootstrap https://www.runoob.com/bootstrap/bootstrap-tutorial.html

使用python库依赖

名称 备注
Django web 模板引擎
markdown markdown2html

初始化

使用python 3.7.6

  1. 安装Django

pip install Django

  1. 创建初始化项目

django-admin startproject pythonweb

  1. 运行测试

python manage.py runserver 0.0.0.0:8000

  1. 新增模块

python manage.py startapp homeApp

  1. 配置新增模块

    INSTALLED_APPS = [
       'django.contrib.admin',
       'django.contrib.auth',
       'django.contrib.contenttypes',
       'django.contrib.sessions',
       'django.contrib.messages',
       'django.contrib.staticfiles',
       'homeApp',#主页
       'aboutApp',#学院简介
       'teamApp',#教师团队
       'scientificApp',#科研
       'partyApp',#党建
       'admissionsAndEmploymentApp',#招生和就业
    ]
    
  2. 创建依赖管理文件

pip freeze > requirements.txt

  1. 创建static静态资源目录和templates模板目录

编辑settings.py文件,配置静态资源加入django管理

``

配置模板的路径

   >TEMPLATES = [
   >    {
   >        ...,
   >        'DIRS': [BASE_DIR / 'templates'],
   >    },
   >]
   >```
   >
   >配置静态资源
   >
   >```python
   >STATICFILES_DIRS = (os.path.join(BASE_DIR, "static"),)
   >```
   >
   >


8. 路由配置

   - 正向路由配置,编辑urls.py文件

     ```python
     from django.contrib import admin
     from django.urls import path
     from homeApp.views import home
     urlpatterns = [
         path('admin/', admin.site.urls),
         path('',home,name='home'), #正向路由
     ]
     ```

     

   - 反向路由,编辑urls.py

     ```python
     from django.conf.urls import include
     urlpatterns = [
         ...,
         path('aboutApp/', include('aboutApp.urls')),
     ]
     ```

     > 在aboutApp中添加一个urls.py文件,并进行路由配置
     >
     > ```python
     > from django.urls import path
     > from . import views
     > 
     > app_name = 'aboutApp'
     > 
     > urlpatterns = [
     >     path('survey/', views.survey, name='survey'),  # 学院概况
     >     path('leader/', views.leader, name='leader'),     # 领导分工
     > ]
     > ```

     

   9. 数据模型配置

      - 创建一个common模块,在models.py中定义数据模型

      > 定义一个文章模型和轮播图模型

      

      ```python
      class Article(models.Model):
          CATEGORY_CHOICES = [
              ('professional', '专业介绍'),
              ('leader', '领导分工'),
              ('academic_leader', '学院学科建设带头人教师'),
              ('computer_science', '计算机系教师'),
              ('software_engineering', '软件工程系教师'),
              ('digital_media', '数字媒体技术系教师'),
              ('iot_networking', '物联网与网络工程系教师'),
              ('math_teaching', '数学教研室教师'),
              ('party_work', '党政学工队伍教师'),
              ('scientific', '教学科研'),
              ('party_dynamic', '党建动态'),
              ('youth_dynamic', '团学动态'),
              ('admissions', '招生'),
              ('employment', '就业'),
          ]
          title = models.CharField(max_length=200, verbose_name='标题')
          markdown_content = models.TextField(verbose_name='markdown内容')
        #blank=True配置字段非必填    
          html_content = models.TextField(verbose_name='html内容',blank=True)
          created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
          updated_at = models.DateTimeField(auto_now=True, verbose_name='更新时间')
          category = models.CharField(max_length=50, choices=CATEGORY_CHOICES, verbose_name='文章分类')
          cover = models.URLField(verbose_name='封面')
      
          class Meta:
              ordering = ['-created_at']
      
          def __str__(self):
              return self.title
      
      
      class Banner(models.Model):
          title = models.CharField(max_length=200, verbose_name='标题')
          url = models.URLField(verbose_name='链接')
          order = models.IntegerField(default=0, verbose_name='序号')
      
          class Meta:
              ordering = ['order']
      
          def __str__(self):
              return self.title
      ```

      - 在admin中注册定义的模型,编译admin.py文件

      ```python
      from django.contrib import admin
      
      from common.models import Article, Banner
      
      # Register your models here.
      admin.site.register(Article)
      admin.site.register(Banner)
      ```

      

      > 更新模型信息:`python manage.py makemigrations common`
      >
      > 同步模型与数据表`python manage.py migrate common`
      >
      > 创建超级管理员用于登陆django的后台:`python manage.py createsuperuser `

## 工作内容分工

- 图片链接收集
- 文章数据收集(html2markdown)
- 前端页面开发
- 管理后台开发
- 前后端对接
- 功能测试与接口测试
- 初始数据维护
- 打包部署上线

| 姓名   | 负责内容             | 备注 |
| ------ | -------------------- | ---- |
| 黄略   | 总体设计、前后端开发 |      |
| 杨昊廷 | 前后端开发           |      |
| 李锐   | 数据采集、数据清洗   |      |
| 朱启政 | 数据采集、数据清洗   |      |
| 毕熙   | 数据录入、数据维护   |      |

## 功能模块

> 参考网站:[计算机学院官网](https://www-new.gwng.edu.cn/xkxy/main.psp)

- 首页
- 学院信息
  - 学院概况
  - 领导分工
  - 机构设置
  - 专业介绍
- 教师队伍
  - 学院学科建设带头人
  - 计算机系
  - 软件工程系
  - 数字媒体技术系
  - 物联网与网络工程系
  - 数学教研室
  - 党政学工队伍
- 科研工作
- 党团工作
  - 党建工作
  - 团学工作
- 招生就业
  - 招生信息
  - 就业信息

## 数据库设计

#### 概要设计

- 文章(**ID**,标题,markdown内容,,html内容,时间,创建人,文章分类,封面)

> 文章分类:专业介绍,领导分工,学院学科建设带头人教师,计算机系教师,软件工程系教师,数字媒体技术系教师,物联网与网络工程系教师,数学教研室教师,党政学工队伍教师,教学科研,党建动态,团学动态,招生,就业

- 首页轮播图(标题,链接,序号)

#### 物理设计

项目设计了两个核心模型,均定义在 `common` 模块中:

**Article(文章模型):** 存储所有模块的文章内容,通过 `category` 字段区分所属模块。内容以 Markdown 格式存储,请求时渲染为 HTML。

| 字段             | 类型          | 说明                  |
| ---------------- | ------------- | --------------------- |
| title            | CharField     | 文章标题              |
| markdown_content | TextField     | Markdown 格式内容     |
| html_content     | TextField     | HTML 格式内容(预留) |
| category         | CharField     | 文章分类(14 种)     |
| cover            | URLField      | 封面图片链接          |
| created_at       | DateTimeField | 创建时间              |
| updated_at       | DateTimeField | 更新时间              |

**Banner(轮播图模型):** 存储首页轮播图数据。

| 字段  | 类型         | 说明     |
| ----- | ------------ | -------- |
| title | CharField    | 标题     |
| url   | URLField     | 图片链接 |
| order | IntegerField | 排序序号 |

**数据库ER图:**

mermaid erDiagram

Article {
    int id PK
    string title
    text markdown_content
    text html_content
    datetime created_at
    datetime updated_at
    string category
    string cover
}
Banner {
    int id PK
    string title
    string url
    int order
}

### 

## 构建部署

### 构建docker镜像及运行

- dockerfile文件

dockerfile

使用官方Python 3.9镜像作为基础

FROM python:3.9-slim

设置工作目录

WORKDIR /app

设置环境变量

ENV PYTHONDONTWRITEBYTECODE=1

PYTHONUNBUFFERED=1 \
DJANGO_SETTINGS_MODULE=pythonweb.settings

安装Python依赖

RUN pip install --no-cache-dir Django Markdown

复制项目文件

COPY ./pythonweb .

创建非root用户

RUN useradd -m -u 1000 django && chown -R django:django /app USER django

暴露端口

EXPOSE 8000

启动命令

CMD ["python", "/app/pythonweb/manage.py", "runserver", "8000"]


使用`docker build ./ -t gwng-pythonweb:v1.0`命令构建docker镜像

使用`docker run --name gwng -p 8000:8000 gwng-pythonweb:v1.0`命令运行

### 申请域名SSL证书

shell #安装certbot apt install cerbot #使用certbot向letsencrypt申请SSL证书 certbot certonly --webroot -w /home/nginx/www/ -d pythonweb.display.anyi.space




### 使用nginx反向代理

nginx upstream pythonwebServer{

    server 127.0.0.1:8000;
}

server{

listen       80;
listen  [::]:80;
server_name  pythonweb.display.anyi.space;
client_max_body_size 1024m;

#certbot自动续签使用的验证路径映射
location ^~ /.well-known/acme-challenge/ {
root /home/nginx/www/;
}

location / {
    proxy_pass http://pythonwebServer;
    proxy_set_header HOST $host;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

}

server{

listen 443 ssl;
server_name pythonweb.display.anyi.space;

ssl_certificate /etc/letsencrypt/live/pythonweb.display.anyi.space/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/pythonweb.display.anyi.space/privkey.pem;

ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;

ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;

ssl_prefer_server_ciphers on;

location / {
    proxy_pass http://pythonwebServer;
    proxy_set_header HOST $host;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

} ```