Django 如何在一个页面中管理多个modelformset_工厂?
我正在做一个有5个表格的任务。 其中两个是表单,其他的是使用modelformset_factory生成的 背景: 我需要构建一个处理以下5种表单的视图: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
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)