Django 如何在一个页面中管理多个modelformset_工厂?

Django 如何在一个页面中管理多个modelformset_工厂?,django,django-views,django-forms,Django,Django Views,Django Forms,我正在做一个有5个表格的任务。 其中两个是表单,其他的是使用modelformset_factory生成的 背景: 我需要构建一个处理以下5种表单的视图: CdnUrl |-- Http |-- Location | -- HttpRedirect | -- HttpProxy |-- Location | -- HttpRedirect | -- HttpProxy |-- Location

我正在做一个有5个表格的任务。 其中两个是表单,其他的是使用modelformset_factory生成的

背景:

我需要构建一个处理以下5种表单的视图:

CdnUrl
|-- Http
    |-- Location
        | -- HttpRedirect
        | -- HttpProxy
    |-- Location
        | -- HttpRedirect
        | -- HttpProxy
    |-- Location
        | -- HttpRedirect
        | -- HttpProxy
无法同时插入HttpProxy和HttpRedirect。只有HttpRedirect或HttpProxy,而不是两者

forms.py 所以我最初的想法是我必须有2个表单和3个模型集

CdnUrlForm和HttpForm是我的表单。 LocationForm、HttpRedirectForm和HttpProxyForm将用于构建我的表单集

我这样做是因为要保存一致的记录,我需要: -CdnUrl数据 -Http数据 -位置数据 -HttpProxy或HttpRedirect数据

我的设计是:

CdnUrlForm(仅一种形式) HttpForm(仅一种形式) 位置(我可以在每页插入多个位置) HttpProxy(每个位置只能插入一个HttpProxy) HttpRedirect(每个位置只能插入一个HttpRedirect)

以下是我的看法:

views.py 每当我将数据发布到此视图时,我的模型表单集似乎未被验证。当然,我的代码是错误的,但我不知道如何处理所有这些表单来执行以下操作:

从CdnUrlForm插入数据 从HttpForm插入数据 插入所有位置

对于每个位置,检查HttpRedirectForm实例是否有效。如果它们有效,我只能插入HttpRedirectForm数据,而不能插入HttpProxy(因此我将忽略HttpProxyForm中的任何数据)

这是我的模型:

models.py
导入uuid
起始日期时间导入日期
从django.conf导入设置
从django.db导入模型
从django.core.exceptions导入ValidationError
从django.core.urlResolver反向导入
从django.utils.translation导入ugettext\u lazy作为_
从azionmanager.validators.URL\验证程序导入验证\域
类别CdnUrl(型号.型号):
cdn_url=models.CharField(uu(“cdn url”),最大长度=255,null=False,blank=False,unique=True)
account=models.ForeignKey(“controlpanel.Accounts”,null=False,blank=False)
#相关服务
service=models.ForeignKey(“controlpanel.Services”,null=False,blank=False)
#用于创建cdn url字段的顺序字段
sequential=models.IntegerField()
@类方法
def get_next_序列(cls、帐户、服务):
“”“如果CDN URL尚不存在,请获取下一个序列号。”“”
sequential=cls.objects.filter(account=account,service=service).defer(“sequential”).order\u by(“-sequential”)
如果不是连续的:
返回1
返回顺序[0]。顺序+1
def create_cdn_url(自我):
self.cdn_url=“{sequential}{account}.{service}.{domain}”\
格式(sequential=self.sequential,account=self.account.client\u id,service=self.service.url\u name,
域=设置.CDN\u域)
def get_绝对_url(自身):
返回反向(“cdnsetup.views.services\u setup.edit\u configuration”,
args=[self.service.service_type.lower(),
self.service.url\u名称,
self.id])
def保存(自身、*args、**kwargs):
self.sequential=CdnUrl.get\u next\u序列(self.account、self.service)
self.create_cdn_url()
超级(CdnUrl,self).save(*args,**kwargs)
类Http(models.Model):
状态\代码\选择=[
(“P”,“待定”),
(“V”,“有效”),
(“I”、“无效”),
(“L”,“锁定”)
]
协议_选项=[
(“HTTP”,“HTTP”),
(“HTTPS”、“HTTPS”),
(“HTTP+HTTPS”、“HTTP&HTTPS”),
]
粒度\u文件大小\u选项=[
(“SF”,“小文件”),
(“LF”,“大文件”),
]
cdn_url=models.ForeignKey(CdnUrl)
#分发设置
cdnurl_allow_content_access=models.BooleanField(u(“允许通过CDN url进行内容访问”),默认值为True)
configuration_state=models.BooleanField(u(“配置状态”),默认值=True)
protocol\u policy=models.CharField(u(“查看器协议策略”),max\u length=10,choices=protocol\u choices,null=False,
空白=假,
默认值=协议(选项[0][0])
ssl_certificate=models.CharField(uu(“ssl证书”),最大长度=255,null=True,blank=True)
gzip=models.BooleanField(uzip内容),默认值=False)
cname_url=models.TextField(_(“cname url”),最大长度=255,null=False,blank=False)
#原点设置
origin=models.CharField(u(“origin域名”),validators=[validate\u domain],max\u length=255,null=False,
空白=假)
host\u header=models.CharField(验证器=[validate\u domain],max\u length=255,null=True,blank=True)
#保存配置后使用
状态=models.CharField(u(“验证状态”),最大长度=1,选项=状态\代码\选项,可编辑=False,
默认值=状态\代码\选项[0][0])
#管理设置
手动配置=models.BooleanField(u(“手动配置”),默认值=False)
最小对象生命周期=models.IntegerField(最小对象生命周期),默认值=60,null=False,blank=True)
connect\u timeout=models.IntegerField(\uU(“连接超时”),默认值=60,null=True,blank=True)
read_timeout=models.IntegerField(u(“读取超时”),默认值=120,null=True,blank=True)
粒度文件大小=models.CharField((“粒度文件大小”),最大长度=2,
选项=粒度\u文件大小\u选项,
默认值=粒度\u文件大小\u选项[1][0],
空=假,空=真)
def ___; unicode(自):
返回“{cname_url}”。格式(cdn_url=self.cdn_url,cname_url=self.cname_url)
课程位置(models.Model):
http=models.ForeignKey(http)
uri=models.CharField(最大长度=255,null=False,blank=False)
创建时间=models.DateF
class OneRequiredFormSet(BaseFormSet):
    def __init__(self, *args, **kwargs):
        super(OneRequiredFormSet, self).__init__(*args, **kwargs)
        for form in self.forms:
            form.empty_permitted = False


class CustomLocationFormset(OneRequiredFormSet):
    def __init__(self, *args, **kwargs):
        super(CustomLocationFormset, self).__init__(*args, **kwargs)
        self.forms[0].fields["uri"].initial = "/"
        self.forms[0].fields["uri"].widget.attrs["readonly"] = True

    def clean(self):
        super(CustomLocationFormset, self).clean()
        if self.forms[0].cleaned_data["uri"] != "/":
            raise forms.ValidationError(u"Your first URI must be '/'")


class CustomInlineStreamingFormset(BaseFormSet):
    pass


class CdnUrlForm(forms.ModelForm):
    class Meta:
        model = CdnUrl
        fields = ("account", )

    def __init__(self, *args, **kwargs):
        self.accounts_range = kwargs.pop("accounts_range", None)

        super(CdnUrlForm, self).__init__(*args, **kwargs)

        if self.accounts_range:
            self.fields["account"].queryset = self.accounts_range

    def save(self, commit=True, **kwargs):
        service = kwargs.pop("service", None)
        instance = super(CdnUrlForm, self).save(commit=False)
        if service:
            instance.service = service
        if commit:
            instance.save()
        return instance


class HttpForm(forms.ModelForm):
    CONFIGURATION_STATE_CHOICES = [
        (True, "Enabled"),
        (False, "Disabled")
    ]

    GZIP_CHOICES = [
        (True, "On"),
        (False, "Off"),
    ]

    configuration_state = forms.TypedChoiceField(choices=CONFIGURATION_STATE_CHOICES,
                                                 widget=forms.RadioSelect,
                                                 initial=True)
    gzip = forms.TypedChoiceField(choices=GZIP_CHOICES,
                                  widget=forms.RadioSelect,
                                  initial=False)

    class Meta:
        model = Http
        fields = ("cdnurl_allow_content_access",
                  "configuration_state",
                  "protocol_policy",
                  "ssl_certificate",
                  "gzip",
                  "cname_url",
                  "origin",
                  "host_header",
                  # admin fields
                  "manual_configuration",
                  "minimum_object_lifetime",
                  "connect_timeout",
                  "read_timeout",
                  "granularity_file_size", )


class LocationForm(forms.ModelForm):
    class Meta:
        model = Location
        fields = ("uri", )


class HttpRedirectForm(forms.ModelForm):
    class Meta:
        model = HttpRedirect
        fields = ("domain_redirect", )


class HttpProxyForm(forms.ModelForm):

    CACHE_QUERY_STRING_CHOICES = [
        (True, "Yes"),
        (False, "No (Improves Caching)"),
    ]

    cache_query_string = forms.TypedChoiceField(choices=CACHE_QUERY_STRING_CHOICES,
                                                widget=forms.RadioSelect,
                                                initial=False)

    class Meta:
        model = HttpProxy
        fields = ("end_user_caching",
                  "expires_range",
                  "expires_value",
                  "cdn_object_caching",
                  "cdn_object_lifetime",
                  "allowed_http_methods",
                  "forward_cookie",
                  "white_list_cookie",
                  "cache_query_string",
                  "proxy_headers",
                  "remove_headers",
                  "comments", )

    def clean(self):
        cleaned_data = super(HttpProxyForm, self).clean()
        expires_range = cleaned_data.get("expires_range")
        expires_value = cleaned_data.get("expires_value")

        if expires_range and expires_range.upper() == "Y" and expires_value > 10:
            raise forms.ValidationError(u"Invalid Range (Max is 10 Years)")

        return cleaned_data
@reversion.create_revision()
@login_required
@user_passes_test(lambda u: u.is_active)
def create_configuration(request, service_type, service_code):
    contact_logged = request.user.get_profile()
    accounts_range = contact_logged.account.get_self_and_children()

    contact_services = get_contact_services(request)

    service = Services.objects.get(url_name=service_code)

    cdn_url_form = CdnUrlForm(request.POST or None, accounts_range=accounts_range)

    http_form = HttpForm(request.POST or None)

    LocationFormSet = modelformset_factory(Location, form=LocationForm, formset=CustomLocationFormset, extra=2,
                                           can_delete=False)
    location_form_set = LocationFormSet(request.POST or None)

    RedirectFormSet = modelformset_factory(HttpRedirect, form=HttpRedirectForm, can_delete=False, extra=2)

    ProxyFormSet = modelformset_factory(HttpProxy, form=HttpProxyForm, can_delete=False, extra=2)

    redirect_form_set = RedirectFormSet(request.POST or None, queryset=HttpRedirect.objects.none())
    proxy_form_set = ProxyFormSet(request.POST or None, queryset=HttpProxy.objects.none())

    if request.method == "POST":
        if cdn_url_form.is_valid():
            cdn_url_instance = cdn_url_form.save(commit=False, service=service)

            if http_form.is_valid() and location_form_set.is_valid():
                http_instance = http_form.save(commit=False)

                for location_form in location_form_set:
                    location_instance = location_form.save(commit=False)

                    if redirect_form_set.is_valid():
                        for redirect_form in redirect_form_set:
                            cdn_url_instance.save()
                            redirect_instance = redirect_form.save(commit=False)
                            http_instance.cdn_url = cdn_url_instance
                            http_instance.save()
                            location_instance.http = http_instance
                            location_instance.save()
                            redirect_instance.location = location_instance
                            redirect_instance.save()

                    if proxy_form_set.is_valid():
                        for proxy_form in redirect_form_set:
                            cdn_url_instance.save()
                            proxy_instance = proxy_form.save(commit=False)
                            http_instance.cdn_url = cdn_url_instance
                            http_instance.save()
                            location_instance.http = http_instance
                            location_instance.save()
                            proxy_instance.location = location_instance
                            proxy_instance.save()

                return HttpResponseRedirect(reverse("dashboard"))

    return render_to_response(
        "cdnsetup/configuration/create_or_edit.html",
        {"contact_services": contact_services,
         "service_type": service_type,
         "cdn_url_form": cdn_url_form,
         "http_form": http_form,
         "location_form_set": location_form_set,
         "redirect_form_set": redirect_form_set,
         "proxy_form_set": proxy_form_set},
        RequestContext(request),
    )
import uuid
from datetime import date
from django.conf import settings
from django.db import models
from django.core.exceptions import ValidationError
from django.core.urlresolvers import reverse
from django.utils.translation import ugettext_lazy as _
from azionmanager.validators.urls_validator import validate_domain


class CdnUrl(models.Model):
    cdn_url = models.CharField(_("cdn url"), max_length=255, null=False, blank=False, unique=True)
    account = models.ForeignKey("controlpanel.Accounts", null=False, blank=False)
    # related service
    service = models.ForeignKey("controlpanel.Services", null=False, blank=False)
    # sequential field used to create cdn url field
    sequential = models.IntegerField()

    @classmethod
    def get_next_sequence(cls, account, service):
        """Get the next sequential number if CDN URL does not exist yet."""
        sequential = cls.objects.filter(account=account, service=service).defer("sequential").order_by("-sequential")
        if not sequential:
            return 1
        return sequential[0].sequential + 1

    def create_cdn_url(self):
        self.cdn_url = "{sequential}{account}.{service}.{domain}". \
            format(sequential=self.sequential, account=self.account.client_id, service=self.service.url_name,
                   domain=settings.CDN_DOMAIN)

    def get_absolute_url(self):
        return reverse("cdnsetup.views.services_setup.edit_configuration",
                       args=[self.service.service_type.lower(),
                             self.service.url_name,
                             self.id])

    def save(self, *args, **kwargs):
        self.sequential = CdnUrl.get_next_sequence(self.account, self.service)
        self.create_cdn_url()
        super(CdnUrl, self).save(*args, **kwargs)


class Http(models.Model):
    STATUS_CODES_CHOICES = [
        ("P", "Pending"),
        ("V", "Valid"),
        ("I", "Invalid"),
        ("L", "Locked")
    ]

    PROTOCOL_CHOICES = [
        ("HTTP", "HTTP"),
        ("HTTPS", "HTTPS"),
        ("HTTP+HTTPS", "HTTP & HTTPS"),
    ]

    GRANULARITY_FILE_SIZE_CHOICES = [
        ("SF", "Small Files"),
        ("LF", "Large Files"),
    ]

    cdn_url = models.ForeignKey(CdnUrl)

    # distribution settings

    cdnurl_allow_content_access = models.BooleanField(_("allow content access through CDN url"), default=True)
    configuration_state = models.BooleanField(_("configuration state"), default=True)
    protocol_policy = models.CharField(_("viewer protocol policy"), max_length=10, choices=PROTOCOL_CHOICES, null=False,
                                       blank=False,
                                       default=PROTOCOL_CHOICES[0][0])
    ssl_certificate = models.CharField(_("ssl certificate"), max_length=255, null=True, blank=True)
    gzip = models.BooleanField(_("gzip content"), default=False)

    cname_url = models.TextField(_("cname url"), max_length=255, null=False, blank=False)

    # origin settings

    origin = models.CharField(_("origin domain name"), validators=[validate_domain], max_length=255, null=False,
                              blank=False)
    host_header = models.CharField(validators=[validate_domain], max_length=255, null=True, blank=True)

    # used after configuration is saved
    status = models.CharField(_("validation status"), max_length=1, choices=STATUS_CODES_CHOICES, editable=False,
                              default=STATUS_CODES_CHOICES[0][0])

    # admin settings

    manual_configuration = models.BooleanField(_("manual configuration"), default=False)
    minimum_object_lifetime = models.IntegerField(_("minimum object lifetime"), default=60, null=False, blank=True)
    connect_timeout = models.IntegerField(_("connect timeout"), default=60, null=True, blank=True)
    read_timeout = models.IntegerField(_("read timeout"), default=120, null=True, blank=True)
    granularity_file_size = models.CharField(_("granularity file size"), max_length=2,
                                             choices=GRANULARITY_FILE_SIZE_CHOICES,
                                             default=GRANULARITY_FILE_SIZE_CHOICES[1][0],
                                             null=False, blank=True)

    def __unicode__(self):
        return "<{cdn_url}>: {cname_url}".format(cdn_url=self.cdn_url, cname_url=self.cname_url)


class Location(models.Model):
    http = models.ForeignKey(Http)
    uri = models.CharField(max_length=255, null=False, blank=False)

    created_at = models.DateField(_("create date"), default=date.today)
    updated_at = models.DateField(_("update date"), auto_now_add=True)


class HttpRedirect(models.Model):
    location = models.ForeignKey(Location, related_name="redirect")

    domain_redirect = models.URLField(_("domain redirect"), max_length=255, null=False, blank=False)


class HttpProxy(models.Model):
    RANGE_UNITS = [
        ("S", "Seconds"),
        ("M", "Minutes"),
        ("H", "Hours"),
        ("D", "Days"),
        ("W", "Weeks"),
        ("M", "Months"),
        ("Y", "Years"),
    ]

    GRANULARITY_FILE_SIZE = [
        ("SF", "Small Files"),
        ("LF", "Large Files"),
    ]

    CACHING_CHOICES = [
        ("O", "Use Origin Cache Headers"),
        ("C", "Customize"),
    ]

    location = models.ForeignKey(Location, related_name="proxy")

    # cache settings

    end_user_caching = models.CharField(_("end user caching"), max_length=1, choices=CACHING_CHOICES,
                                        default=CACHING_CHOICES[0][0])
    expires_range = models.CharField(_("expires_range"), max_length=2, choices=RANGE_UNITS, default=RANGE_UNITS[3][0])
    expires_value = models.IntegerField(_("expires_value"), default=30)

    cdn_object_caching = models.CharField(_("cdn object caching"), max_length=1, choices=CACHING_CHOICES,
                                          default=CACHING_CHOICES[0][0])
    cdn_object_lifetime = models.IntegerField(_("cdn object lifetime"), default=10080, null=False, blank=False)

    allowed_http_methods = models.TextField(_("allowed http methods"), max_length=255, null=False, blank=False)
    forward_cookie = models.CharField(_("forward cookie"), max_length=255, null=True, blank=True)
    white_list_cookie = models.CharField(_("white list cookie"), max_length=255, null=True, blank=True)
    cache_query_string = models.BooleanField(_("cache query string"), default=False)

    proxy_headers = models.TextField(_("proxy headers"), null=True, blank=True)
    remove_headers = models.TextField(_("remove headers"), null=True, blank=True)

    # add comments to the configuration
    comments = models.TextField(null=True, blank=True)

    def clean(self):
        if self.cdn_object_lifetime < self.location.http.cdn_url.minimum_object_lifetime:
            raise ValidationError(u"Object lifetime can not be less than {minimum_object_lifetime}".format(
                minimum_object_lifetime=self.location.http.cdn_url.minimum_object_lifetime))

    def __unicode__(self):
        return "<{cdn_url}>: {uri}".format(cdn_url=self.cdn_url, uri=self.uri)