如何通过文件链接而非本地文件将书籍上传至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
相关产品推荐
相关产品推荐

