python - 如何使用 CreateView 在 Django 中上传多个文件?
问题描述
请帮我。我是 Django 新手,无法理解以下内容 - 我有 CreateView 的子类来创建评论。我想创建一个项目,人们可以在其中留下评论并将文件(图像)附加到此评论。一个人应该可以将任意数量的图像附加到一个带有文本注释的表单中。我在 Internet 上发现我需要使用 2 个模型 - 1 个用于文本评论的模型 + 1 个用于图像的单独模型。是这样吗?
评论(文本)表单是由 CreateView 的子类在我的 views.py 中创建和处理的。如何将新的独立图像模型与我的 CreateView 连接起来?
models.py
class Descriptions(models.Model):
…
city = models.ForeignKey(Cities, on_delete=models.CASCADE)
description = models.TextField()
date_added = models.DateTimeField(auto_now_add=True)
owner = models.ForeignKey(User, on_delete=models.DO_NOTHING)
…
class Description_Photos(models.Model):
image = models.ImageField(upload_to='images/', blank=True)
description = models.ForeignKey(Descriptions, on_delete=models.CASCADE, related_name='photos')
forms.py
class DescriptionsForm(forms.ModelForm):
class Meta:
model = Descriptions
exclude = []
widgets = {'description': forms.Textarea(attrs={'cols':90})}
class Photos_form(forms.Form):
photos = forms.FileField(widget=forms.FileInput(attrs={'multiple': True}))
views.py
class DescriptionCreate(CreateView):
model = Descriptions
form_class = DescriptionsForm
template_name = 'countries/new_description.html'
def get_success_url(self):
return reverse('countries:descr', args=[self.kwargs['country_id'], self.kwargs['city_id']])
def get_context_data(self, **kwargs):
self.city = get_object_or_404(Cities, id=self.kwargs['city_id'])
kwargs['city'] = self.city
return super().get_context_data(**kwargs)
def form_valid(self, form):
form.instance.city = get_object_or_404(Cities, id=self.kwargs['city_id'])
form.instance.owner = self.request.user
messages.success(self.request, 'Your post has been added, thank you')
return super().form_valid(form)
所以我的问题是我应该在 views.py 中写什么class Photos_form(forms.Form):
?如何连接这个类和我的class DescriptionCreate(CreateView)
?
解决方案
我在相同的情况下使用 FormSets https://docs.djangoproject.com/en/2.0/topics/forms/formsets/
为图像模型声明 FormSet
…
# forms.py
class DescriptionsForm(forms.ModelForm):
class Meta:
model = Descriptions
exclude = []
widgets = {'description': forms.Textarea(attrs={'cols':90})}
class Photos_form(forms.Form):
photos = forms.FileField(widget=forms.FileInput(attrs={'multiple': True}))
##### Declare FORMSET !!! ###
class BasePhotosFormSet(BaseModelFormSet):
"""By default, when you create a formset from a model, the formset
will use a queryset that includes all objects in the model"""
def __init__(self, *args, **kwargs):
if 'city' in kwargs.keys():
city = kwargs.pop('city')
else:
city = None
super().__init__(*args, **kwargs)
if city and isinstance(instance, Cities):
self.queryset = Description_Photos.objects.filter(city=city)
else:
self.queryset = Description_Photos.objects.none()
# I usually declare formset for create operations and formset for update operations separately
PhotosCreateFormSet = forms.modelformset_factory(Description_Photos, Photos_form,
fields=Photos_form.Meta.fields, extra=0,
formset=BasePhotosFormSet)
PhotosUpdateFormSet = forms.modelformset_factory(Description_Photos, Photos_form, can_delete=True,
fields=PropertyImageForm.Meta.fields, extra=0,
formset=BasePhotosFormSet)
#############
# views.py
class DescriptionCreate(CreateView):
def __init__(self, **kwargs):
self.object = None
super().__init__(**kwargs)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
if self.request.POST:
images_formset = PhotosCreateFormSet(self.request.POST, self.request.FILES, city=self.object)
else:
images_formset = PhotosCreateFormSet(instance=self.object)
context['formset'] = images_formset
context['city'] = self.object
return context
模板
<div id="img-form-template" style="display: none">
<!- Declare EMPTY FORM for dynamically rebuild user interface by jQuery, for example->
{{ formset.empty_form }}
</div>
...
<div id="my-images">
...
{{ formset.management_form }}
{% for image_form in formset %}
{{ image_form }}
{% endfor %}
</div>
...
<script>
...
<!- Any javascript code to dynamically create empty form based on template "#img-form-template" ->
...
</script>
我试图将我的自定义代码重写为您的变体。我想self.city
在您的示例中声明为创建模型实例是一个坏主意:Django 自动创建self.object
推荐阅读
- html - 我想单击 VBA 中的按钮
- asp.net-core -
- css - 在函数末尾重新加载 css
- unity3d - 是否可以统一定义 3d 模型/预制件尺寸?
- google-cloud-dataflow - 为什么我的 PAssert 与我的 PCollection 中的项目不匹配?
- subprocess - 交互式运行斯坦福解析器(使用标准输入和标准输出)或将其作为服务器运行
- javascript - 创建基于显示图像的多个选择列表,基于您选择的内容
- c# - 当尝试更新 CreatorUserId 更改 NULL
- python - 使用 Python Selenium 从日历中选择日期
- node.js - 如何将 CMS 添加到 React 和 Node 网站?