4
\$\begingroup\$

I am making a small database and these are the following files. The scripts are working. How can I improve my scripts? Are there any places where a problem could occur? I have yet to write tests for this. Let me know if you need further details.

models.py

from django.db import models
from django.contrib import admin
from django.utils import timezone


class ProteinDatabase(models.Model):
    name = models.CharField(max_length=15, blank=True, null=False)
    oldname = models.CharField(max_length=15, blank=True, null=False)
    accession = models.CharField(max_length=25, blank=True, null=False)
    year = models.CharField(max_length=5, blank=True, null=False)
    fastasequence = models.TextField(blank=True, null=False)

    class Meta:
        ordering = ('name',)

    def publish(self):
        self.published_date = timezone.now()
        self.save()

    def __str__(self):
        return self.name

class ProteinDatabaseAdmin(admin.ModelAdmin):
    search_fields = ('name', 'oldname','accession','year')

class Description(models.Model):
    name = models.CharField(max_length=7) 
    description = models.TextField()

    class Meta:
        ordering = ('name',)

    def __str__(self):
        return self.name

class UserUploadData(models.Model):
    session_key = models.CharField(max_length=40, default=None)
    name = models.CharField(max_length=15, blank=True, null=False)
    fastasequence = models.TextField(blank=True, null=False)

urls.py

from django.urls import path
from database import views

urlpatterns = [
    path('', views.home, name='home'),
    path('database/', views.database, name='database'),
    path('category_<str:category>', views.category, name='category'),
    path('search/', views.search ,name='search'),
    path('search/add_cart/', views.add_cart ,name='add_cart'),
    path('remove_cart/<int:id>/', views.remove_cart ,name='remove_cart'),
    path('clear_session/', views.clear_session ,name='clear_session'),
    path('view_cart/', views.view_cart ,name='view_cart'),
    path('clear_session_temp_model/', views.clear_session_temp_model ,name='clear_session_temp_model'),
    path('temporary_model_remove/<int:id>/', views.temporary_model_remove ,name='temporary_model_remove'),
    path('temporary_model/', views.temporary_model ,name='temporary_model'),
    path('download_all_sequences/', views.download_all_sequences ,name='download_all_sequences'),

]

views.py

from django.shortcuts import render, redirect
from .models import ProteinDatabase, UserUploadData, Description
from .forms import UserSubmittedSequenceAnalysis
from django.views.decorators.csrf import csrf_exempt
from django.db.models import Q
from django.contrib import messages
from django.http import HttpResponse
from django.conf import settings
from django.core.files.storage import default_storage
from django.core.files.base import ContentFile
from io import StringIO
from Bio import SeqIO
import re
import textwrap

def home(request):
    return render(request, 'database/home.html')

def category(request, category=None):

    """
    Filter the database according to the available categories and return the results.

    """

    context = {
        'proteins': ProteinDatabase.objects.filter(name__istartswith=category),
        'descriptions': Description.objects.filter(name__istartswith=category)
    }
    return render(request, 'database/category_update.html', context)

def database(request):
    """
    Filter the database according to the categories prefixes

    """
    categories = ProteinDatabase.objects.order_by('name').values_list('name').distinct()
    category_prefixes = []
    for category in categories:
        prefix = category[0][:3]
        if prefix not in category_prefixes:
            category_prefixes.append(prefix)

    context = {
        'category_prefixes': category_prefixes,
        'descriptions': Description.objects.all()
    }
    return render(request, 'database/database.html', context)


def search(request):

    """
    This will search according to the keywords. It will also filter and return the results

   """
    context = {
        'proteins': ProteinDatabase.objects.all()
    }

    if request.method =='POST':
        search_term = request.POST['search_term']

        search_term = search_term.strip()

        searches = re.split(':|, ?|\s |\- |_ |. |; |\*|\n', search_term)

        q_objects = Q()
        for search in searches:
            q_objects.add(Q(name__icontains=search), Q.OR)

        proteins = ProteinDatabase.objects.filter(q_objects)

        if proteins:
            return render(request,'database/search_results.html', {'proteins' : proteins} )

    return render(request,'database/search_page.html')

def add_cart(request):
    '''
    This will add the proteins to the cart.

    '''

    if request.method == 'POST':
        selected_values = request.POST.getlist('name', []) # qs=param1=1&param1=3
        previously_selected_values = request.session.get('list_names', []) # session is a dict that has a list for the key list_names
        previously_selected_values.extend(selected_values)

        request.session['list_names'] = previously_selected_values
        profile_length = len(selected_values)
        message_profile = "Selected {} proteins added to the cart".format(profile_length)
        messages.success(request, message_profile)

    return redirect("search")


def clear_session(request):

    """
    This will clear the session.

    """

    session_key = list(request.session.keys())

    for key in session_key:
        del request.session[key]

    return redirect("view_cart")

def remove_cart(request, id):
    '''
    This will remove the profiles one by one from the cart
    '''

    protein = ProteinDatabase.objects.get(id=id)

    selected_values = request.session.get('list_names')
    selected_values.remove(protein.name)
    request.session.modified = True


    if not selected_values:
        message_profile = "Please add sequences to the cart"
        messages.success(request, message_profile)
        return redirect("search")

    else:
        return redirect("view_cart")

def view_cart(request):

    '''
    This will show the cart page with list of profiles
    '''


    selected_values = request.session.get('list_names')

    userdata = UserUploadData.objects.filter(session_key=request.session.session_key)

    context = {
        'proteins': ProteinDatabase.objects.all(),
        'selected_groups': selected_values,
        'userdata' : userdata
    }

    return render(request, 'database/search_user_data.html', context)

def clear_session_temp_model(request):

    UserUploadData.objects.filter(session_key=request.session.session_key).delete()

    return redirect("view_cart")


def temporary_model_remove(request, id):

    instance = UserUploadData.objects.get(session_key=request.session.session_key, id=id)
    instance.delete()

    return redirect("view_cart")

def temporary_model(request):

    """
    A user will upload a sequence or list of sequences. These sequences has to be stored
    temporarily in the sesssion. The html file will have a table where the user can delete/update the sequences.

    """

    if request.method =='POST':

        file = request.POST['fulltextarea']
        if not file:
            message_profile = "Please add some sequences"
            messages.success(request, message_profile)
            return redirect("view_cart")

        content = ContentFile(file)

        for rec in SeqIO.parse(content, "fasta"):
            name = rec.id
            sequence = str(rec.seq)
            UserUploadData.objects.create(session_key=request.session.session_key, name=name, fastasequence=sequence)

        message_profile = "Added the sequence"
        messages.success(request, message_profile)

    return redirect("view_cart")


@csrf_exempt
def download_all_sequences(request):

    selected_values = request.session.get('list_names', [])
    userdata = UserUploadData.objects.filter(session_key=request.session.session_key)

    if not selected_values and not userdata.exists():
        message_profile = "Please add sequences to the cart"
        messages.success(request, message_profile)
        return redirect("view_cart")

    else:
        file = StringIO()

        data = ProteinDatabase.objects.filter(name__in=selected_values)
        for item in data:
            fasta = textwrap.fill(item.fastasequence, 80)
            str_to_write = f">{item.name}\n{fasta}\n"
            file.write(str_to_write)

        for record in userdata:
            fasta = textwrap.fill(record.fastasequence, 80)
            str_to_write = f">{record.name}\n{fasta}\n"
            file.write(str_to_write)

        response = HttpResponse(file.getvalue(), content_type="text/plain")
        response['Content-Disposition'] = 'attachment;filename=data_fasta.txt'
        response['Content-Length'] = file.tell()
        return response

\$\endgroup\$
1
  • \$\begingroup\$ Not worth making an answer for: Pick a quotation method for your strings and stick with it. Some of your doc strings use single quotes, other use double quotes. Same with some other strings, like accessing HTTP headers with single but most strings using double. \$\endgroup\$
    – Gloweye
    Commented Sep 13, 2019 at 9:59

1 Answer 1

3
\$\begingroup\$

This is really not bad at all. I only found a couple of things worth mentioning - run a linter which will tell you that you sometimes have too many blank lines inside of your function. Also, this:

if not selected_values:
    message_profile = "Please add sequences to the cart"
    messages.success(request, message_profile)
    return redirect("search")

else:
    return redirect("view_cart")

could stand to be inverted, i.e.

if selected_values:
    return redirect("view_cart")
message_profile = "Please add sequences to the cart"
messages.success(request, message_profile)
return redirect("search")

and here:

    return redirect("view_cart")

else:

you can drop the else.

In terms of function documentation, something like this:

def clear_session(request):

    """
    This will clear the session.

    """

should have a PEP484 type hint on request. Plus, either that docstring should be expanded to include more information than we can garner just by reading the method name, or it should be deleted. This pattern:

# do the thing
do_thing()

isn't helping anyone.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.