ottertune/server/website/website/forms.py

162 lines
5.7 KiB
Python

#
# OtterTune - forms.py
#
# Copyright (c) 2017-18, Carnegie Mellon University Database Group
#
from django import forms
from .db import target_objectives
from .models import Session, Project, Hardware, SessionKnob
from .types import StorageType
class NewResultForm(forms.Form):
upload_code = forms.CharField(max_length=30)
metrics_before = forms.FileField()
metrics_after = forms.FileField()
knobs = forms.FileField()
summary = forms.FileField()
execution_times = forms.CharField(required=False, strip=True)
class ProjectForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.user_id = kwargs.pop('user_id')
self.project_id = kwargs.pop('project_id')
super().__init__(*args, **kwargs)
def is_valid(self):
valid = super().is_valid()
if valid:
new_name = self.cleaned_data['name']
user_projects = Project.objects.filter(
user__id=self.user_id, name=new_name)
if self.project_id:
user_projects = user_projects.exclude(id=self.project_id)
if user_projects.exists():
valid = False
self._errors['name'] = ["Project '{}' already exists.".format(new_name)]
return valid
class Meta: # pylint: disable=no-init
model = Project
fields = ['name', 'description']
widgets = {
'name': forms.TextInput(attrs={'required': True}),
'description': forms.Textarea(attrs={'maxlength': 500,
'rows': 5}),
}
class SessionForm(forms.ModelForm):
gen_upload_code = forms.BooleanField(widget=forms.CheckboxInput,
initial=False,
required=False,
label='Get new upload code')
cpu = forms.IntegerField(label='Number of CPUs', min_value=1)
memory = forms.IntegerField(label='Memory (GB)', min_value=1)
storage = forms.IntegerField(label='Storage (GB)', min_value=1)
storage_type = forms.ChoiceField(label='Storage Type', choices=StorageType.choices())
def __init__(self, *args, **kwargs):
self.project_id = kwargs.pop('project_id')
self.user_id = kwargs.pop('user_id')
self.session_id = kwargs.pop('session_id')
super().__init__(*args, **kwargs)
self.fields['description'].required = False
self.fields['target_objective'].required = True
self.fields['tuning_session'].required = True
self.initial.update(cpu=4, memory=16, storage=32,
storage_type=StorageType.SSD)
target_objs = target_objectives.get_all()
choices = set()
for entry in target_objs.values():
for name, obj in entry.items():
choices.add((name, obj.label))
target_obj_choices = sorted(choices)
self.fields['target_objective'].widget = forms.Select(
choices=target_obj_choices)
def is_valid(self):
valid = super().is_valid()
if valid:
new_name = self.cleaned_data['name']
user_sessions = Session.objects.filter(
user__id=self.user_id, project__id=self.project_id, name=new_name)
if self.session_id:
user_sessions = user_sessions.exclude(id=self.session_id)
if user_sessions.exists():
valid = False
self._errors['name'] = ["Session '{}' already exists.".format(new_name)]
if valid:
dbms = self.cleaned_data['dbms']
assert dbms is not None
target_obj_name = self.cleaned_data['target_objective']
try:
target_objectives.get_instance(dbms.pk, target_obj_name)
except KeyError:
self._errors['target_objective'] = \
["Invalid target objective '{}' for dbms {}.".format(
target_obj_name, dbms.full_name)]
valid = False
return valid
def save(self, commit=True):
model = super().save(commit=False)
cpu2 = self.cleaned_data['cpu']
memory2 = self.cleaned_data['memory']
storage2 = self.cleaned_data['storage']
storage_type2 = self.cleaned_data['storage_type']
hardware, _ = Hardware.objects.get_or_create(cpu=cpu2,
memory=memory2,
storage=storage2,
storage_type=storage_type2)
model.hardware = hardware
if commit:
model.save()
return model
class Meta: # pylint: disable=no-init
model = Session
fields = ('name', 'description', 'tuning_session', 'dbms', 'cpu', 'memory', 'storage',
'algorithm', 'target_objective', 'hyperparameters')
widgets = {
'name': forms.TextInput(attrs={'required': True}),
'description': forms.Textarea(attrs={'maxlength': 500, 'rows': 5}),
'hyperparameters': forms.Textarea(attrs={'maxlength': 5000, 'rows': 15}),
}
labels = {
'dbms': 'DBMS',
}
class SessionKnobForm(forms.ModelForm):
name = forms.CharField(max_length=128)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['session'].required = False
self.fields['knob'].required = False
self.fields['name'].widget.attrs['readonly'] = True
class Meta: # pylint: disable=no-init
model = SessionKnob
fields = ['session', 'knob', 'minval', 'maxval', 'lowerbound', 'upperbound', 'tunable']