Enforce unique Project.name for same user and unique Session.name for same user and project
This commit is contained in:
parent
40c75de3ce
commit
c568c09c00
|
@ -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
|
||||
|
|
|
@ -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')]),
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -13,7 +13,8 @@
|
|||
<th>{{ labels.dbms }}</th>
|
||||
<th>{{ labels.hardware }}</th>
|
||||
<th>{{ labels.tuning_session }}</th>
|
||||
<th>{{ labels.creation_time }}</th>
|
||||
<th>{{ labels.algorithm }}</th>
|
||||
<!-- <th>{{ labels.creation_time }}</th> -->
|
||||
<th>{{ labels.last_update }}</th>
|
||||
</tr>
|
||||
{% for session in sessions %}
|
||||
|
@ -22,8 +23,9 @@
|
|||
<td style="vertical-align:middle"><a href="{% url 'session' project.pk session.pk %}">{{ session.name }}</a></td>
|
||||
<td style="vertical-align:middle">{{ session.dbms.full_name }}</td>
|
||||
<td style="vertical-align:middle">{{ session.hardware }}</td>
|
||||
<td style="vertical-align:middle">{{ session.tuning_session }}</td>
|
||||
<td style="vertical-align:middle">{{ session.creation_time }}</td>
|
||||
<td style="vertical-align:middle">{{ session.session_type_name }}</td>
|
||||
<td style="vertical-align:middle">{{ session.algorithm_name }}</td>
|
||||
<!-- <td style="vertical-align:middle">{{ session.creation_time }}</td> -->
|
||||
<td style="vertical-align:middle">{{ session.last_update }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
|
|
@ -89,9 +89,13 @@ caption span {float: right;}
|
|||
<td><div class="text-right">{{ labels.hardware }}</div></td>
|
||||
<td>{{ session.hardware }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><div class="text-right">{{ labels.tuning_session }}</div></td>
|
||||
<td>{{ session.session_type_name }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><div class="text-right">{{ labels.algorithm }}</div></td>
|
||||
<td>{{ algorithm_name }}</td>
|
||||
<td>{{ session.algorithm_name }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><div class="text-right">{{ labels.creation_time }}</div></td>
|
||||
|
@ -101,10 +105,6 @@ caption span {float: right;}
|
|||
<td><div class="text-right">{{ labels.last_update }}</div></td>
|
||||
<td>{{ session.last_update }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><div class="text-right">{{ labels.tuning_session }}</div></td>
|
||||
<td>{{ session.tuning_session }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><div class="text-right">{{ labels.target_objective }}</div></td>
|
||||
<td>{{ metric_meta|get_item:session.target_objective|get_attr:"pprint" }}</td>
|
||||
|
|
|
@ -141,9 +141,10 @@ def home_projects_view(request):
|
|||
|
||||
@login_required(login_url=reverse_lazy('login'))
|
||||
def create_or_edit_project(request, project_id=''):
|
||||
form_kwargs = dict(user_id=request.user.pk, project_id=project_id)
|
||||
if request.method == 'POST':
|
||||
if project_id == '':
|
||||
form = ProjectForm(request.POST)
|
||||
form = ProjectForm(request.POST, **form_kwargs)
|
||||
if not form.is_valid():
|
||||
return render(request, 'edit_project.html', {'form': form})
|
||||
project = form.save(commit=False)
|
||||
|
@ -151,22 +152,24 @@ def create_or_edit_project(request, project_id=''):
|
|||
ts = now()
|
||||
project.creation_time = ts
|
||||
project.last_update = ts
|
||||
project.save()
|
||||
else:
|
||||
project = get_object_or_404(Project, pk=project_id, user=request.user)
|
||||
form = ProjectForm(request.POST, instance=project)
|
||||
form_kwargs.update(instance=project)
|
||||
form = ProjectForm(request.POST, **form_kwargs)
|
||||
if not form.is_valid():
|
||||
return render(request, 'edit_project.html', {'form': form})
|
||||
project.last_update = now()
|
||||
|
||||
project.save()
|
||||
return redirect(reverse('project_sessions', kwargs={'project_id': project.pk}))
|
||||
else:
|
||||
if project_id == '':
|
||||
project = None
|
||||
form = ProjectForm()
|
||||
form = ProjectForm(**form_kwargs)
|
||||
else:
|
||||
project = Project.objects.get(pk=int(project_id))
|
||||
form = ProjectForm(instance=project)
|
||||
project = Project.objects.get(pk=project_id)
|
||||
form_kwargs.update(instance=project)
|
||||
form = ProjectForm(**form_kwargs)
|
||||
context = {
|
||||
'project': project,
|
||||
'form': form,
|
||||
|
@ -191,6 +194,10 @@ def project_sessions_view(request, project_id):
|
|||
'button_create': 'create a new session',
|
||||
}))
|
||||
form_labels['title'] = "Your Sessions"
|
||||
for session in sessions:
|
||||
session.session_type_name = Session.TUNING_OPTIONS[session.tuning_session]
|
||||
session.algorithm_name = AlgorithmType.name(session.algorithm)
|
||||
|
||||
context = {
|
||||
"sessions": sessions,
|
||||
"project": project,
|
||||
|
@ -245,8 +252,12 @@ def session_view(request, project_id, session_id):
|
|||
knobs = SessionKnob.objects.get_knobs_for_session(session)
|
||||
knob_names = [knob["name"] for knob in knobs if knob["tunable"]]
|
||||
|
||||
session.session_type_name = Session.TUNING_OPTIONS[session.tuning_session]
|
||||
session.algorithm_name = AlgorithmType.name(session.algorithm)
|
||||
|
||||
form_labels = Session.get_labels()
|
||||
form_labels['title'] = "Session Info"
|
||||
|
||||
context = {
|
||||
'project': project,
|
||||
'dbmss': dbmss,
|
||||
|
@ -263,7 +274,6 @@ def session_view(request, project_id, session_id):
|
|||
'knob_names': knob_names,
|
||||
'filters': [],
|
||||
'session': session,
|
||||
'algorithm_name': AlgorithmType.TYPE_NAMES[session.algorithm],
|
||||
'results': results,
|
||||
'labels': form_labels,
|
||||
}
|
||||
|
@ -274,13 +284,14 @@ def session_view(request, project_id, session_id):
|
|||
@login_required(login_url=reverse_lazy('login'))
|
||||
def create_or_edit_session(request, project_id, session_id=''):
|
||||
project = get_object_or_404(Project, pk=project_id, user=request.user)
|
||||
form_kwargs = dict(user_id=request.user.pk, project_id=project_id, session_id=session_id)
|
||||
if request.method == 'POST':
|
||||
if not session_id:
|
||||
# Create a new session from the form contents
|
||||
form = SessionForm(request.POST)
|
||||
form = SessionForm(request.POST, **form_kwargs)
|
||||
if not form.is_valid():
|
||||
return render(request, 'edit_session.html',
|
||||
{'project': project, 'form': form})
|
||||
{'project': project, 'form': form, 'session': None})
|
||||
session = form.save(commit=False)
|
||||
session.user = request.user
|
||||
session.project = project
|
||||
|
@ -293,7 +304,8 @@ def create_or_edit_session(request, project_id, session_id=''):
|
|||
else:
|
||||
# Update an existing session with the form contents
|
||||
session = Session.objects.get(pk=session_id)
|
||||
form = SessionForm(request.POST, instance=session)
|
||||
form_kwargs.update(instance=session)
|
||||
form = SessionForm(request.POST, **form_kwargs)
|
||||
if not form.is_valid():
|
||||
return render(request, 'edit_session.html',
|
||||
{'project': project, 'form': form, 'session': session})
|
||||
|
@ -308,17 +320,19 @@ def create_or_edit_session(request, project_id, session_id=''):
|
|||
if session_id:
|
||||
# Return a pre-filled form for editing an existing session
|
||||
session = Session.objects.get(pk=session_id)
|
||||
form = SessionForm(instance=session)
|
||||
form_kwargs.update(instance=session)
|
||||
form = SessionForm(**form_kwargs)
|
||||
else:
|
||||
# Return a new form with defaults for creating a new session
|
||||
session = None
|
||||
form = SessionForm(
|
||||
form_kwargs.update(
|
||||
initial={
|
||||
'dbms': DBMSCatalog.objects.get(
|
||||
type=DBMSType.POSTGRES, version='9.6'),
|
||||
'algorithm': AlgorithmType.GPR,
|
||||
'target_objective': 'throughput_txn_per_sec',
|
||||
})
|
||||
form = SessionForm(**form_kwargs)
|
||||
context = {
|
||||
'project': project,
|
||||
'session': session,
|
||||
|
|
Loading…
Reference in New Issue