Django model and views to summarize and plot an uploaded CSV
up vote
1
down vote
favorite
I have a simple web application where a user uploads a CSV of some dataset and some summary statistics and box plots are displayed. I heard that it is better to have so called skinny views and fat models, though I'm unsure how is best to divide the work. How could I improve my database schema and division of labour?
views.py
class HomeView(View):
"""View that handles when users land on the homepage"""
def get(self, request):
return render(request, 'summary/home.html')
# Will currently raise an HttpResponseNotAllowed if POST request received to home
@method_decorator(login_required, name='dispatch')
class UploadView(TemplateView):
"""Users land here after successfully signing in and are prompted to upload a CSV file"""
form_class = UploadFileForm
template_name = 'summary/uploads.html'
def get(self, request):
form = self.form_class()
datasets = Dataset.objects.filter(user=request.user)
context = {
'datasets': datasets,
'csv_form': form,
'within_dataset_limit': request.user.within_dataset_limit()
}
return render(request, self.template_name, context=context)
def post(self, request):
form = self.form_class(request.POST, request.FILES)
if form.is_valid():
uploaded_file = request.FILES['dataset_file']
datasets = Dataset.objects.filter(user=request.user)
context = {
'datasets': datasets,
'csv_form': form,
'within_dataset_limit': request.user.within_dataset_limit(),
}
# Check the file is a CSV
if not str(uploaded_file).lower().endswith('.csv'):
context['error'] = 'File not in CSV format.'
return render(request, 'summary/uploads.html', context)
# Check the file size is within the set limit
elif not 0 < uploaded_file.size < request.user.max_dataset_size:
context['error'] = 'File exceeds size limit.'
return render(request, 'summary/uploads.html', context)
else:
ds = Dataset(user=request.user, dataset_name=str(uploaded_file), dataset_file=uploaded_file)
ds.save()
return redirect(f'/{request.user.pk}/{ds.id}/overview/')
@method_decorator(login_required, name='dispatch')
class OverviewView(TemplateView):
"""Display head and summary statistics of the uploaded dataset"""
template_name = 'summary/overview.html'
def get(self, request, upk, dpk):
if request.user.pk == upk:
ds = Dataset.objects.get(pk=dpk)
head, summary, df = dataset_stats(ds)
request.session['dataframe'] = df.to_json()
context = {
'first_five': head,
'summary_stats': summary,
}
return render(request, self.template_name, context)
def delete_dataset(request, upk, dpk):
if request.method == 'POST':
if request.user.is_authenticated and request.user.pk == upk:
try:
ds = Dataset.objects.get(pk=dpk)
os.remove(ds.dataset_file.path)
ds.delete()
return HttpResponse(status=200)
except Dataset.DoesNotExist:
return HttpResponseNotFound()
return HttpResponseForbidden()
return HttpResponseBadRequest()
def boxplot(request):
"""Generation of boxplots to be moved to computation server"""
# Get the selected columns from the overview view
selected_columns = request.GET['selectedColumns']
selected_columns = json.loads(selected_columns)
code, boxplot_html = generate_plots(selected_columns, request.session.get('dataframe'))
if boxplot_html is not None:
return HttpResponse(status=code, content=boxplot_html)
else:
error = "Could not create your plots"
return HttpResponse(status=code, content=error)
models.py
def get_upload_path(instance, filename):
return "user_{}/{}".format(instance.user.pk, filename)
class Dataset(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True)
dataset_name = models.CharField(max_length=100)
date_added = models.DateTimeField(auto_now_add=True)
dataset_file = models.FileField(upload_to=get_upload_path)
def __str__(self):
return self.dataset_name
def save(self, *args, **kwargs):
user = CustomUser.objects.get(username=self.user)
if user.num_datasets == user.max_datasets:
return # Exceeding the max number of datasets
else:
user.num_datasets += 1
user.save()
super().save(*args, **kwargs)
def delete(self, *args, **kwargs):
user = CustomUser.objects.get(username=self.user)
user.num_datasets -= 1
user.save()
super().delete(*args, **kwargs)
python django
New contributor
awcot is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
add a comment |
up vote
1
down vote
favorite
I have a simple web application where a user uploads a CSV of some dataset and some summary statistics and box plots are displayed. I heard that it is better to have so called skinny views and fat models, though I'm unsure how is best to divide the work. How could I improve my database schema and division of labour?
views.py
class HomeView(View):
"""View that handles when users land on the homepage"""
def get(self, request):
return render(request, 'summary/home.html')
# Will currently raise an HttpResponseNotAllowed if POST request received to home
@method_decorator(login_required, name='dispatch')
class UploadView(TemplateView):
"""Users land here after successfully signing in and are prompted to upload a CSV file"""
form_class = UploadFileForm
template_name = 'summary/uploads.html'
def get(self, request):
form = self.form_class()
datasets = Dataset.objects.filter(user=request.user)
context = {
'datasets': datasets,
'csv_form': form,
'within_dataset_limit': request.user.within_dataset_limit()
}
return render(request, self.template_name, context=context)
def post(self, request):
form = self.form_class(request.POST, request.FILES)
if form.is_valid():
uploaded_file = request.FILES['dataset_file']
datasets = Dataset.objects.filter(user=request.user)
context = {
'datasets': datasets,
'csv_form': form,
'within_dataset_limit': request.user.within_dataset_limit(),
}
# Check the file is a CSV
if not str(uploaded_file).lower().endswith('.csv'):
context['error'] = 'File not in CSV format.'
return render(request, 'summary/uploads.html', context)
# Check the file size is within the set limit
elif not 0 < uploaded_file.size < request.user.max_dataset_size:
context['error'] = 'File exceeds size limit.'
return render(request, 'summary/uploads.html', context)
else:
ds = Dataset(user=request.user, dataset_name=str(uploaded_file), dataset_file=uploaded_file)
ds.save()
return redirect(f'/{request.user.pk}/{ds.id}/overview/')
@method_decorator(login_required, name='dispatch')
class OverviewView(TemplateView):
"""Display head and summary statistics of the uploaded dataset"""
template_name = 'summary/overview.html'
def get(self, request, upk, dpk):
if request.user.pk == upk:
ds = Dataset.objects.get(pk=dpk)
head, summary, df = dataset_stats(ds)
request.session['dataframe'] = df.to_json()
context = {
'first_five': head,
'summary_stats': summary,
}
return render(request, self.template_name, context)
def delete_dataset(request, upk, dpk):
if request.method == 'POST':
if request.user.is_authenticated and request.user.pk == upk:
try:
ds = Dataset.objects.get(pk=dpk)
os.remove(ds.dataset_file.path)
ds.delete()
return HttpResponse(status=200)
except Dataset.DoesNotExist:
return HttpResponseNotFound()
return HttpResponseForbidden()
return HttpResponseBadRequest()
def boxplot(request):
"""Generation of boxplots to be moved to computation server"""
# Get the selected columns from the overview view
selected_columns = request.GET['selectedColumns']
selected_columns = json.loads(selected_columns)
code, boxplot_html = generate_plots(selected_columns, request.session.get('dataframe'))
if boxplot_html is not None:
return HttpResponse(status=code, content=boxplot_html)
else:
error = "Could not create your plots"
return HttpResponse(status=code, content=error)
models.py
def get_upload_path(instance, filename):
return "user_{}/{}".format(instance.user.pk, filename)
class Dataset(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True)
dataset_name = models.CharField(max_length=100)
date_added = models.DateTimeField(auto_now_add=True)
dataset_file = models.FileField(upload_to=get_upload_path)
def __str__(self):
return self.dataset_name
def save(self, *args, **kwargs):
user = CustomUser.objects.get(username=self.user)
if user.num_datasets == user.max_datasets:
return # Exceeding the max number of datasets
else:
user.num_datasets += 1
user.save()
super().save(*args, **kwargs)
def delete(self, *args, **kwargs):
user = CustomUser.objects.get(username=self.user)
user.num_datasets -= 1
user.save()
super().delete(*args, **kwargs)
python django
New contributor
awcot is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
add a comment |
up vote
1
down vote
favorite
up vote
1
down vote
favorite
I have a simple web application where a user uploads a CSV of some dataset and some summary statistics and box plots are displayed. I heard that it is better to have so called skinny views and fat models, though I'm unsure how is best to divide the work. How could I improve my database schema and division of labour?
views.py
class HomeView(View):
"""View that handles when users land on the homepage"""
def get(self, request):
return render(request, 'summary/home.html')
# Will currently raise an HttpResponseNotAllowed if POST request received to home
@method_decorator(login_required, name='dispatch')
class UploadView(TemplateView):
"""Users land here after successfully signing in and are prompted to upload a CSV file"""
form_class = UploadFileForm
template_name = 'summary/uploads.html'
def get(self, request):
form = self.form_class()
datasets = Dataset.objects.filter(user=request.user)
context = {
'datasets': datasets,
'csv_form': form,
'within_dataset_limit': request.user.within_dataset_limit()
}
return render(request, self.template_name, context=context)
def post(self, request):
form = self.form_class(request.POST, request.FILES)
if form.is_valid():
uploaded_file = request.FILES['dataset_file']
datasets = Dataset.objects.filter(user=request.user)
context = {
'datasets': datasets,
'csv_form': form,
'within_dataset_limit': request.user.within_dataset_limit(),
}
# Check the file is a CSV
if not str(uploaded_file).lower().endswith('.csv'):
context['error'] = 'File not in CSV format.'
return render(request, 'summary/uploads.html', context)
# Check the file size is within the set limit
elif not 0 < uploaded_file.size < request.user.max_dataset_size:
context['error'] = 'File exceeds size limit.'
return render(request, 'summary/uploads.html', context)
else:
ds = Dataset(user=request.user, dataset_name=str(uploaded_file), dataset_file=uploaded_file)
ds.save()
return redirect(f'/{request.user.pk}/{ds.id}/overview/')
@method_decorator(login_required, name='dispatch')
class OverviewView(TemplateView):
"""Display head and summary statistics of the uploaded dataset"""
template_name = 'summary/overview.html'
def get(self, request, upk, dpk):
if request.user.pk == upk:
ds = Dataset.objects.get(pk=dpk)
head, summary, df = dataset_stats(ds)
request.session['dataframe'] = df.to_json()
context = {
'first_five': head,
'summary_stats': summary,
}
return render(request, self.template_name, context)
def delete_dataset(request, upk, dpk):
if request.method == 'POST':
if request.user.is_authenticated and request.user.pk == upk:
try:
ds = Dataset.objects.get(pk=dpk)
os.remove(ds.dataset_file.path)
ds.delete()
return HttpResponse(status=200)
except Dataset.DoesNotExist:
return HttpResponseNotFound()
return HttpResponseForbidden()
return HttpResponseBadRequest()
def boxplot(request):
"""Generation of boxplots to be moved to computation server"""
# Get the selected columns from the overview view
selected_columns = request.GET['selectedColumns']
selected_columns = json.loads(selected_columns)
code, boxplot_html = generate_plots(selected_columns, request.session.get('dataframe'))
if boxplot_html is not None:
return HttpResponse(status=code, content=boxplot_html)
else:
error = "Could not create your plots"
return HttpResponse(status=code, content=error)
models.py
def get_upload_path(instance, filename):
return "user_{}/{}".format(instance.user.pk, filename)
class Dataset(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True)
dataset_name = models.CharField(max_length=100)
date_added = models.DateTimeField(auto_now_add=True)
dataset_file = models.FileField(upload_to=get_upload_path)
def __str__(self):
return self.dataset_name
def save(self, *args, **kwargs):
user = CustomUser.objects.get(username=self.user)
if user.num_datasets == user.max_datasets:
return # Exceeding the max number of datasets
else:
user.num_datasets += 1
user.save()
super().save(*args, **kwargs)
def delete(self, *args, **kwargs):
user = CustomUser.objects.get(username=self.user)
user.num_datasets -= 1
user.save()
super().delete(*args, **kwargs)
python django
New contributor
awcot is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
I have a simple web application where a user uploads a CSV of some dataset and some summary statistics and box plots are displayed. I heard that it is better to have so called skinny views and fat models, though I'm unsure how is best to divide the work. How could I improve my database schema and division of labour?
views.py
class HomeView(View):
"""View that handles when users land on the homepage"""
def get(self, request):
return render(request, 'summary/home.html')
# Will currently raise an HttpResponseNotAllowed if POST request received to home
@method_decorator(login_required, name='dispatch')
class UploadView(TemplateView):
"""Users land here after successfully signing in and are prompted to upload a CSV file"""
form_class = UploadFileForm
template_name = 'summary/uploads.html'
def get(self, request):
form = self.form_class()
datasets = Dataset.objects.filter(user=request.user)
context = {
'datasets': datasets,
'csv_form': form,
'within_dataset_limit': request.user.within_dataset_limit()
}
return render(request, self.template_name, context=context)
def post(self, request):
form = self.form_class(request.POST, request.FILES)
if form.is_valid():
uploaded_file = request.FILES['dataset_file']
datasets = Dataset.objects.filter(user=request.user)
context = {
'datasets': datasets,
'csv_form': form,
'within_dataset_limit': request.user.within_dataset_limit(),
}
# Check the file is a CSV
if not str(uploaded_file).lower().endswith('.csv'):
context['error'] = 'File not in CSV format.'
return render(request, 'summary/uploads.html', context)
# Check the file size is within the set limit
elif not 0 < uploaded_file.size < request.user.max_dataset_size:
context['error'] = 'File exceeds size limit.'
return render(request, 'summary/uploads.html', context)
else:
ds = Dataset(user=request.user, dataset_name=str(uploaded_file), dataset_file=uploaded_file)
ds.save()
return redirect(f'/{request.user.pk}/{ds.id}/overview/')
@method_decorator(login_required, name='dispatch')
class OverviewView(TemplateView):
"""Display head and summary statistics of the uploaded dataset"""
template_name = 'summary/overview.html'
def get(self, request, upk, dpk):
if request.user.pk == upk:
ds = Dataset.objects.get(pk=dpk)
head, summary, df = dataset_stats(ds)
request.session['dataframe'] = df.to_json()
context = {
'first_five': head,
'summary_stats': summary,
}
return render(request, self.template_name, context)
def delete_dataset(request, upk, dpk):
if request.method == 'POST':
if request.user.is_authenticated and request.user.pk == upk:
try:
ds = Dataset.objects.get(pk=dpk)
os.remove(ds.dataset_file.path)
ds.delete()
return HttpResponse(status=200)
except Dataset.DoesNotExist:
return HttpResponseNotFound()
return HttpResponseForbidden()
return HttpResponseBadRequest()
def boxplot(request):
"""Generation of boxplots to be moved to computation server"""
# Get the selected columns from the overview view
selected_columns = request.GET['selectedColumns']
selected_columns = json.loads(selected_columns)
code, boxplot_html = generate_plots(selected_columns, request.session.get('dataframe'))
if boxplot_html is not None:
return HttpResponse(status=code, content=boxplot_html)
else:
error = "Could not create your plots"
return HttpResponse(status=code, content=error)
models.py
def get_upload_path(instance, filename):
return "user_{}/{}".format(instance.user.pk, filename)
class Dataset(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True)
dataset_name = models.CharField(max_length=100)
date_added = models.DateTimeField(auto_now_add=True)
dataset_file = models.FileField(upload_to=get_upload_path)
def __str__(self):
return self.dataset_name
def save(self, *args, **kwargs):
user = CustomUser.objects.get(username=self.user)
if user.num_datasets == user.max_datasets:
return # Exceeding the max number of datasets
else:
user.num_datasets += 1
user.save()
super().save(*args, **kwargs)
def delete(self, *args, **kwargs):
user = CustomUser.objects.get(username=self.user)
user.num_datasets -= 1
user.save()
super().delete(*args, **kwargs)
python django
python django
New contributor
awcot is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
New contributor
awcot is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
edited yesterday
200_success
127k15148412
127k15148412
New contributor
awcot is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
asked 2 days ago
awcot
61
61
New contributor
awcot is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
New contributor
awcot is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
awcot is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.
add a comment |
add a comment |
active
oldest
votes
active
oldest
votes
active
oldest
votes
active
oldest
votes
active
oldest
votes
awcot is a new contributor. Be nice, and check out our Code of Conduct.
awcot is a new contributor. Be nice, and check out our Code of Conduct.
awcot is a new contributor. Be nice, and check out our Code of Conduct.
awcot is a new contributor. Be nice, and check out our Code of Conduct.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f208478%2fdjango-model-and-views-to-summarize-and-plot-an-uploaded-csv%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown