Добавление поля для нескольких файлов в Django ModelForm
Я хочу создать форму, которая позволяет загружать несколько изображений. У меня есть модель Listing
, которая выглядит следующим образом:
class Listing(models.Model):
location = models.CharField("Address/Neighborhood", max_length=250)
class ListingImage(models.Model):
listing = models.ForeignKey(
Listing,
related_name="images",
on_delete=models.SET_NULL,
null=True,
)
image = models.ImageField()
Я использую django-crispy-forms для создания формы на странице, но не могу понять, как вывести поле listing
на страницу.
class ListingModelForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.layout = Layout(
Fieldset(
"Location",
Div("location", css_class="col-md-12 col-lg-6")
)
)
class Meta:
model = Listing
fields = "__all__"
А вот мое мнение:
class ListingCreateView(LoginRequiredMixin, CreateView):
model = Listing
form_class = ListingModelForm
def form_valid(self, form):
form.instance.user = self.request.user
return super().form_valid(form)
Если я правильно понимаю, вы хотите иметь поле, в которое можно добавить несколько изображений, а затем сохранить их все. Если я прав, то вот подход, который вы можете использовать.
Добавьте в форму дополнительное поле, которое вы установите для приема нескольких изображений... например:
class ListingModelForm(forms.ModelForm):
# Extra field to collect multiple images
listing_images = forms.ImageField(
required=False,
widget=forms.ClearableFileInput(attrs={'name': 'listing_images', 'id': 'listing_images', 'multiple': True})
)
# other portion of your form below...
Теперь вы можете получить доступ к полю в форме: {{ form.listing_images }}
, добавление нескольких изображений...
Теперь внутри функции post request
у вас есть обработка этой формы... Вы можете сделать:
if request.method == 'POST':
form = ListingModelForm(data=request.POST, files=request.FILES)
if form.is_valid():
# listing = form.save(commit=False)
# listing.location = 'blah blah'
# listing.save()
# or just use
listing = form.save()
# Looping over the list of images and create for each iteration
for file in request.FILES.getlist('listing_images'):
ListingImage.objects.create(listing=listing, image=file)
# Also note that you could override the save method on the form to include the above forloop
# if you don't want it out here...
Предполагая, что на image field
на ListingImage
указан путь для загрузки изображений и настроены параметры MEDIA_URL
и MEDIA_ROOT
...
UPDATES
Опубликовал ответ, не зная, что вы используете class-based view
.
class ListingCreateView(LoginRequiredMixin, CreateView):
model = Listing
form_class = ListingModelForm
def form_valid(self, form):
# form.instance.user = self.request.user
listing = form.save() # Listing must be created first to use as the image reference
for file in self.request.FILES.getlist('listing_images'):
ListingImage.objects.create(listing=listing, image=file)
return super(ListingCreateView, self).form_valid(form)
# or using the post method
def post(self, *args, *kwargs):
form = ListingModelForm(data=request.POST, files=request.FILES)
if form.is_valid():
for file in self.request.FILES.getlist('listing_images'):
ListingImage.objects.create(listing=listing, image=file)
return redirect('to a path...')
Так что вы можете просто использовать один из методов, выделенных выше на class-based view
.