【发布时间】:2019-11-08 11:07:12
【问题描述】:
我正在处理一个需要使用表单向导来填充三个相关模型的项目。第一个模型 - Listing - 具有与第二个模型 (Property) 具有 OneToOneField 关系的一般数据。 Listing 模型还与第三个模型(ListingImages) 具有多对多关系。一般来说,我在向导中使用了 4 个表单。这是模型定义
模型.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 模型,但是获取它的主 ID 并使用它来保存 Property 模型是问题所在。同样,ListingImages 模型存储与Listing 模型相关的图像。考虑到它们是多个模型,如何将这些模型保存到数据库中?
【问题讨论】:
-
缩进错误?在
PropertyView中return之前的最后三行看起来好像它们应该是form_list循环的一部分。除此之外,您需要澄清“第一个模型”“第三个模型”等的含义。 -
缩进是可以的,因为它们不属于 for 循环。让我尽快澄清模型命名。
-
为了澄清三行运行良好,
listing = listing_instance.save()正在按预期将数据保存到数据库中。由于主键没有按照应有的方式分配为外键,因此后面的行出现了问题。
标签: django django-views django-formwizard django-file-upload