You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过文件链接而非本地文件将书籍上传至Django数据库?

实现通过文件链接上传书籍的Django方案

以下是针对需求的具体修改步骤,基于现有代码调整以支持通过文件URL上传书籍:

1. 更新表单定义(forms.py)

添加URL输入字段,支持本地文件和URL两种上传方式(若仅需URL上传,可删除原book字段):

class BookInfo(forms.ModelForm):
    class Meta:
        model = Genre
        fields = ["genres"]
        widgets = {"genres": forms.TextInput(attrs={"list": "genres"})}


class BookFile(BookInfo):
    # 保留本地文件上传(可选,不需要则删除)
    book = forms.FileField(widget=forms.ClearableFileInput(attrs={"multiple": True}), required=False)
    # 添加书籍URL输入字段
    book_url = forms.URLField(label="书籍文件链接", required=False)

    class Meta(BookInfo.Meta):
        fields = BookInfo.Meta.fields + ["book", "book_url"]

2. 修改视图逻辑(views.py)

添加URL文件下载与保存的处理逻辑,需先安装requests库:pip install requests

首先导入依赖:

import requests
from django.core.files.base import ContentFile
from django.core.exceptions import ValidationError

然后修改books视图函数:

def books(request):
    genres_names = Genre.objects.all()
    if request.method == "POST":
        form = BookFile(request.POST, request.FILES)
        genres_name = request.POST.get("genres")
        try:
            if form.is_valid():
                new_old_genre, created = Genre.objects.get_or_create(
                    genres=genres_name.lower()
                )
                # 处理本地文件上传(保留原逻辑)
                files = request.FILES.getlist("book")
                if files:
                    for f in files:
                        title = str(f).strip(".pdf")
                        Books.objects.create(
                            genre=new_old_genre,
                            title=title,
                            book=f,
                            is_available=True,
                            edition=0  # 补充必填字段默认值
                        )
                # 处理URL上传逻辑
                book_url = request.POST.get("book_url")
                if book_url:
                    try:
                        # 流式下载远程文件
                        response = requests.get(book_url, stream=True)
                        response.raise_for_status()  # 捕获HTTP请求错误
                        # 从URL提取文件名
                        filename = book_url.split("/")[-1]
                        # 复用文件扩展名验证器
                        validate_book_extension(filename)
                        # 将文件内容转为Django可处理的ContentFile
                        file_content = ContentFile(response.content, name=filename)
                        # 创建书籍记录
                        title = filename.strip(".pdf")
                        Books.objects.create(
                            genre=new_old_genre,
                            title=title,
                            book=file_content,
                            is_available=True,
                            edition=0
                        )
                    except requests.exceptions.RequestException as e:
                        messages.error(request, f"URL文件下载失败: {str(e)}")
                    except ValidationError as e:
                        messages.error(request, f"文件格式无效: {str(e)}")
                return redirect(index)
        except IntegrityError:
            messages.error(request, "该书籍已存在于数据库中")
            return redirect(books)
    else:
        form = BookFile()
    return render(request, "books.html", {"form": form, "genres_names": genres_names})

3. 更新HTML模板

添加URL输入框,并修正datalist的错误嵌套:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Upload Books</title>
</head>
<body>
    <form action="/books/" method="POST" enctype='multipart/form-data'>
        {% csrf_token %}
        {% if request.user.is_authenticated %}
            
            <p>
                <label>本地文件上传:</label><br>
                {{form.book}}
            </p>

            <p>
                <label>书籍文件链接:</label><br>
                {{form.book_url}}
                <small>请输入公开可访问的PDF文件链接</small>
            </p>

            <p>
                {{form.genres}}
                <datalist id="genres">
                    {% for name in genres_names %}
                    <option value="{{name.genres}}">{{name.genres}}</option>
                    {% endfor %}
                </datalist>
            </p>

            <p>
                <input type="submit" value="Create">
            </p>

            <div>
                <a href="/signout/"><input type="button" value="SignOut"></a>
            </div>
            
            <p>
                {{form.errors}}
            </p>

            {% for message in messages %}
                <p>{{ message }}</p>
            {% endfor %}
        {% endif %}
    </form>
</body>
</html>

4. 模型字段修正(可选但必要)

你的Books模型存在两个潜在问题,建议修正:

class Books(models.Model):
    title = models.CharField(max_length=500, default="")
    author = models.CharField(max_length=500, default="")
    publication = models.CharField(max_length=500, default="")
    # IntegerField不能用字符串默认值,改为数字或允许为空
    edition = models.IntegerField(default=0, blank=True, null=True)
    # 添加默认值,否则创建时会报错
    is_available = models.BooleanField(default=True)
    book = models.FileField(
        default="",
        upload_to="books",
        validators=[validate_book_extension],
        verbose_name="books",
    )
    genre = models.ForeignKey(Genre, on_delete=models.CASCADE, default="")

    class Meta:
        verbose_name_plural = "Books"

    def __str__(self):
        return self.title

额外注意事项

  • 确保服务器有足够的磁盘空间存储下载的文件
  • 对于大文件,可优化下载逻辑,增加文件大小限制
  • 可添加URL域名白名单,限制仅从可信源下载文件

内容的提问来源于stack exchange,提问作者Olasubomi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 19:20:36