首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >django中的多步形式和模型继承

django中的多步形式和模型继承
EN

Stack Overflow用户
提问于 2021-06-14 17:27:44
回答 6查看 242关注 0票数 4

我已经在许多web应用程序中看到了这种方法(例如,当你购买保险时),但我找不到在django中实现它的好方法。我的模型中有几个继承自基类的类,因此它们有几个共同的字段。在create-view中,我希望使用该继承,因此首先请求公共字段,然后根据用户的选择请求特定字段。

举个简单的例子,假设我想填充一个地点数据库

代码语言:javascript
复制
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,但没有真正链接到继承),也做更复杂的事情,因为继承更深入。

EN

回答 6

Stack Overflow用户

发布于 2021-06-18 09:26:33

models.py

代码语言:javascript
复制
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

代码语言:javascript
复制
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

代码语言:javascript
复制
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

代码语言:javascript
复制
<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中添加模板文件夹

代码语言:javascript
复制
TEMPLATES = [
    {
        ...
        'DIRS': [os.path.join(BASE_DIR, 'templates')],
        ...
]
票数 4
EN

Stack Overflow用户

发布于 2021-06-19 21:27:11

我已经使用修改后的Class Based Views创建了一个2页的工作示例。

在第一页提交表单时,将创建一个place_type对象。然后,用户被重定向到第二个页面,在那里他们可以更新现有的详细信息并添加其他信息。

不需要单独的模型,因为CreateViewUpdateView会自动从相关对象的ModelForm类生成表单。

需要一个名为place_form.html的模板。它应该呈现{{ form }}标记。

代码语言:javascript
复制
# 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...
代码语言:javascript
复制
# 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'),
]
代码语言:javascript
复制
# 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',])
票数 2
EN

Stack Overflow用户

发布于 2021-06-18 01:41:31

我们手动做了类似的事情,我们基于设计创建了视图和表单,并基于if条件进行了链接。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67967805

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档