Несколько загрузок файлов не работают в мастере форм Django - PullRequest
0 голосов
/ 24 июня 2019

Я работаю над проектом, который требует загрузки нескольких изображений за один из шагов мастера формы. В мастере форм также есть несколько моделей, используемых для мастера, которые, как мне кажется, усложняют весь процесс. Вот соответствующий код:

models.py

from django.db import models
from django.contrib.auth.models import User
from location_field.models.plain import PlainLocationField
from PIL import Image
from django.core.validators import MaxValueValidator, MinValueValidator
from listing_admin_data.models import (Service, SubscriptionType, PropertySubCategory,
        PropertyFeatures, VehicleModel, VehicleBodyType, VehicleFuelType,
        VehicleColour, VehicleFeatures, BusinessAmenities, Currency
    )

class Listing(models.Model):
    listing_type_choices = [('P', 'Property'), ('V', 'Vehicle'), ('B', 'Business/Service'), ('E', 'Events')]

    listing_title = models.CharField(max_length=255)
    listing_type = models.CharField(choices=listing_type_choices, max_length=1, default='P')
    status = models.BooleanField(default=False)
    featured = models.BooleanField(default=False)
    city = models.CharField(max_length=255, blank=True)
    location = PlainLocationField(based_fields=['city'], zoom=7, blank=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    expires_on = models.DateTimeField(auto_now=True)
    created_by = models.ForeignKey(User,
        on_delete=models.CASCADE, editable=False, null=True, blank=True
    )
    listing_owner = models.ForeignKey(User,
        on_delete=models.CASCADE, related_name='list_owner'
    )

    def __str__(self):
        return self.listing_title


def get_image_filename(instance, filename):
    title = instance.listing.listing_title
    slug = slugify(title)
    return "listings_pics/%s-%s" % (slug, filename)


class ListingImages(models.Model):
    listing = models.ForeignKey(Listing, on_delete=models.CASCADE)
    image_url = models.ImageField(upload_to=get_image_filename,
                              verbose_name='Listing Images')
    main_image = models.BooleanField(default=False)

    class Meta:
        verbose_name_plural = "Listing Images"

    def __str__(self):
        return f'{self.listing.listing_title} Image'


class Subscriptions(models.Model):
    subscription_type = models.ForeignKey(SubscriptionType, on_delete=models.CASCADE)
    subscription_date = models.DateTimeField(auto_now_add=True)
    subscription_amount = models.DecimalField(max_digits=6, decimal_places=2)
    subscribed_by = models.ForeignKey(User, on_delete=models.CASCADE)
    duration = models.PositiveIntegerField(default=0)
    listing_subscription = models.ManyToManyField(Listing)
    updated_at = models.DateTimeField(auto_now=True)
    status = models.BooleanField(default=False)

    class Meta:
        verbose_name_plural = "Subscriptions"

    def __str__(self):
        return f'{self.listing.listing_title} Subscription'


class Property(models.Model):
    sale_hire_choices = [('S', 'Sale'), ('R', 'Rent')]
    fully_furnished_choices = [('Y', 'Yes'), ('N', 'No')]

    listing = models.OneToOneField(Listing, on_delete=models.CASCADE)
    sub_category = models.ForeignKey(PropertySubCategory, on_delete=models.CASCADE)
    for_sale_rent = models.CharField(choices=sale_hire_choices, max_length=1, default=None)
    bedrooms = models.PositiveIntegerField(default=0)
    bathrooms = models.PositiveIntegerField(default=0)
    rooms = models.PositiveIntegerField(default=0)
    land_size = models.DecimalField(max_digits=10, decimal_places=2)
    available_from = models.DateField()
    car_spaces = models.PositiveIntegerField(default=0)
    fully_furnished = models.CharField(choices=fully_furnished_choices, max_length=1, default=None)
    desc = models.TextField()
    property_features = models.ManyToManyField(PropertyFeatures)
    price = models.DecimalField(max_digits=15, decimal_places=2)
    currency = models.ForeignKey(Currency, on_delete=models.CASCADE)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    created_by = models.ForeignKey(User, on_delete=models.CASCADE)

    class Meta:
        verbose_name_plural = "Properties"

    def __str__(self):
        return f'{self.listing.listing_title}'

Форма для этого приложения выглядит следующим образом: forms.py

    from django import forms
from .models import Listing, Property, Vehicle, Business, ListingImages

class ListingDetails(forms.ModelForm):
    class Meta:
        model = Listing
        fields = ['listing_title', 'city', 'location']

class PropertyDetails1(forms.ModelForm):
    class Meta:
        model = Property
        fields = ['sub_category', 'for_sale_rent', 'bedrooms', 'bathrooms',
            'rooms', 'land_size', 'available_from', 'car_spaces', 'fully_furnished',
            'desc', 'currency', 'price'
        ]

class PropertyDetails2(forms.ModelForm):
    class Meta:
        model = Property
        fields = ['property_features']

class ListingImagesForm(forms.ModelForm):
    class Meta:
        model = ListingImages
        fields = ['image_url']

Представление, которое обрабатывает все это, хотя еще не завершено, так как я все еще исследую лучший способ сохранить данные в базе данных, показано ниже: views.py

    from django.shortcuts import render
import os
from .forms import ListingDetails, PropertyDetails1, PropertyDetails2, ListingImagesForm
from .models import ListingImages
from formtools.wizard.views import SessionWizardView
from django.conf import settings
from django.core.files.storage import FileSystemStorage
from django.forms import modelformset_factory
from django.contrib import messages
from django.http import HttpResponseRedirect

class PropertyView(SessionWizardView):
    ImageFormSet = modelformset_factory(ListingImages, form=ListingImagesForm, extra=3)
    template_name = "listings/create_property.html"
    formset = ImageFormSet(queryset=Images.objects.none())
    form_list = [ListingDetails, PropertyDetails1, PropertyDetails2, ListingImagesForm]
    file_storage = FileSystemStorage(location=os.path.join(settings.MEDIA_ROOT, 'media'))
    def done(self, form_list, **kwargs):
        return render(self.request, 'done.html', {
            'form_data': [form.cleaned_data for form in form_list],
        })

Шаблон, который используется для обработки полей формы, выглядит следующим образом: create_property.py

    <p>Step {{ wizard.steps.step1 }} of {{ wizard.steps.count }}</p>
<form action="" method="post">
    {% csrf_token %}
    <table>
    {{ wizard.management_form }}
    {% if wizard.form.forms %}
        {{ wizard.form.management_form }}
        {% for form in wizard.form.forms %}
            {{ form }}
        {% endfor %}
        {% else %}
            {% for field in wizard.form %}
                <div class="form-group">
                    <label for="{{ field.id_for_label }}">{{ field.label }}</label>
                    {{ field }}
                    <span class="message">{{ field.errors }}</span>
                </div>
            {% endfor %}
    {% endif %}
    </table>
    {% if wizard.steps.prev %}
    <div class="d-flex justify-content-around">
        <button name="wizard_goto_step" type="submit" class="btn btn-primary" value="{{ wizard.steps.first }}">First Step</button>
        <button name="wizard_goto_step" type="submit" class="btn btn-primary" value="{{ wizard.steps.prev }}">Previous Step</button>
    </div>
    {% endif %}

    <div class="d-flex justify-content-end col-12 mb-30 pl-15 pr-15">
        <input type="submit" value="{% trans "submit" %}"/>
    </div>
</form>

Я попытался приложить всю необходимую информацию, чтобы это работало.

Основная проблема, с которой я сталкиваюсь, заключается в том, что шаблон не дает места для нескольких загрузок, и снова, после того, как я прикрепляю один предоставленный файл и пытаюсь отправить, я получаю сообщение об ошибке field cannot be empty.

Я все еще новичок в Django и пытаюсь учиться, когда пишу код, но пока что не так много задокументировано о мастере форм и проблемах с множественной загрузкой изображений. Большинство доступных сообщений выглядят некачественными и использует только контактную форму, которая не хранит никаких данных в базе данных.

...