【问题标题】:Django: Add & delete extra input field using class view at a click of a buttonDjango:单击按钮使用类视图添加和删除额外的输入字段
【发布时间】:2016-11-05 00:44:33
【问题描述】:

我想要做的是:User 将有一个 production(也称为播客插曲)已经创建了必要的信息,直到这一点(production_id 将是 id 用于此询问)。这个想法是,当用户到达ChapterMark 模板时,他将能够create several timestamps 指出他/她在整个剧集中谈论的某些主题。 chaptermark_id 的创建是因为它将是 One-To-Many 并且有了这个 id 我可以在该剧集中添加任意数量的时间戳。考虑到这一点,对于这种情况,哪种方法是最好的方法,以及如何在我的表单、类视图和模板中实现它?

提前致谢

这是我的views.py

from django.http import HttpResponseRedirect, Http404, HttpResponseForbidden
from django.shortcuts import render, get_object_or_404
from django.views.generic import View, RedirectView, TemplateView
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin

from .forms.client_setup import ClientSetupForm
from .forms.podcast_setup import PodcastSetupForm
from .forms.episode_info import EpisodeInfoForm
from .forms.image_files import EpisodeImageFilesForm
from .forms.wordpress_info import EpisodeWordpressInfoForm
from .forms.chapter_marks import EpisodeChapterMarksForm
from .forms.show_links import ShowLinksForm
from .forms.tweetables import TweetablesForm
from .forms.clicktotweet import ClickToTweetForm
from .forms.schedule import ScheduleForm
from .forms.wordpress_account import WordpressAccountForm
from .forms.wordpress_account_setup import WordpressAccountSetupForm
from .forms.wordpress_account_sortable import WordpressAccountSortableForm
from .forms.soundcloud_account import SoundcloudAccountForm
from .forms.twitter_account import TwitterAccountForm
from producer.helpers import get_podfunnel_client_and_podcast_for_user
from producer.helpers.soundcloud_api import SoundcloudAPI
from producer.helpers.twitter import TwitterAPI

from django.conf import settings
from producer.models import Client, Production, ChapterMark, ProductionLink, ProductionTweet, Podcast, WordpressConfig, Credentials, WordPressSortableSection, \
    TwitterConfig, SoundcloudConfig

from django.core.urlresolvers import reverse
from producer.tasks.auphonic import update_or_create_preset_for_podcast

class EpisodeChapterMarksView(LoginRequiredMixin, View):
    form_class = EpisodeChapterMarksForm
    template_name = 'fc/forms_chapter_marks.html'

    def get(self, request, *args, **kwargs):
        initial_values = {}
        user = request.user

        # Lets get client and podcast for the user already. if not existent raise 404
        client, podcast = get_fc_client_and_podcast_for_user(user)
        if client is None or podcast is None:
            raise Http404

        # The production_id or the chaptermark_id must be passed on teh KWargs
        production_id = kwargs.get('production_id', None)
        chaptermark_id = kwargs.get('chaptermark_id', None)
        if chaptermark_id:
            chaptermark = get_object_or_404(ChapterMark, id=chaptermark_id)
            production = chaptermark.production
        elif production_id:
            production = get_object_or_404(Production, id=production_id)
            chaptermark = None

        initial_values['production_id'] = production.id

        if chaptermark is not None:
            initial_values['chaptermark_id'] = chaptermark_id
            initial_values['start_time'] = chaptermark.start_time
            initial_values['title'] = chaptermark.title

        form = self.form_class(initial=initial_values)
        return render(request, self.template_name, {'form': form})

    def post(self, request, *args, **kwargs):
        form = self.form_class(request.POST)

        if form.is_valid():
            # lets get the data
            production_id = form.cleaned_data.get('production_id')
            chaptermark_id = form.cleaned_data.get('chaptermark_id')
            start_time = form.cleaned_data.get('start_time')
            title = form.cleaned_data.get('title')

            # Get production
            production = get_object_or_404(Production, id=production_id)

            # if a chaptermark existed, we update, if not we create
            if chaptermark_id is not None:
                chaptermark = ChapterMark.objects.get(id=chaptermark_id)
            else:
                chaptermark = ChapterMark()

            chaptermark.start_time = start_time
            chaptermark.title = title
            chaptermark.production = production
            chaptermark.save()

            return HttpResponseRedirect(reverse('fc:episodeshowlinks'))

        return render(request, self.template_name, {'form': form})

chaptermark.py 表单:

from django import forms

class EpisodeChapterMarksForm(forms.Form):

    production_id = forms.IntegerField(widget=forms.Field.hidden_widget, required=False)
    chaptermark_id = forms.IntegerField(widget=forms.Field.hidden_widget, required=False)
    start_time = forms.TimeField(required=False)
    title = forms.CharField(max_length=200)

chaptermark模板:

{% extends "fc/base.html" %}
{% load crispy_forms_tags %}


{% block content %}

<div class="progress">
  <div class="progress-bar progress-bar-striped progress-bar-success active" role="progressbar" aria-valuenow="50" aria-valuemin="0" aria-valuemax="100" style="width: 50%">
    <span class="sr-only">50% Complete</span>
  </div>
</div>

<div class="panel panel-default box-shadow--16dp col-sm-6 col-sm-offset-3">
<div class="panel-body">

<div class='row'>
<div class='col-sm-12'>

{% if title %}
<h1 class='{% if title_align_center %}text-align-center{% endif %}'>{{ title }}<!-- : {{ get.clientsetup.company_name }} --></h1>
{% endif %}
{% if subtitle %}
<h3 class='{% if subtitle_align_center %}text-align-center{% endif %}'>{{ subtitle }}</h4>
{% endif %}

<h5>Chapter Marks</h5>

<form method='POST' action=''>{% csrf_token %}
{{ form|crispy }}

<hr/>

<button type="submit" class="btn btn-primary box-shadow--6dp"><i class="fa fa-chevron-right pull-right"></i> Continue
</button>

</form>
</div>
</div>

</div>
</div>

{% endblock %}

----------更新---------- ----

views.py:

@login_required
def episodechaptermarks(request):
    title = 'Podcast'
    title_align_center = True
    subtitle = 'Setup | Add Episode'
    subtitle_align_center = True
    form = ChapterMarksForm(request.POST or None)
    context = {
        "title": title,
        "subtitle": subtitle,
        "form": form
    }

    if form.is_valid():

        instance = form.save(commit=False)

        start_time = form.cleaned_data.get("start_time")
        title = form.cleaned_data.get("title")

        instance.start_time = start_time
        instance.title = title

        instance.user = request.user

        instance.save()

        return render(request, "pod_funnel/forms_chapter_marks.html", context)

    else:

        return render(request, "pod_funnel/forms_chapter_marks.html", context)

ModelForm:

from django import forms

from producer.models import ChapterMark

class ChapterMarksForm(forms.ModelForm):

    class Meta:

        model = ChapterMark
        fields = ['start_time', 'title']

    def clean_start_time(self):
        start_time = self.cleaned_data.get('start_time')

        return start_time

    def clean_title(self):
        title = self.cleaned_data.get('title')

        return title

【问题讨论】:

    标签: django django-models django-forms django-templates django-views


    【解决方案1】:

    本质上,您的production 对象有一系列timestamps,它们通过FK 关联回来。您需要一组production 级别的 CRUD 视图。假设您的模型已经创建。根据我的经验,我想指出一些事情,我认为这些事情会为您指明正确的方向。

    1. 除非绝对必要,否则在创建镜像模型的表单对象时不要使用Form 类;您正在引入不必要的复杂性并为错误打开了大门。使用ModelForm,它可以直接从视图将对象保存到数据库,并帮助您管理清理、验证等。此外,这些可以很容易地与各种通用视图相结合。

    2. 对于这种关系(一个模型对象与给定类型的不同数量的模型对象相关联),Django 提供了强大但困难的inlineformset_factory。这会根据需要为此类关系创建一系列内联表单。

    3. 所以你有一个模型 (production) 和另一个与之相关的模型 (timestamp)。您需要同时保存这些,可能执行清理或验证,并真正为整个关系提供 CRUD 功能。为此,您可以从头开始创建一个复杂的视图您可以使用 django-extra-views 及其通用 CBV 用于具有内联的模型。你可以继承CreateWithInlinesViewUpdateWithInlinesView。为什么?大多数 Django 开发人员都同意表单集难以实现。

    所以,给你一个简化的版本,你可以如何做到这一点

    from extra_views.advanced import CreateWithInlinesView, InlineFormSet, UpdateWithInlinesView
    
    
    class TimeStampsInline(InlineFormSet):
        model = models.TimeStamp
        form = TimeStampForm # If you haven't created a custom ModelForm, can also specify "fields= ['field_1','field_2',...] and the CBV will create a ModelForm
        extra = 0
    
    
    class ProductionCreate(CreateWithInlinesView):
        model=models.Production
        inlines = [TimeStampsInline]
        success_url = reverse('production-list') # the url to return to on successful create
        exclude = ['created_by'] # render all fields except this in form
        template_name = 'myapp/update.html'
    
    class ProductionUpdate(UpdateWithInlinesView):
        model=models.Production
        inlines = [TimeStampsInline]
        success_url = reverse('production-list')
        exclude = ['created_by']
        template_name = 'myapp/update.html'
    

    您的模板必须在规范中使用表单集构建;到处都有文档和教程。

    这已经有很多要消化的内容了,但是您可能已经大致了解了。不要从头开始造马;)

    【讨论】:

    • 感谢详细的回复!在设置我的ChapterMarkView 课程之前,我将其作为ModelForm(检查更新)视图,但并没有深入了解它。您是否建议返回ModelForm 并用您提供的模板替换我的模板并从那里开始?我对 django 很陌生...你能指导我完成它吗?会很感激的。
    • 使用这些通用视图,您可以不指定form,而是指定fieldsexclude(要排除的字段列表),视图将自行创建ModelForm。如果您使用标准表单来表示模型对象,您将失去所有内置的清理和验证。这意味着如果不满足所有数据库约束,您可能会尝试保存通过失败的表单提交的数据。它不必要地为一些大问题打开了大门。 ModelForm 是 Django 的重要组成部分,值得深入了解 :)
    • 好的,试一试。你介意我在整个过程中回来问任何问题吗?另外,关于id,我是否还必须为ModelForm 中的每个创建一个?例如,如果您在我的Forms 中看到我有production_id = forms.IntegerField(widget=forms.Field.hidden_widget, required=False)chaptermark_id = forms.IntegerField(widget=forms.Field.hidden_widget, required=False)
    • 我建议按照教程创建 ModelForm,这远远超出了我们在 SO 答案中所能涵盖的范围。但很乐意回答具体问题,如果您遇到困难,请务必作为新问题提出具体问题
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多