diff --git a/server/website/website/forms.py b/server/website/website/forms.py index 75ff36c..c463a2e 100644 --- a/server/website/website/forms.py +++ b/server/website/website/forms.py @@ -8,7 +8,6 @@ Created on Jul 25, 2017 @author: dvanaken ''' - from django import forms from .models import Session, Project, Hardware, SessionKnob @@ -25,6 +24,24 @@ class NewResultForm(forms.Form): 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=old-style-class,no-init model = Project @@ -50,7 +67,11 @@ class SessionForm(forms.ModelForm): storage_type = forms.ChoiceField(label='Storage Type', choices=StorageType.choices()) def __init__(self, *args, **kwargs): - super(SessionForm, self).__init__(*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 = False self.fields['tuning_session'].required = True @@ -59,8 +80,21 @@ class SessionForm(forms.ModelForm): self.fields['storage'].initial = 32 self.fields['storage_type'].initial = StorageType.SSD + 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)] + return valid + def save(self, commit=True): - model = super(SessionForm, self).save(commit=False) + model = super().save(commit=False) cpu2 = self.cleaned_data['cpu'] memory2 = self.cleaned_data['memory'] @@ -99,7 +133,7 @@ class SessionKnobForm(forms.ModelForm): name = forms.CharField(max_length=128) def __init__(self, *args, **kwargs): - super(SessionKnobForm, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.fields['session'].required = False self.fields['knob'].required = False self.fields['name'].widget.attrs['readonly'] = True diff --git a/server/website/website/migrations/0001_initial.py b/server/website/website/migrations/0001_initial.py index 76036a1..67d2d34 100644 --- a/server/website/website/migrations/0001_initial.py +++ b/server/website/website/migrations/0001_initial.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Generated by Django 1.10.1 on 2019-10-02 07:59 +# Generated by Django 1.10.1 on 2019-10-08 03:47 from __future__ import unicode_literals from django.conf import settings @@ -150,9 +150,6 @@ class Migration(migrations.Migration): ('last_update', models.DateTimeField()), ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), ], - options={ - 'abstract': False, - }, ), migrations.CreateModel( name='Result', @@ -186,16 +183,13 @@ class Migration(migrations.Migration): ('creation_time', models.DateTimeField()), ('last_update', models.DateTimeField()), ('upload_code', models.CharField(max_length=30, unique=True)), - ('tuning_session', models.CharField(choices=[('tuning_session', 'Tuning Session'), ('no_tuning_session', 'No Tuning'), ('randomly_generate', 'Randomly Generate')], default='tuning_session', max_length=64)), + ('tuning_session', models.CharField(choices=[('tuning_session', 'Tuning Session'), ('no_tuning_session', 'No Tuning'), ('randomly_generate', 'Randomly Generate')], default='tuning_session', max_length=64, verbose_name='session type')), ('target_objective', models.CharField(choices=[('throughput_txn_per_sec', 'Throughput'), ('99th_lat_ms', '99 Percentile Latency')], max_length=64, null=True)), ('dbms', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='website.DBMSCatalog')), ('hardware', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='website.Hardware')), ('project', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='website.Project')), ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), ], - options={ - 'abstract': False, - }, ), migrations.CreateModel( name='SessionKnob', @@ -264,6 +258,14 @@ class Migration(migrations.Migration): name='workload', unique_together=set([('dbms', 'hardware', 'name')]), ), + migrations.AlterUniqueTogether( + name='session', + unique_together=set([('user', 'project', 'name')]), + ), + migrations.AlterUniqueTogether( + name='project', + unique_together=set([('user', 'name')]), + ), migrations.AlterUniqueTogether( name='pipelinedata', unique_together=set([('pipeline_run', 'task_type', 'workload')]), diff --git a/server/website/website/models.py b/server/website/website/models.py index aa02e1b..647e22e 100644 --- a/server/website/website/models.py +++ b/server/website/website/models.py @@ -164,6 +164,9 @@ class Project(BaseModel): x.delete() super(Project, self).delete(using, keep_parents) + class Meta: # pylint: disable=old-style-class,no-init + unique_together = ('user', 'name') + class Hardware(BaseModel): @@ -201,13 +204,14 @@ class Session(BaseModel): last_update = models.DateTimeField() upload_code = models.CharField(max_length=30, unique=True) - TUNING_OPTIONS = [ + TUNING_OPTIONS = OrderedDict([ ("tuning_session", "Tuning Session"), ("no_tuning_session", "No Tuning"), ("randomly_generate", "Randomly Generate") - ] - tuning_session = models.CharField(choices=TUNING_OPTIONS, - max_length=64, default='tuning_session') + ]) + tuning_session = models.CharField(choices=TUNING_OPTIONS.items(), + max_length=64, default='tuning_session', + verbose_name="session type") TARGET_OBJECTIVES = [ ('throughput_txn_per_sec', 'Throughput'), @@ -228,6 +232,9 @@ class Session(BaseModel): r.delete() super(Session, self).delete(using=DEFAULT_DB_ALIAS, keep_parents=False) + class Meta: # pylint: disable=old-style-class,no-init + unique_together = ('user', 'project', 'name') + class SessionKnobManager(models.Manager): @staticmethod diff --git a/server/website/website/templates/project_sessions.html b/server/website/website/templates/project_sessions.html index 00fa131..44e3785 100644 --- a/server/website/website/templates/project_sessions.html +++ b/server/website/website/templates/project_sessions.html @@ -13,7 +13,8 @@