我已经在许多web应用程序中看到了这种方法(例如,当你购买保险时),但我找不到在django中实现它的好方法。我的模型中有几个继承自基类的类,因此它们有几个共同的字段。在create-view中,我希望使用该继承,因此首先请求公共字段,然后根据用户的选择请求特定字段。
举个简单的例子,假设我想填充一个地点数据库
class Place(Model):
name = models.CharField(max_length=40)
address = models.CharField(max_length=100)
class Restaurant(Place):
cuisine = models.CharField(max_length=40)
website = models.CharField(max_length=40)
class SportField(Place):
sport = models.CharField(max_length=40)现在,我希望在有公共字段(name和address)时创建一个视图,然后可以选择地点类型(餐厅/ SportField)。一旦选择了位置类型(或者用户按下"Continue“按钮),新的字段就会出现(我猜为了简单起见,页面需要重新加载),旧的字段仍然可见,已经填充。
我已经见过这种方法很多次了,所以我很惊讶没有标准的方法,或者已经有一些扩展在这方面有帮助(我看过django-formtools中的Form Wizard,但没有真正链接到继承),也做更复杂的事情,因为继承更深入。
发布于 2021-06-18 09:26:33
models.py
class Place(models.Model):
name = models.CharField(max_length=40)
address = models.CharField(max_length=100)
class Restaurant(Place):
cuisine = models.CharField(max_length=40)
website = models.CharField(max_length=40)
class SportField(Place):
sport = models.CharField(max_length=40)forms.py
from django.db import models
from django import forms
class CustomForm(forms.Form):
CHOICES = (('restaurant', 'Restaurant'), ('sport', 'Sport'),)
name = forms.CharField(widget=forms.TextInput(attrs={'placeholder': 'Name'}))
address = forms.CharField(widget=forms.TextInput(attrs={'placeholder': 'Address'}))
type = forms.ChoiceField(
choices=CHOICES,
widget=forms.Select(attrs={'onChange':'renderForm();'}))
cuisine = forms.CharField(required=False, widget=forms.TextInput(attrs={'placeholder': 'Cuisine'}))
website = forms.CharField(required=False, widget=forms.TextInput(attrs={'placeholder': 'Website'}))
sport = forms.CharField(required=False, widget=forms.TextInput(attrs={'placeholder': 'Sport'}))views.py
from django.http.response import HttpResponse
from .models import Restaurant, SportField
from .forms import CustomForm
from django.shortcuts import render
from django.views import View
class CustomView(View):
def get(self, request,):
form = CustomForm()
return render(request, 'home.html', {'form':form})
def post(self, request,):
data = request.POST
name = data['name']
address = data['address']
type = data['type']
if(type == 'restaurant'):
website = data['website']
cuisine = data['cuisine']
Restaurant.objects.create(
name=name, address=address, website=website, cuisine=cuisine
)
else:
sport = data['sport']
SportField.objects.create(name=name, address=address, sport=sport)
return HttpResponse("Success")templates/home.html
<html>
<head>
<script type="text/javascript">
function renderForm() {
var type =
document.getElementById("{{form.type.auto_id}}").value;
if (type == 'restaurant') {
document.getElementById("{{form.website.auto_id}}").style.display = 'block';
document.getElementById("{{form.cuisine.auto_id}}").style.display = 'block';
document.getElementById("{{form.sport.auto_id}}").style.display = 'none';
} else {
document.getElementById("{{form.website.auto_id}}").style.display = 'none';
document.getElementById("{{form.cuisine.auto_id}}").style.display = 'none';
document.getElementById("{{form.sport.auto_id}}").style.display = 'block';
}
}
</script>
</head>
<body onload="renderForm()">
<form method="post" action="/">
{% csrf_token %}
{{form.name}}<br>
{{form.address}}<br>
{{form.type}}<br>
{{form.website}}
{{form.cuisine}}
{{form.sport}}
<input type="submit">
</form>
</body>
</html>在settings.py中添加模板文件夹
TEMPLATES = [
{
...
'DIRS': [os.path.join(BASE_DIR, 'templates')],
...
]发布于 2021-06-19 21:27:11
我已经使用修改后的Class Based Views创建了一个2页的工作示例。
在第一页提交表单时,将创建一个place_type对象。然后,用户被重定向到第二个页面,在那里他们可以更新现有的详细信息并添加其他信息。
不需要单独的模型,因为CreateView和UpdateView会自动从相关对象的ModelForm类生成表单。
需要一个名为place_form.html的模板。它应该呈现{{ form }}标记。
# models.py
from django.db import models
from django.urls import reverse
class Place(models.Model):
"""
Each tuple in TYPE_CHOICES contains a child class name
as the first element.
"""
TYPE_CHOICES = (
('Restaurant', 'Restaurant'),
('SportField', 'Sport Field'),
)
name = models.CharField(max_length=40)
address = models.CharField(max_length=100)
place_type = models.CharField(max_length=40, blank=True, choices=TYPE_CHOICES)
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('place_update', args=[self.pk])
# Child models go here...# urls.py
from django.urls import path
from . import views
urlpatterns = [
path('create/', views.PlaceCreateView.as_view(), name='place_create'),
path('<pk>/', views.PlaceUpdateView.as_view(), name='place_update'),
]# views.py
from django.http import HttpResponseRedirect
from django.forms.models import construct_instance, modelform_factory
from django.views.generic.edit import CreateView, UpdateView
from django.urls import reverse_lazy
from . import models
class PlaceCreateView(CreateView):
model = models.Place
fields = '__all__'
def form_valid(self, form):
"""
If a `place_type` is selected, it is used to create an
instance of that Model and return the url.
"""
place_type = form.cleaned_data['place_type']
if place_type:
klass = getattr(models, place_type)
instance = klass()
obj = construct_instance(form, instance)
obj.save()
return HttpResponseRedirect(obj.get_absolute_url())
return super().form_valid(form)
class PlaceUpdateView(UpdateView):
fields = '__all__'
success_url = reverse_lazy('place_create')
template_name = 'place_form.html'
def get_object(self, queryset=None):
"""
If the place has a `place_type`, get that object instead.
"""
pk = self.kwargs.get(self.pk_url_kwarg)
if pk is not None:
obj = models.Place.objects.get(pk=pk)
if obj.place_type:
klass = getattr(models, obj.place_type)
obj = klass.objects.get(pk=pk)
else:
raise AttributeError(
"PlaceUpdateView must be called with an object pk in the URLconf."
)
return obj
def get_form_class(self):
"""
Remove the `place_type` field.
"""
model = self.object.__class__
return modelform_factory(model, exclude=['place_type',])发布于 2021-06-18 01:41:31
我们手动做了类似的事情,我们基于设计创建了视图和表单,并基于if条件进行了链接。
https://stackoverflow.com/questions/67967805
复制相似问题