Сохранение данных мастера форм Django в трех моделях со связанными полями - PullRequest
1 голос
/ 26 июня 2019

Я работаю над проектом, который требует использования мастера форм для заполнения трех связанных моделей.Первая модель - Listing - имеет общие данные, которые имеют отношение OneToOneField ко второй модели (Property).Модель Listing также имеет много-много связей с третьей моделью (ListingImages).В общем, я использую 4 формы в мастере.Вот это определение модели models.py

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 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)

Вот это forms.py

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

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):
    image_url = forms.ImageField(label='Listing Image',
        widget=forms.ClearableFileInput(attrs={'multiple': True}),
        required=False
    )
    class Meta:
        model = ListingImages
        fields = ['image_url']

ImageFormSet = modelformset_factory(ListingImages, form=ListingImagesForm, extra=3)

views.py

    from django.shortcuts import render, redirect
import os
from .forms import ListingDetails, PropertyDetails1, PropertyDetails2, ListingImagesForm
from .models import ListingImages, Listing, Property
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, HttpResponse
from django.forms.models import construct_instance

class PropertyView(SessionWizardView):
    # formset = ImageFormSet(queryset=Images.objects.none())
    template_name = "listings/create_property.html"
    form_list = [ListingDetails, PropertyDetails1, PropertyDetails2, ListingImagesForm]
    file_storage = FileSystemStorage(location=os.path.join(settings.MEDIA_ROOT, 'media'))
    def done(self, form_list, **kwargs):
        listing_instance = Listing()
        property_instance = Property()
        listing_instance.created_by = self.request.user
        listing_instance.listing_owner = self.request.user
        listing_instance.listing_type = 'P'
        for form in form_list:
            listing_instance = construct_instance(form, listing_instance, form._meta.fields, form._meta.exclude)
            property_instance = construct_instance(form, property_instance, form._meta.fields, form._meta.exclude)
        listing = listing_instance.save()
        property_instance.listing = listing
        property_instance.save()
        return HttpResponse('data saved successfully')

Проблема, с которой я сталкиваюсьЯ могу сохранить модель Listing, но проблема заключается в получении ее основного идентификатора и использовании ее для сохранения модели Property.Опять же, модель ListingImages хранит изображения, связанные с моделью Listing.Как сохранить эти модели в базе данных, учитывая, что их несколько?

1 Ответ

1 голос
/ 26 июня 2019

Что не так в том, что, как описано здесь , model.save () не возвращает сохраненный объект, но None.

Так что последние несколько строк приведенного выше кода должныбыть

    listing_instance.save()
    property_instance.listing = listing_instance
    property_instance.save()
    return HttpResponse('data saved successfully')

То же самое, если сохранить список list_images, будет что-то вроде

    for li_obj in listing_image_instances:
         li_obj.listing = listing_instance # saved above
         li_obj.save()
...