如何在 Django 中将多张图片上传到博客 post
how to upload multiple images to a blog post in django
我正在尝试允许每个用户将多张图片上传到一个博客 post。几天来,我一直在努力找出最好的方法来做到这一点。执行此操作的最佳做法是什么?
根据我的阅读,我应该从博客 post 模型中制作一个单独的图像模型并使用外键。那正确吗?
然后就是如何让他们同时上传多张图片的问题。我假设我应该使用像 drop zone 这样的东西是对的吗?
也欢迎就存储照片的最佳做法提出任何建议。我看过 Amazon s3 和 cloudinary。我想创建一些可扩展的东西。
如有任何帮助,我们将不胜感激!
您只需要两个模型。一个用于 Post,另一个用于图像。您的图像模型将具有 Post 模型的外键:
from django.db import models
from django.contrib.auth.models import User
from django.template.defaultfilters import slugify
class Post(models.Model):
user = models.ForeignKey(User)
title = models.CharField(max_length=128)
body = models.CharField(max_length=400)
def get_image_filename(instance, filename):
title = instance.post.title
slug = slugify(title)
return "post_images/%s-%s" % (slug, filename)
class Images(models.Model):
post = models.ForeignKey(Post, default=None)
image = models.ImageField(upload_to=get_image_filename,
verbose_name='Image')
您需要为每个模型创建一个表单,但它们将相互关联,因为当用户填写表单时 post 他还必须为 post 才能成功 posted,我们将在视图中执行此操作,但现在您的表单看起来像这样
from django import forms
from .models import Post, Images
class PostForm(forms.ModelForm):
title = forms.CharField(max_length=128)
body = forms.CharField(max_length=245, label="Item Description.")
class Meta:
model = Post
fields = ('title', 'body', )
class ImageForm(forms.ModelForm):
image = forms.ImageField(label='Image')
class Meta:
model = Images
fields = ('image', )
现在这是最重要的部分,即视图,因为这是将多张图片上传到单个魔术的地方。为了能够一次上传多张图片,我们需要多个图片字段,对吧?这就是您爱上 Django formsets 的地方。我们将需要 django 表单集来实现这一点,您可以在我已链接的 Django 文档中阅读有关表单集的信息 :) 但是您的视图应该如下所示:
*进口非常重要
from django.shortcuts import render
from django.forms import modelformset_factory
from django.contrib.auth.decorators import login_required
from django.contrib import messages
from django.http import HttpResponseRedirect
from .forms import ImageForm, PostForm
from .models import Images
@login_required
def post(request):
ImageFormSet = modelformset_factory(Images,
form=ImageForm, extra=3)
#'extra' means the number of photos that you can upload ^
if request.method == 'POST':
postForm = PostForm(request.POST)
formset = ImageFormSet(request.POST, request.FILES,
queryset=Images.objects.none())
if postForm.is_valid() and formset.is_valid():
post_form = postForm.save(commit=False)
post_form.user = request.user
post_form.save()
for form in formset.cleaned_data:
#this helps to not crash if the user
#do not upload all the photos
if form:
image = form['image']
photo = Images(post=post_form, image=image)
photo.save()
# use django messages framework
messages.success(request,
"Yeeew, check it out on the home page!")
return HttpResponseRedirect("/")
else:
print(postForm.errors, formset.errors)
else:
postForm = PostForm()
formset = ImageFormSet(queryset=Images.objects.none())
return render(request, 'index.html',
{'postForm': postForm, 'formset': formset})
在视图中,我们得到了两个表单,它会检查两个表单是否有效。这样,用户必须填写表格并上传所有图像,在本例中为 3 extra=3
。只有这样 post 才能成功创建。
您的模板应该如下所示:
<form id="post_form" method="post" action="" enctype="multipart/form-data">
{% csrf_token %}
{% for hidden in postForm.hidden_fields %}
{{ hidden }}
{% endfor %}
{% for field in postForm %}
{{ field }} <br />
{% endfor %}
{{ formset.management_form }}
{% for form in formset %}
{{ form }}
{% endfor %}
<input type="submit" name="submit" value="Submit" />
</form>
我遇到了类似的问题。在我的模型中,一篇文章必须有一个缩略图(图像),然后我为可选图像设置了五个字段。问题出现在应用安全过滤器后,图像源不会呈现,因为它不再是 HTML,
<img src="{{article.image1.url}}" class="some class">
不行。我使用的一个临时解决方案是根据文章标题命名图像。如果我在 "django filters" 上写作,我会将我的其他图像命名为 djangofiltersimage1.png 或 djangofiltersimage2.png,这很有帮助,因为在我的模型中,每篇文章都有一个唯一的标题。然后我将图像源更改为:
<img src="/media/djangofiltersimage1.png" class="some class">
唯一的问题是图像的严格命名。您可以通过为博客图像创建模型来上传更多图像。与此同时,我仍在寻找另一种解决方案。
你可以看看我的博客here
一步步解决 => 偶,我也被卡住了。这就是我成功的做法。
Finally
,实现下面的代码,我实现了这个
- 1 有很多图片的笔记模型
- 多个上传(在同时,相同的选择文件按钮,&全部保存在一起,就像 Gmail 文件上传)
这是我的笔记和图片模型-(或see full code)
class Note(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE)
title = models.CharField(max_length=30)
text = models.TextField(null=True,blank=True)
created_date = models.DateTimeField(auto_now_add=True)
last_modified = models.DateTimeField(auto_now=True)
class Images(models.Model):
note = models.ForeignKey(Note,on_delete=models.CASCADE)
image = models.ImageField(upload_to=user_directory_path,null=True,blank=True)
这是我的表格 (Link of doc. on multiple upload)- (or see full code)
class NoteForm(forms.ModelForm):
class Meta:
model = Note
fields = ['title','text'] #make sure to mention field here, if nothing is mentioned then all will be required.
class NoteFullForm(NoteForm): #extending form
images = forms.FileField(widget=forms.ClearableFileInput(attrs={'multiple': True}))
class Meta(NoteForm.Meta):
fields = NoteForm.Meta.fields + ['images',]
这是我的视图文件-(或see full code)
def addNoteView(request):
if request.method == "POST":
#images will be in request.FILES
form = NoteFullForm(request.POST or None, request.FILES or None)
files = request.FILES.getlist('images')
if form.is_valid():
user = request.user
title = form.cleaned_data['title']
text = form.cleaned_data['text']
note_obj = Note.objects.create(user=user,title=title,text=text) #create will create as well as save too in db.
for f in files:
Images.objects.create(note=note_obj,image=f)
else:
print("Form invalid")
然后,终于 我的 Html 文件 (be sure to bind files as said in docs)- (or see full code)
<form action="{% url 'note:add_note' %}" method="post" class="note-form" enctype="multipart/form-data">{% csrf_token %}
<div class="form-group">
<label for="note-title">Title</label>
<input type="text" name="title" class="form-control" id="note-title" placeholder="Enter Title" required>
</div>
<div class="form-group">
<label for="note-description">Description</label>
<textarea type="text" name="text" class="form-control" id="note-description" placeholder="Description here"></textarea>
</div>
<div class="form-group">
<label for="note-image">Images</label>
<input type="file" name="images" class="form-control-file" id="note-image" multiple>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
答案很简单。不需要那么多代码。
HTML 文件
<input type="file" name = "files" multiple />
VIEWS.PY
files = request.FILES.getlist('files')
for f in files:
a = Image(image=f)
a.save()
获取列表名称和html输入名称字段应该相同
为 models.py
class studentImage(models.Model):
image = models.ImageField(upload_to='media/')
def __str__(self):
return self.image
为 views.py
def studentImageView(request):
if request.method == "POST":
images = request.FILES.getlist('images')
for image in images:
photo = studentImage.objects.create(image=image,)
photo.save()
return render(request, 'image.html')
模板
<form method="post" enctype="multipart/form-data" >
{% csrf_token %}
<input required name="images" type="file" multiple >
<button class="btn btn-primary" type="submit">Upload</button>
</form>
我正在尝试允许每个用户将多张图片上传到一个博客 post。几天来,我一直在努力找出最好的方法来做到这一点。执行此操作的最佳做法是什么?
根据我的阅读,我应该从博客 post 模型中制作一个单独的图像模型并使用外键。那正确吗? 然后就是如何让他们同时上传多张图片的问题。我假设我应该使用像 drop zone 这样的东西是对的吗?
也欢迎就存储照片的最佳做法提出任何建议。我看过 Amazon s3 和 cloudinary。我想创建一些可扩展的东西。
如有任何帮助,我们将不胜感激!
您只需要两个模型。一个用于 Post,另一个用于图像。您的图像模型将具有 Post 模型的外键:
from django.db import models
from django.contrib.auth.models import User
from django.template.defaultfilters import slugify
class Post(models.Model):
user = models.ForeignKey(User)
title = models.CharField(max_length=128)
body = models.CharField(max_length=400)
def get_image_filename(instance, filename):
title = instance.post.title
slug = slugify(title)
return "post_images/%s-%s" % (slug, filename)
class Images(models.Model):
post = models.ForeignKey(Post, default=None)
image = models.ImageField(upload_to=get_image_filename,
verbose_name='Image')
您需要为每个模型创建一个表单,但它们将相互关联,因为当用户填写表单时 post 他还必须为 post 才能成功 posted,我们将在视图中执行此操作,但现在您的表单看起来像这样
from django import forms
from .models import Post, Images
class PostForm(forms.ModelForm):
title = forms.CharField(max_length=128)
body = forms.CharField(max_length=245, label="Item Description.")
class Meta:
model = Post
fields = ('title', 'body', )
class ImageForm(forms.ModelForm):
image = forms.ImageField(label='Image')
class Meta:
model = Images
fields = ('image', )
现在这是最重要的部分,即视图,因为这是将多张图片上传到单个魔术的地方。为了能够一次上传多张图片,我们需要多个图片字段,对吧?这就是您爱上 Django formsets 的地方。我们将需要 django 表单集来实现这一点,您可以在我已链接的 Django 文档中阅读有关表单集的信息 :) 但是您的视图应该如下所示:
*进口非常重要
from django.shortcuts import render
from django.forms import modelformset_factory
from django.contrib.auth.decorators import login_required
from django.contrib import messages
from django.http import HttpResponseRedirect
from .forms import ImageForm, PostForm
from .models import Images
@login_required
def post(request):
ImageFormSet = modelformset_factory(Images,
form=ImageForm, extra=3)
#'extra' means the number of photos that you can upload ^
if request.method == 'POST':
postForm = PostForm(request.POST)
formset = ImageFormSet(request.POST, request.FILES,
queryset=Images.objects.none())
if postForm.is_valid() and formset.is_valid():
post_form = postForm.save(commit=False)
post_form.user = request.user
post_form.save()
for form in formset.cleaned_data:
#this helps to not crash if the user
#do not upload all the photos
if form:
image = form['image']
photo = Images(post=post_form, image=image)
photo.save()
# use django messages framework
messages.success(request,
"Yeeew, check it out on the home page!")
return HttpResponseRedirect("/")
else:
print(postForm.errors, formset.errors)
else:
postForm = PostForm()
formset = ImageFormSet(queryset=Images.objects.none())
return render(request, 'index.html',
{'postForm': postForm, 'formset': formset})
在视图中,我们得到了两个表单,它会检查两个表单是否有效。这样,用户必须填写表格并上传所有图像,在本例中为 3 extra=3
。只有这样 post 才能成功创建。
您的模板应该如下所示:
<form id="post_form" method="post" action="" enctype="multipart/form-data">
{% csrf_token %}
{% for hidden in postForm.hidden_fields %}
{{ hidden }}
{% endfor %}
{% for field in postForm %}
{{ field }} <br />
{% endfor %}
{{ formset.management_form }}
{% for form in formset %}
{{ form }}
{% endfor %}
<input type="submit" name="submit" value="Submit" />
</form>
我遇到了类似的问题。在我的模型中,一篇文章必须有一个缩略图(图像),然后我为可选图像设置了五个字段。问题出现在应用安全过滤器后,图像源不会呈现,因为它不再是 HTML,
<img src="{{article.image1.url}}" class="some class">
不行。我使用的一个临时解决方案是根据文章标题命名图像。如果我在 "django filters" 上写作,我会将我的其他图像命名为 djangofiltersimage1.png 或 djangofiltersimage2.png,这很有帮助,因为在我的模型中,每篇文章都有一个唯一的标题。然后我将图像源更改为:
<img src="/media/djangofiltersimage1.png" class="some class">
唯一的问题是图像的严格命名。您可以通过为博客图像创建模型来上传更多图像。与此同时,我仍在寻找另一种解决方案。 你可以看看我的博客here
一步步解决 => 偶,我也被卡住了。这就是我成功的做法。
Finally
,实现下面的代码,我实现了这个
- 1 有很多图片的笔记模型
- 多个上传(在同时,相同的选择文件按钮,&全部保存在一起,就像 Gmail 文件上传)
这是我的笔记和图片模型-(或see full code)
class Note(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE)
title = models.CharField(max_length=30)
text = models.TextField(null=True,blank=True)
created_date = models.DateTimeField(auto_now_add=True)
last_modified = models.DateTimeField(auto_now=True)
class Images(models.Model):
note = models.ForeignKey(Note,on_delete=models.CASCADE)
image = models.ImageField(upload_to=user_directory_path,null=True,blank=True)
这是我的表格 (Link of doc. on multiple upload)- (or see full code)
class NoteForm(forms.ModelForm):
class Meta:
model = Note
fields = ['title','text'] #make sure to mention field here, if nothing is mentioned then all will be required.
class NoteFullForm(NoteForm): #extending form
images = forms.FileField(widget=forms.ClearableFileInput(attrs={'multiple': True}))
class Meta(NoteForm.Meta):
fields = NoteForm.Meta.fields + ['images',]
这是我的视图文件-(或see full code)
def addNoteView(request):
if request.method == "POST":
#images will be in request.FILES
form = NoteFullForm(request.POST or None, request.FILES or None)
files = request.FILES.getlist('images')
if form.is_valid():
user = request.user
title = form.cleaned_data['title']
text = form.cleaned_data['text']
note_obj = Note.objects.create(user=user,title=title,text=text) #create will create as well as save too in db.
for f in files:
Images.objects.create(note=note_obj,image=f)
else:
print("Form invalid")
然后,终于 我的 Html 文件 (be sure to bind files as said in docs)- (or see full code)
<form action="{% url 'note:add_note' %}" method="post" class="note-form" enctype="multipart/form-data">{% csrf_token %}
<div class="form-group">
<label for="note-title">Title</label>
<input type="text" name="title" class="form-control" id="note-title" placeholder="Enter Title" required>
</div>
<div class="form-group">
<label for="note-description">Description</label>
<textarea type="text" name="text" class="form-control" id="note-description" placeholder="Description here"></textarea>
</div>
<div class="form-group">
<label for="note-image">Images</label>
<input type="file" name="images" class="form-control-file" id="note-image" multiple>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
答案很简单。不需要那么多代码。
HTML 文件
<input type="file" name = "files" multiple />
VIEWS.PY
files = request.FILES.getlist('files')
for f in files:
a = Image(image=f)
a.save()
获取列表名称和html输入名称字段应该相同
为 models.py
class studentImage(models.Model):
image = models.ImageField(upload_to='media/')
def __str__(self):
return self.image
为 views.py
def studentImageView(request):
if request.method == "POST":
images = request.FILES.getlist('images')
for image in images:
photo = studentImage.objects.create(image=image,)
photo.save()
return render(request, 'image.html')
模板
<form method="post" enctype="multipart/form-data" >
{% csrf_token %}
<input required name="images" type="file" multiple >
<button class="btn btn-primary" type="submit">Upload</button>
</form>