### 数据模型设计
为了实现房间、冰箱、盒子和样本之间的多层次关系,可以定义如下 Django 或 Flask-SQLAlchemy 的数据模型:
#### 房间 (Room)
表示存储空间的一个物理区域。
```python
from django.db import models
class Room(models.Model):
name = models.CharField(max_length=100, unique=True) # 房间的唯一名称
description = models.TextField(blank=True, null=True)
def __str__(self):
return self.name
```
#### 冰箱 (Fridge)
属于某个房间的设备。
```python
class Fridge(models.Model):
room = models.ForeignKey(Room, on_delete=models.CASCADE, related_name='fridges') # 外键关联到房间
serial_number = models.CharField(max_length=50, unique=True) # 冰箱序列号
capacity = models.PositiveIntegerField() # 容量(单位自定)
def __str__(self):
return f"Fridge {self.serial_number} in {self.room}"
```
#### 盒子 (Box)
存放在某台冰箱内的容器。
```python
class Box(models.Model):
fridge = models.ForeignKey(Fridge, on_delete=models.CASCADE, related_name='boxes') # 外键关联到冰箱
box_id = models.CharField(max_length=50, unique=True) # 盒子ID
size = models.PositiveSmallIntegerField() # 尺寸或容量
def __str__(self):
return f"Box {self.box_id} in {self.fridge}"
```
#### 样本 (Sample)
保存在某个盒子中的具体物品。
```python
class Sample(models.Model):
box = models.ForeignKey(Box, on_delete=models.CASCADE, related_name='samples') # 外键关联到盒子
sample_id = models.CharField(max_length=50, unique=True) # 样本ID
type = models.CharField(max_length=50) # 类型
created_at = models.DateTimeField(auto_now_add=True) # 创建时间
def __str__(self):
return f"Sample {self.sample_id} in {self.box}"
```
---
### CRUD API 接口生成
可以通过 Django REST Framework (DRF) 自动生成上述模型的增删改查 (CRUD) API 接口。
#### 配置 DRF Serializer 和 ViewSet
```python
from rest_framework import serializers, viewsets
# Serializers define the API representation.
class RoomSerializer(serializers.ModelSerializer):
class Meta:
model = Room
fields = '__all__'
class FridgeSerializer(serializers.ModelSerializer):
class Meta:
model = Fridge
fields = '__all__'
class BoxSerializer(serializers.ModelSerializer):
class Meta:
model = Box
fields = '__all__'
class SampleSerializer(serializers.ModelSerializer):
class Meta:
model = Sample
fields = '__all__'
# ViewSets define the view behavior.
class RoomViewSet(viewsets.ModelViewSet):
queryset = Room.objects.all()
serializer_class = RoomSerializer
class FridgeViewSet(viewsets.ModelViewSet):
queryset = Fridge.objects.all()
serializer_class = FridgeSerializer
class BoxViewSet(viewsets.ModelViewSet):
queryset = Box.objects.all()
serializer_class = BoxSerializer
class SampleViewSet(viewsets.ModelViewSet):
queryset = Sample.objects.all()
serializer_class = SampleSerializer
```
#### 注册路由
```python
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register(r'rooms', RoomViewSet)
router.register(r'fridges', FridgeViewSet)
router.register(r'boxes', BoxViewSet)
router.register(r'samples', SampleViewSet)
urlpatterns = [
path('api/', include(router.urls)),
]
```
这将自动为 `Room`, `Fridge`, `Box` 和 `Sample` 提供完整的 CRUD 功能[^1]。
---
### 批量上传功能
对于批量上传文件并解析其中的内容以更新数据库,可以使用以下流程:
#### HTML 表单
允许用户上传 CSV 文件。
```html
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
<input type="file" name="csv_file">
<button type="submit">Upload</button>
</form>
```
#### 后端逻辑
假设 CSV 文件包含字段:room_name, fridge_serial, box_id, sample_id, sample_type。
```python
import csv
from django.http import HttpResponse
def upload_csv(request):
if request.method == 'POST':
csv_file = request.FILES['csv_file']
if not csv_file.name.endswith('.csv'):
return HttpResponse("File is not a valid CSV", status=400)
decoded_file = csv_file.read().decode('utf-8').splitlines()
reader = csv.DictReader(decoded_file)
for row in reader:
room, _ = Room.objects.get_or_create(name=row['room_name'])
fridge, _ = Fridge.objects.get_or_create(room=room, serial_number=row['fridge_serial'])
box, _ = Box.objects.get_or_create(fridge=fridge, box_id=row['box_id'])
Sample.objects.update_or_create(
box=box,
sample_id=row['sample_id'],
defaults={'type': row['sample_type']}
)
return HttpResponse("CSV uploaded successfully!")
```
此函数读取 CSV 文件并将每条记录映射到相应的模型实例中[^3]。
---