我正在一个需要使用表单向导来填充三个相关模型的项目中。第一个模型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)
这是表格。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
模型,但要获取其主要ID并使用它来保存Property
模型是问题。同样,ListingImages
模型存储与Listing
模型相关的图像。考虑到这些模型是多个模型,如何将它们保存到数据库中?
答案 0 :(得分:1)
出问题的是,如here所述,model.save()不会返回保存的对象,而是返回None
。
因此上述代码的最后几行应该是
listing_instance.save()
property_instance.listing = listing_instance
property_instance.save()
return HttpResponse('data saved successfully')
同上保存一组listing_images就像
for li_obj in listing_image_instances:
li_obj.listing = listing_instance # saved above
li_obj.save()