# Django 课后练习题  

## 1. Python 虚拟环境创建

请根据下列方法选择一种创建 Python 虚拟环境，并按要求安装课程所需包。

在 Python 中，虚拟环境是一种隔离的工作环境，可以防止不同项目的依赖项之间相互干扰。有多种方法可以创建 Python 虚拟环境，以下是其中几种常见的方法：

- **使用 venv 模块创建虚拟环境**  ***——推荐使用***

  ```bash
  python -m venv myenv      # 创建虚拟环境
  source myenv/bin/activate  # 激活虚拟环境
  ```
  
- **使用 virtualenv 创建虚拟环境**
  

    ```bash
    virtualenv myenv        # 创建虚拟环境
    source myenv/bin/activate  # 激活虚拟环境
    ```

- **使用 conda 创建虚拟环境**

    ```bash
    conda create --name myenv  # 创建虚拟环境
    conda activate myenv        # 激活虚拟环境
    ```

​

以上是三种常见的 Python 虚拟环境创建方法，其中 venv 和 virtualenv 是在命令行中使用的，而 conda 是 Python 第三方库，需要先安装。另外，在 Windows 系统中，需要使用 Scripts 目录下的 activate.bat 文件来激活虚拟环境。

## 2. pip 源设置

请根据需求设置 pip 源

pip 源设置的方法有修改 pip 配置文件和使用代理两种方法。

- 修改 pip 配置文件：在 pip 配置文件中添加相应的源。  


- 使用代理：在命令行中使用代理命令进行设置。

临时使用：在 pip install 命令后面加上 -i 参数，指定 pip 源。例如：

```bash
pip install jieba -i https://pypi.tuna.tsinghua.edu.cn/simple
```

永久修改：在 Linux 系统中，修改 ~/.pip/pip.conf 文件（没有就创建一个），指定 pip 源。例如：清华大学源。

请切换 pip 源为国内源，可多次尝试。

国内 pip 源有：

- 清华大学：https://pypi.tuna.tsinghua.edu.cn/simple；
- 阿里云：https://mirrors.aliyun.com/pypi/simple；
- 中国科学技术大学：https://pypi.mirrors.ustc.edu.cn/simple；
- 华中科技大学：http://pypi.hustunique.com/；
- 豆瓣源：http://pypi.douban.com/simple；
- 腾讯源：http://mirrors.cloud.tencent.com/pypi/simple；
- 华为镜像源：https://repo.huaweicloud.com/repository/pypi/simple。



## 4. Django 项目搭建

根据下列流程搭建一个学生管理系统。

创建 Django 项目的步骤如下：  

1. 安装 Django：首先，确保你的系统上已经安装了Python。然后，通过以下命令安装 Django：  

    ```
    pip install django
    ```

2. 创建 Django 项目：使用以下命令创建一个新的 Django 项目：

    ```
    django-admin startproject project_name
    ```  

    其中，`project_name` 是你的项目名称。这将在当前目录下创建一个名为 `project_name` 的文件夹，其中包含了一个基本的 Django 项目结构。

3. 配置项目：进入项目文件夹：  

    ```bash
    cd project_name
    ```  

    然后，编辑`settings.py` 文件，根据你的需求配置项目设置，例如数据库设置、静态文件路径等。  

4. 创建应用：使用以下命令创建一个新的 Django 应用：

    ```bash
    # 二者皆可
    python manage.py startapp app_name  

    django-admin startapp app_name
    ```  

    其中，`app_name` 是你的应用名称。这将在 `project_name` 文件夹下的 `app` 文件夹中创建一个新的应用。  

5. 定义模型：在应用中定义数据库模型。打开`app/models.py`文件，并定义你的模型类。这些模型类将映射到数据库中的表。  

6. 创建数据库表：运行以下命令来创建数据库表：

    ```bash
    python manage.py makemigrations app_name
    python manage.py migrate app_name
    ```

    这将根据你在`models.py`文件中定义的模型创建数据库表。  

7. 编写视图和模板：在应用中编写视图和模板文件，以实现具体的业务逻辑和页面呈现。

8. 运行项目。运行开发服务器。在终端中输入以下命令来启动开发服务器：

    ```bash
    python manage.py runserver
    ```

## 5. 创建班级和学生表

请按下列方法创建班级、学生表

在Django中创建班级和学生表，需要执行以下步骤：

1. 创建Django应用

    如果还没有创建Django应用，请执行以下命令创建一个新的Django应用：

    ```bash
    python manage.py startapp myapp
    ```  

    其中`myapp`是你想要创建的应用名称。

2. 定义班级和学生模型

    在`myapp/models.py`文件中定义班级和学生模型。例如：

    ```python
    from django.db import models

    class Classroom(models.Model):
        name = models.CharField(max_length=100)
        grade = models.IntegerField()

        def __str__(self):
            return self.name

    class Student(models.Model):
        name = models.CharField(max_length=100)
        age = models.IntegerField()
        classroom = models.ForeignKey(Classroom, on_delete=models.CASCADE)

        def __str__(self):
            return self.name
    ```  

    这里我们定义了两个模型，`Classroom`和`Student`，并在`Student`模型中通过`ForeignKey`字段关联了`Classroom`模型。

3. 生成迁移脚本

    执行以下命令生成迁移脚本：

    ```bash
    python manage.py makemigrations
    ```  

    其中`myapp`是刚刚创建的应用名称。这个命令会在`myapp/migrations/`目录下生成一个迁移脚本文件。

4. 执行迁移命令

    执行以下命令将模型应用到数据库中：

    ```bash
    python manage.py migrate
    ```  

    这个命令会将迁移脚本应用到数据库中，创建相应的班级和学生表。如果迁移成功，就可以在Django的admin后台管理页面中看到这两个表，并进行增删改查等操作。

## 6. QuerySet 和 Instance增删改查

请使用QuerySet 和 Instance在班级、学生表上进行增删改查。

在Django中，我们可以使用QuerySet和实例对班级和学生表进行增删改查操作。以下是一些例子：

- **增加（Create）**

创建新的班级和学生实例：

```python
from myapp.models import Classroom, Student

# 创建一个新的班级
new_classroom = Classroom(name='一班', grade=1)
new_classroom.save()

# 创建一个新的学生，并关联到刚刚创建的班级
new_student = Student(name='小明', age=10, classroom=new_classroom)
new_student.save()
```  

- **查询（Retrieve）**

使用QuerySet查询班级和学生：

```python
# 获取所有班级
all_classrooms = Classroom.objects.all()

# 获取名称为'一班'的班级
classroom = Classroom.objects.get(name='一班')

# 获取班级为'一班'的所有学生
students = Student.objects.filter(classroom__name='一班')
```  

- **更新（Update）**

更新班级或学生的属性：

```python
# 获取名称为'一班'的班级
classroom = Classroom.objects.get(name='一班')

# 更新班级的名称
classroom.name = '二班'
classroom.save()
```  

- **删除（Delete）**

删除班级或学生：

```python
# 获取名称为'二班'的班级
classroom = Classroom.objects.get(name='二班')

# 删除该班级
classroom.delete()
```  

注意，删除一个班级将会同时删除与之关联的所有学生，因为我们在学生模型中设置了`on_delete=models.CASCADE`。这意味着当一个班级被删除时，与之关联的学生也会被删除。如果你不希望这样，你可以考虑更改`on_delete`参数的设置。例如，设置为`models.SET_NULL`将会在删除班级时将学生的班级设置为NULL。不过，这样你需要确保学生的班级字段允许为NULL。

## 7. 使用serializers 序列化、APIView 创建班级和学生查询

请对创建的班级、学生表进行序列化。

要使用APIView创建班级和学生的查询视图，你需要执行以下步骤：

首先，确保你已经安装了Django REST framework。如果没有安装，可以使用以下命令进行安装：
  
```python
pip install djangorestframework
```  

然后，你可以使用以下代码在Django中创建班级和学生的查询视图：

1. 在`myapp`应用中创建一个名为`views.py`的文件（如果尚未创建）。  

2. 在`myapp/models.py`文件中定义班级和学生模型。可参考task5
3. 在`views.py`文件中，导入所需的模块并创建查询视图。例如：

    ```python
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from .models import Classroom, Student

    class ClassroomListView(APIView):
        def get(self, request):
            classrooms = Classroom.objects.all()
            serializer = ClassroomSerializer(classrooms, many=True)
            return Response(serializer.data)

    class StudentListView(APIView):
        def get(self, request):
            students = Student.objects.all()
            serializer = StudentSerializer(students, many=True)
            return Response(serializer.data)
    ```  

4. 在上述代码中，我们创建了两个视图，一个用于查询所有班级，另一个用于查询所有学生。这些视图继承了 `APIView`，并使用了Django REST framework 的 `Response` 和序列化器来处理数据。
5. 你还需要创建序列化器，以便将班级和学生实例转换为 JSON 格式。在 `myapp` 应用中创建一个名为 `serializers.py` 的文件，并在其中定义序列化器。例如：

    ```python
    from rest_framework import serializers
    from .models import Classroom, Student

    class ClassroomSerializer(serializers.ModelSerializer):
        class Meta:
            model = Classroom
            fields = ['id', 'name', 'grade']

    class StudentSerializer(serializers.ModelSerializer):
        class Meta:
            model = Student
            fields = ['id', 'name', 'age', 'classroom']
    ```  

6. 最后，在你的应用的`urls.py`文件中添加URL配置，以便将视图与URL进行关联。例如：

    ```python
    from django.urls import path
    from .views import ClassroomListView, StudentListView

    urlpatterns = [
        path('classrooms/', ClassroomListView.as_view(), name='classroom-list'),
        path('students/', StudentListView.as_view(), name='student-list'),
    ]
    ```  

现在，当你访问`/classrooms/`路径时，你将获得所有班级的列表，当你访问`/students/`路径时，你将获得所有学生的列表。这些视图会以JSON格式返回数据。

## 8. 使用 ModelViewSet 创建班级、学生查询 view

请使用 ModelViewSet 创建班级、学生查询 view。

使用 `ModelViewSet` 可以更方便地创建班级和学生的查询视图。`ModelViewSet` 是 Django REST framework 提供的一个视图集，它提供了默认的 `list()` 和 `retrieve()` 方法，适用于查询操作。

下面是使用 `ModelViewSet` 创建班级和学生查询视图的步骤：

1. 在 `myapp` 应用的 `views.py` 文件中，导入所需的模块并创建 `ModelViewSet` 子类。例如：

    ```python
    from rest_framework.viewsets import ModelViewSet
    from .models import Classroom, Student
    from .serializers import ClassroomSerializer, StudentSerializer

    class ClassroomViewSet(ModelViewSet):
        queryset = Classroom.objects.all()
        serializer_class = ClassroomSerializer

    class StudentViewSet(ModelViewSet):
        queryset = Student.objects.all()
        serializer_class = StudentSerializer
    ```  

2. 在上述代码中，我们创建了两个视图集，`ClassroomViewSet` 用于处理班级的查询操作， `StudentViewSet` 用于处理学生的查询操作。我们指定了 `queryset` 属性来定义视图中使用的查询集，以及`serializer_class`属性来定义用于序列化和反序列化数据的序列化器。
3. 在应用的 `urls.py` 文件中，使用路由器（Router）自动生成 URL 配置。这样可以简化 URL 的定义。首先，导入路由器类，然后在 `urls.py` 文件的底部添加以下代码：

    ```python
    from rest_framework.routers import DefaultRouter

    router = DefaultRouter()
    router.register(r'classrooms', ClassroomViewSet)
    router.register(r'students', StudentViewSet)


    urlpatterns += router.urls 
    ```  

上述代码使用路由器注册了班级和学生视图集，并将生成的URL模式添加到 `urlpatterns` 列表中。

现在，当你访问 `/classrooms/` 路径时，你会获得所有班级的列表，并且可以通过 `/classrooms/<id>/` 路径访问特定班级的详细信息。类似地，通过访问 `/students/` 路径，你可以获得所有学生的列表，并通过 `/students/<id>/` 路径访问特定学生的详细信息。

