start oef
This commit is contained in:
@@ -0,0 +1,9 @@
|
|||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
# Register your models here.
|
||||||
|
|
||||||
|
from .models import Entry, Formats
|
||||||
|
|
||||||
|
|
||||||
|
admin.site.register(Entry)
|
||||||
|
admin.site.register(Formats)
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class OefConfig(AppConfig):
|
||||||
|
default_auto_field = 'django.db.models.BigAutoField'
|
||||||
|
name = 'oef'
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
|
||||||
|
import django_filters
|
||||||
|
|
||||||
|
from .models import Entry
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
|
||||||
|
from django.db.models import Q
|
||||||
|
|
||||||
|
class EntryFilter(django_filters.FilterSet):
|
||||||
|
class Meta:
|
||||||
|
model = Entry
|
||||||
|
fields = {
|
||||||
|
"modality": ["icontains"],
|
||||||
|
"exam_code": ["icontains"],
|
||||||
|
"exam_name": ["icontains"],
|
||||||
|
"questions": ["icontains"],
|
||||||
|
"comments": ["icontains"],
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
from django.core.management.base import BaseCommand, CommandError
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
from oef.models import Entry
|
||||||
|
from bs4 import BeautifulSoup
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
help = "Imports the RCR spreadsheet"
|
||||||
|
|
||||||
|
def add_arguments(self, parser):
|
||||||
|
# parser.add_argument("poll_ids", nargs="+", type=int)
|
||||||
|
parser.add_argument('--file', type=argparse.FileType('r'))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def handle(self, *args, **options):
|
||||||
|
#with open(options["file"]) as f:
|
||||||
|
soup = BeautifulSoup(options["file"], "html.parser")
|
||||||
|
|
||||||
|
Entry.objects.all().delete()
|
||||||
|
rows = 0
|
||||||
|
for row in soup.find_all("tr"):
|
||||||
|
if rows > 0:
|
||||||
|
entry.questions = entry.questions + "\n" + row.find_all("td")[0].text
|
||||||
|
rows = rows - 1
|
||||||
|
if rows == 0:
|
||||||
|
entry.save()
|
||||||
|
continue
|
||||||
|
|
||||||
|
cells = row.find_all("td")
|
||||||
|
|
||||||
|
if cells[0].text == "Modality":
|
||||||
|
continue
|
||||||
|
|
||||||
|
|
||||||
|
entry = Entry()
|
||||||
|
entry.modality = cells[0].text
|
||||||
|
entry.exam_code = cells[1].text
|
||||||
|
entry.exam_name = cells[2].text
|
||||||
|
entry.questions = cells[3].text
|
||||||
|
entry.oef_name = cells[4].text
|
||||||
|
entry.comments = cells[5].text
|
||||||
|
|
||||||
|
if cells[0].has_attr("rowspan"):
|
||||||
|
rows = int(cells[0]["rowspan"]) - 1
|
||||||
|
else:
|
||||||
|
entry.save()
|
||||||
|
|
||||||
|
#Entry.objects.all().delete()
|
||||||
|
|
||||||
|
#for row in soup.find_all("tr"):
|
||||||
|
# cells = row.find_all("td")
|
||||||
|
# if len(cells) == 6:
|
||||||
|
# entry = Entry()
|
||||||
|
# entry.modality = cells[0].text
|
||||||
|
# entry.exam_code = cells[1].text
|
||||||
|
# entry.exam_name = cells[2].text
|
||||||
|
# entry.questions = cells[3].text
|
||||||
|
# #entry.
|
||||||
|
# entry.comments = cells[5].text
|
||||||
|
# entry.save()
|
||||||
|
# self.stdout.write(
|
||||||
|
# self.style.SUCCESS(f"Entry added: {entry.pk}/{entry.exam_name}")
|
||||||
|
# )
|
||||||
|
# else:
|
||||||
|
# self.stdout.write(
|
||||||
|
# self.style.WARNING(f"Skipping row: {row}")
|
||||||
|
# )
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
# Generated by Django 5.0.2 on 2024-10-07 13:30
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Entry',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('modality', models.CharField(max_length=200)),
|
||||||
|
('exam_code', models.CharField(max_length=50)),
|
||||||
|
('exam_name', models.CharField(max_length=200)),
|
||||||
|
('questions', models.TextField()),
|
||||||
|
('questions_original', models.TextField()),
|
||||||
|
('comments', models.TextField()),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Formats',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('name', models.CharField(max_length=200)),
|
||||||
|
('format', models.TextField()),
|
||||||
|
('inherits', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='oef.formats')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
# Generated by Django 5.0.2 on 2024-10-07 15:01
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('oef', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='entry',
|
||||||
|
name='oef_name',
|
||||||
|
field=models.CharField(blank=True, max_length=200),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='entry',
|
||||||
|
name='comments',
|
||||||
|
field=models.TextField(blank=True),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 5.0.2 on 2024-10-07 15:44
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('oef', '0002_entry_oef_name_alter_entry_comments'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='formats',
|
||||||
|
name='format',
|
||||||
|
field=models.TextField(blank=True),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
from django.db import models
|
||||||
|
from django.urls import reverse
|
||||||
|
|
||||||
|
# Create your models here.
|
||||||
|
class Entry(models.Model):
|
||||||
|
modality = models.CharField(max_length=200)
|
||||||
|
exam_code = models.CharField(max_length=50)
|
||||||
|
exam_name = models.CharField(max_length=200)
|
||||||
|
|
||||||
|
questions = models.TextField()
|
||||||
|
|
||||||
|
questions_original = models.TextField()
|
||||||
|
|
||||||
|
oef_name = models.CharField(max_length=200, blank=True)
|
||||||
|
|
||||||
|
comments = models.TextField(blank=True)
|
||||||
|
|
||||||
|
#format = models.ForeignKey('Formats', on_delete=models.CASCADE, null=True, blank=True)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.exam_name
|
||||||
|
|
||||||
|
def get_absolute_url(self):
|
||||||
|
return reverse("oef:entry_update", kwargs={"pk": self.pk})
|
||||||
|
|
||||||
|
def clean(self) -> None:
|
||||||
|
self.questions = self.questions.replace("\r\n", "\n")
|
||||||
|
return super().clean()
|
||||||
|
|
||||||
|
def save(self, *args, **kwargs):
|
||||||
|
self.questions = self.questions.replace("\r\n", "\n")
|
||||||
|
return super().save(*args, **kwargs)
|
||||||
|
|
||||||
|
class Formats(models.Model):
|
||||||
|
name = models.CharField(max_length=200)
|
||||||
|
format = models.TextField(blank=True)
|
||||||
|
|
||||||
|
inherits = models.ForeignKey('self', on_delete=models.CASCADE, null=True, blank=True)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
def get_absolute_url(self):
|
||||||
|
return reverse("oef:format_update", kwargs={"pk": self.pk})
|
||||||
|
|
||||||
|
def clean(self) -> None:
|
||||||
|
self.format = self.format.replace("\r\n", "\n")
|
||||||
|
return super().clean()
|
||||||
|
|
||||||
|
def save(self, *args, **kwargs):
|
||||||
|
self.format = self.format.replace("\r\n", "\n")
|
||||||
|
return super().save(*args, **kwargs)
|
||||||
|
|
||||||
|
def get_format(self):
|
||||||
|
formats = [self.format]
|
||||||
|
while self.inherits:
|
||||||
|
self = self.inherits
|
||||||
|
formats.append(self.format)
|
||||||
|
|
||||||
|
formats.reverse()
|
||||||
|
return "\n".join(formats)
|
||||||
Executable
+35
@@ -0,0 +1,35 @@
|
|||||||
|
import django_tables2 as tables
|
||||||
|
from django_tables2.utils import A
|
||||||
|
|
||||||
|
from generic.tables import SeriesImageColumn
|
||||||
|
|
||||||
|
from .models import (
|
||||||
|
Entry,
|
||||||
|
Formats
|
||||||
|
)
|
||||||
|
|
||||||
|
from django.utils.html import format_html
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class EntryTable(tables.Table):
|
||||||
|
edit = tables.LinkColumn(
|
||||||
|
"oef:entry_update", text="Edit", args=[A("pk")], orderable=False
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = Entry
|
||||||
|
template_name = "django_tables2/bootstrap4.html"
|
||||||
|
fields = (
|
||||||
|
"modality",
|
||||||
|
"exam_code",
|
||||||
|
"exam_name",
|
||||||
|
"questions",
|
||||||
|
"comments",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def render_questions(self, value):
|
||||||
|
return format_html("<pre>{}</pre>", value)
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
{% block css %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block navigation %}
|
||||||
|
<a href="{% url 'oef:entry_table_view' %}">Entries</a> /
|
||||||
|
<a href="{% url 'oef:formats_view' %}">Formats</a> /
|
||||||
|
{% endblock %}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
{% extends 'oef/base.html' %}
|
||||||
|
|
||||||
|
{% block css %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<div id="view-filter-options">
|
||||||
|
<details><summary>
|
||||||
|
<h3>Filter Entries</h3>
|
||||||
|
</summary>
|
||||||
|
<form action="" method="get">
|
||||||
|
|
||||||
|
{{ filter.form }}
|
||||||
|
|
||||||
|
<input class="btn btn-primary btn-sm mt-1 mb-1" type="submit" />
|
||||||
|
</form>
|
||||||
|
</details>
|
||||||
|
</div>
|
||||||
|
{% autoescape off %}
|
||||||
|
{% load render_table from django_tables2 %}
|
||||||
|
{% render_table table %}
|
||||||
|
{% endautoescape %}
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
{% extends 'oef/base.html' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<form method="post">{% csrf_token %}
|
||||||
|
{{ form }}
|
||||||
|
<input type="submit" value="Update">
|
||||||
|
</form>
|
||||||
|
{% endblock content %}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
|
||||||
|
{% extends 'oef/base.html' %}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<h2>Formats Search</h2>
|
||||||
|
|
||||||
|
The format {{format.name}} exists in the following {{ entries.count }} entries:
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
{{ format.get_format}}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
{% for entry, text in entry_list %}
|
||||||
|
<li class=" {% if not text %}no-extra{% endif %}">{{ entry.exam_name }} (<a href='{% url "oef:entry_update" entry.pk %}'>edit</a>)<br/> <pre>{{text}}<pre></li>
|
||||||
|
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
{% endblock content %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block css %}
|
||||||
|
<style type="text/css">
|
||||||
|
.no-extra {
|
||||||
|
color: blue;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
{% endblock %}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
{% extends 'oef/base.html' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<form method="post">{% csrf_token %}
|
||||||
|
{{ form }}
|
||||||
|
<input type="submit" value="Update">
|
||||||
|
</form>
|
||||||
|
{% endblock content %}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
|
||||||
|
{% extends 'oef/base.html' %}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<h2>Formats</h2>
|
||||||
|
<a href="{% url 'oef:format_create' %}">Create a new format</a>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
{% for format in formats %}
|
||||||
|
<li>
|
||||||
|
<a href="{% url 'oef:format_update' format.id %}">{{ format.name }}</a>
|
||||||
|
<a href="{% url 'oef:formats_apply' format.id %}">apply</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
{% endblock content %}
|
||||||
|
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
||||||
+33
@@ -0,0 +1,33 @@
|
|||||||
|
|
||||||
|
from django.contrib import admin
|
||||||
|
from django.urls import path, include
|
||||||
|
from django.conf import settings
|
||||||
|
from django.conf.urls.static import static
|
||||||
|
from django.views.generic import TemplateView
|
||||||
|
|
||||||
|
|
||||||
|
from . import views
|
||||||
|
|
||||||
|
app_name = "oef"
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
path(
|
||||||
|
"entries", views.EntryTableView.as_view(), name="entry_table_view"
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"formats", views.formats_view, name="formats_view"
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"formats/create", views.FormatsCreateView.as_view(), name="format_create"
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"entries/<int:pk>/update", views.EntryUpdateView.as_view(), name="entry_update"
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"formats/<int:pk>/update", views.FormatsUpdateView.as_view(), name="format_update"
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"formats/<int:pk>/apply", views.formats_apply, name="formats_apply"
|
||||||
|
),
|
||||||
|
|
||||||
|
]
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
from django.shortcuts import get_object_or_404, render
|
||||||
|
from django.views.generic.edit import UpdateView, CreateView
|
||||||
|
|
||||||
|
from .models import Entry, Formats
|
||||||
|
# Create your views here.
|
||||||
|
from .tables import EntryTable
|
||||||
|
from .filters import EntryFilter
|
||||||
|
from django_filters.views import FilterView
|
||||||
|
|
||||||
|
from django_tables2 import SingleTableView, SingleTableMixin
|
||||||
|
|
||||||
|
class EntryUpdateView(UpdateView):
|
||||||
|
model = Entry
|
||||||
|
template_name = "oef/entry_update_view.html"
|
||||||
|
fields = ['modality', 'exam_code', 'exam_name', 'questions', 'comments']
|
||||||
|
|
||||||
|
class FormatsCreateView(CreateView):
|
||||||
|
model = Formats
|
||||||
|
template_name_suffix = "_update_form"
|
||||||
|
fields = ['name', 'format', 'inherits']
|
||||||
|
|
||||||
|
class FormatsUpdateView(UpdateView):
|
||||||
|
model = Formats
|
||||||
|
template_name_suffix = "_update_form"
|
||||||
|
fields = ['name', 'format', 'inherits']
|
||||||
|
|
||||||
|
class EntryTableView(SingleTableMixin, FilterView):
|
||||||
|
model = Entry
|
||||||
|
table_class = EntryTable
|
||||||
|
|
||||||
|
template_name = "oef/entry_table.html"
|
||||||
|
|
||||||
|
filterset_class = EntryFilter
|
||||||
|
|
||||||
|
def formats_view(request):
|
||||||
|
formats = Formats.objects.all()
|
||||||
|
return render(request, "oef/formats_view.html", {"formats": formats})
|
||||||
|
|
||||||
|
def formats_apply(request, pk):
|
||||||
|
format = get_object_or_404(Formats, pk=pk)
|
||||||
|
|
||||||
|
search_text = format.get_format()
|
||||||
|
|
||||||
|
entries = Entry.objects.filter(questions__icontains=search_text)
|
||||||
|
|
||||||
|
entry_list = []
|
||||||
|
for entry in entries:
|
||||||
|
entry_list.append((entry, entry.questions.replace(search_text, "")))
|
||||||
|
return render(request, "oef/formats_apply.html", {"format": format, "entry_list": entry_list, "entries": entries})
|
||||||
@@ -51,6 +51,7 @@ INSTALLED_APPS = [
|
|||||||
"atlas",
|
"atlas",
|
||||||
"rcr",
|
"rcr",
|
||||||
"rota",
|
"rota",
|
||||||
|
"oef",
|
||||||
"reversion",
|
"reversion",
|
||||||
"debug_toolbar",
|
"debug_toolbar",
|
||||||
"django_tables2",
|
"django_tables2",
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ urlpatterns = [
|
|||||||
path("atlas/", include("atlas.urls"), name="atlas"),
|
path("atlas/", include("atlas.urls"), name="atlas"),
|
||||||
path("rcr/", include("rcr.urls"), name="rcr"),
|
path("rcr/", include("rcr.urls"), name="rcr"),
|
||||||
path("rota/", include("rota.urls"), name="rota"),
|
path("rota/", include("rota.urls"), name="rota"),
|
||||||
|
path("oef/", include("oef.urls"), name="oef"),
|
||||||
path(
|
path(
|
||||||
"accounts/check_users", views.accounts_check_users, name="accounts_check_users"
|
"accounts/check_users", views.accounts_check_users, name="accounts_check_users"
|
||||||
),
|
),
|
||||||
|
|||||||
Reference in New Issue
Block a user