Merge branch 'master' of ssh://161.35.163.87:/home/django/rad
This commit is contained in:
+4
-11
@@ -205,6 +205,7 @@ class Long(models.Model):
|
|||||||
#"feedback_image": [],
|
#"feedback_image": [],
|
||||||
#"annotations": [str(q.image_annotations)],
|
#"annotations": [str(q.image_annotations)],
|
||||||
"type": "long",
|
"type": "long",
|
||||||
|
"cached": False,
|
||||||
}
|
}
|
||||||
|
|
||||||
return exam_question
|
return exam_question
|
||||||
@@ -393,14 +394,10 @@ class LongSeries(models.Model):
|
|||||||
else:
|
else:
|
||||||
skipcount = skipcount + 1
|
skipcount = skipcount + 1
|
||||||
|
|
||||||
print("skipped, no SliceLocation: {}".format(skipcount))
|
print("skipped, no {}: {}".format(field, skipcount))
|
||||||
|
|
||||||
# ensure they are in the correct order
|
# ensure they are in the correct order
|
||||||
slices = sorted(slices, key=lambda s: s[field].value)
|
slices = sorted(slices, key=lambda s: s[field].value)
|
||||||
#if field == "SliceLocation":
|
|
||||||
# slices = sorted(slices, key=lambda s: s.SliceLocation)
|
|
||||||
#elif field == "InstanceNumber":
|
|
||||||
# slices = sorted(slices, key=lambda s: s.InstanceNumber)
|
|
||||||
|
|
||||||
|
|
||||||
#print(slices)
|
#print(slices)
|
||||||
@@ -632,12 +629,6 @@ class CidUserAnswer(models.Model):
|
|||||||
ans = ans.strip()
|
ans = ans.strip()
|
||||||
|
|
||||||
|
|
||||||
# def get_compare_string(self):
|
|
||||||
# # strip here should be unneccasry (providing clean is now working)
|
|
||||||
# s = self.answer.lower().strip()
|
|
||||||
# s = s.translate(str.maketrans('', '', string.punctuation))
|
|
||||||
# return s
|
|
||||||
|
|
||||||
def is_marked(self):
|
def is_marked(self):
|
||||||
if self.score == "":
|
if self.score == "":
|
||||||
return False
|
return False
|
||||||
@@ -645,4 +636,6 @@ class CidUserAnswer(models.Model):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
def get_answer_score(self):
|
def get_answer_score(self):
|
||||||
|
if self.score == "":
|
||||||
|
return ""
|
||||||
return float(self.score)
|
return float(self.score)
|
||||||
|
|||||||
@@ -4,13 +4,28 @@
|
|||||||
<div class="longs">
|
<div class="longs">
|
||||||
<h2>Exam: {{ exam.name }}</h2>
|
<h2>Exam: {{ exam.name }}</h2>
|
||||||
<h3>Candidate: {{ cid }}</h3>
|
<h3>Candidate: {{ cid }}</h3>
|
||||||
Answers:
|
Scores:
|
||||||
<ul>{% for score in answers_marks %}
|
<ul>{% for score in answers_marks %}
|
||||||
<li class="user-answer-li">Question {{forloop.counter}}</li>
|
<li class="user-answer-li">Question {{forloop.counter}}</li>
|
||||||
<span class="user-answer-score user-answer-score-{{score}}"><pre>{{ans}}</pre> ({{score}})</span>
|
<span class="user-answer-score user-answer-score-{{score}}"><pre>{{ans}}</pre> ({{score}})</span>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
<br /> Total mark: {{ total_score }} / {{max_score}}
|
<br /> Total mark: {{ total_score }} / {{max_score}}
|
||||||
|
<div>
|
||||||
|
<h4>Answers</h4>
|
||||||
|
<ul class="long-answer">{% for a,b,c,d,e in answer_text %}
|
||||||
|
<li class="user-answer-li"><b>Question {{forloop.counter}}</b></li>
|
||||||
|
<ul>
|
||||||
|
<li class="user-answer-li">Observation</br><pre>{{a}}</pre></li>
|
||||||
|
<li class="user-answer-li">Interpretation</br><pre>{{b}}</pre></li>
|
||||||
|
<li class="user-answer-li">Principle Diagnosis</br><pre>{{c}}</pre></li>
|
||||||
|
<li class="user-answer-li">Differential Diagnosis</br><pre>{{d}}</pre></li>
|
||||||
|
<li class="user-answer-li">Management</br><pre>{{e}}</pre></li>
|
||||||
|
</ul>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<a href="{% url 'cid_scores' cid %}">Other exams</a>
|
<a href="{% url 'cid_scores' cid %}">Other exams</a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ This series is not associated with any cases.
|
|||||||
<div>
|
<div>
|
||||||
<a href="{% url 'longs:long_series_order_dicom' pk=series.pk %}" title="orders dicom by slice location">Order dicoms by slice location</a>
|
<a href="{% url 'longs:long_series_order_dicom' pk=series.pk %}" title="orders dicom by slice location">Order dicoms by slice location</a>
|
||||||
<a href="{% url 'longs:long_series_order_dicom_instance' pk=series.pk %}" title="orders dicom by instance number">Order dicoms by instance number</a>
|
<a href="{% url 'longs:long_series_order_dicom_instance' pk=series.pk %}" title="orders dicom by instance number">Order dicoms by instance number</a>
|
||||||
|
<a href="{% url 'longs:long_series_order_dicom_SeriesInstanceUID' pk=series.pk %}" title="orders dicom by instance number">Order dicoms by SeriesInstanceUID</a>
|
||||||
<a href="{% url 'longs:long_series_order_upload_filename' pk=series.pk %}" title="orders dicom by uploaded filename">Order by uploaded filename</a>
|
<a href="{% url 'longs:long_series_order_upload_filename' pk=series.pk %}" title="orders dicom by uploaded filename">Order by uploaded filename</a>
|
||||||
</div>
|
</div>
|
||||||
{% for image in series.images.all %}
|
{% for image in series.images.all %}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ urlpatterns = [
|
|||||||
path("series/<int:pk>", views.long_series_detail, name="long_series_detail"),
|
path("series/<int:pk>", views.long_series_detail, name="long_series_detail"),
|
||||||
path("series/<int:pk>/order_dicom", views.long_series_order_dicom, name="long_series_order_dicom"),
|
path("series/<int:pk>/order_dicom", views.long_series_order_dicom, name="long_series_order_dicom"),
|
||||||
path("series/<int:pk>/order_dicom_instance", views.long_series_order_dicom_instance, name="long_series_order_dicom_instance"),
|
path("series/<int:pk>/order_dicom_instance", views.long_series_order_dicom_instance, name="long_series_order_dicom_instance"),
|
||||||
|
path("series/<int:pk>/order_dicom_SeriesInstanceUID", views.long_series_order_dicom_SeriesInstanceUID, name="long_series_order_dicom_SeriesInstanceUID"),
|
||||||
path("series/<int:pk>/order_upload_filename", views.long_series_order_upload_filename, name="long_series_order_upload_filename"),
|
path("series/<int:pk>/order_upload_filename", views.long_series_order_upload_filename, name="long_series_order_upload_filename"),
|
||||||
path("series/<int:pk>/delete", views.LongSeriesDelete.as_view(), name="long_series_delete"),
|
path("series/<int:pk>/delete", views.LongSeriesDelete.as_view(), name="long_series_delete"),
|
||||||
# path("unchecked/", views.unchecked_list, name="unchecked_list"),
|
# path("unchecked/", views.unchecked_list, name="unchecked_list"),
|
||||||
|
|||||||
@@ -889,21 +889,27 @@ def exam_scores_cid_user(request, pk, sk):
|
|||||||
#answers_and_marks = []
|
#answers_and_marks = []
|
||||||
answers_marks = []
|
answers_marks = []
|
||||||
#answers = []
|
#answers = []
|
||||||
|
answer_text = []
|
||||||
|
|
||||||
for q in questions:
|
for q in questions:
|
||||||
# Get user answer
|
# Get user answer
|
||||||
user_answer = q.cid_user_answers.filter(cid=cid).first()
|
user_answer = q.cid_user_answers.filter(cid=cid).first()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if not user_answer or user_answer is None:
|
if not user_answer or user_answer is None:
|
||||||
# skip if no answer
|
# skip if no answer
|
||||||
#answers_marks.append("")
|
#answers_marks.append("")
|
||||||
#answers.append("")
|
#answers.append("")
|
||||||
answer_score = 4
|
answer_score = 4
|
||||||
#ans = "Not answered"
|
#ans = "Not answered"
|
||||||
|
answer_text.append((("Not answered"),("Not answered"),("Not answered"),("Not answered"),("Not answered")))
|
||||||
else:
|
else:
|
||||||
answer_score = user_answer.get_answer_score()
|
answer_score = user_answer.get_answer_score()
|
||||||
|
|
||||||
|
answer_text.append((user_answer.answer_observations, user_answer.answer_interpretation, user_answer.answer_principle_diagnosis, user_answer.answer_differential_diagnosis, user_answer.answer_management))
|
||||||
|
|
||||||
if not exam.publish_results:
|
if not exam.publish_results:
|
||||||
answer_score = 0
|
answer_score = 0
|
||||||
#answers.append(ans)
|
#answers.append(ans)
|
||||||
@@ -931,6 +937,7 @@ def exam_scores_cid_user(request, pk, sk):
|
|||||||
"answers_marks": answers_marks,
|
"answers_marks": answers_marks,
|
||||||
"total_score": total_score,
|
"total_score": total_score,
|
||||||
"max_score": max_score,
|
"max_score": max_score,
|
||||||
|
"answer_text": answer_text
|
||||||
#"answers_and_marks": answers_and_marks,
|
#"answers_and_marks": answers_and_marks,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -955,6 +962,16 @@ def long_series_order_dicom_instance(request, pk):
|
|||||||
|
|
||||||
return redirect("longs:long_series_detail", pk=pk)
|
return redirect("longs:long_series_detail", pk=pk)
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def long_series_order_dicom_SeriesInstanceUID(request, pk):
|
||||||
|
series = get_object_or_404(LongSeries, pk=pk)
|
||||||
|
try:
|
||||||
|
series.order_by_dicom("SeriesInstanceUID")
|
||||||
|
except:
|
||||||
|
return HttpResponse('<h1>Series does not appear to contain dicoms (or field SeriesInstanceUID)</h1>')
|
||||||
|
|
||||||
|
return redirect("longs:long_series_detail", pk=pk)
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def long_series_order_upload_filename(request, pk):
|
def long_series_order_upload_filename(request, pk):
|
||||||
series = get_object_or_404(LongSeries, pk=pk)
|
series = get_object_or_404(LongSeries, pk=pk)
|
||||||
@@ -986,6 +1003,9 @@ def question_json(request, pk):
|
|||||||
|
|
||||||
cache.set("{}_question_json_{}".format("longs", pk), question_json, 3600)
|
cache.set("{}_question_json_{}".format("longs", pk), question_json, 3600)
|
||||||
|
|
||||||
|
question.recreate_json = False
|
||||||
|
question.save()
|
||||||
|
|
||||||
return JsonResponse(question_json)
|
return JsonResponse(question_json)
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
|
|||||||
+7
-1
@@ -1,5 +1,5 @@
|
|||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from .models import Rapid, RapidImage, Examination, Site, Abnormality, Region, Note, RapidCreationDefault, Answer, Exam
|
from .models import Rapid, RapidImage, Examination, Site, Abnormality, Region, Note, RapidCreationDefault, Answer, Exam, CidUserAnswer
|
||||||
|
|
||||||
import tagulous.admin
|
import tagulous.admin
|
||||||
|
|
||||||
@@ -72,3 +72,9 @@ class RapidAdmin(VersionAdmin):
|
|||||||
admin.site.register(Rapid, RapidAdmin)
|
admin.site.register(Rapid, RapidAdmin)
|
||||||
|
|
||||||
#tagulous.admin.register(Rapid.condition)
|
#tagulous.admin.register(Rapid.condition)
|
||||||
|
|
||||||
|
class CidUserAnswerAdmin(admin.ModelAdmin):
|
||||||
|
exclude = []
|
||||||
|
readonly_fields = ["created", "updated"]
|
||||||
|
|
||||||
|
admin.site.register(CidUserAnswer, CidUserAnswerAdmin)
|
||||||
+12
-8
@@ -71,7 +71,7 @@ class RapidCreationDefaultForm(ModelForm):
|
|||||||
|
|
||||||
class RapidForm(ModelForm):
|
class RapidForm(ModelForm):
|
||||||
|
|
||||||
exams = ModelMultipleChoiceField(required=False, queryset=Exam.objects.all(),widget=FilteredSelectMultiple(verbose_name="Exams", is_stacked=False))
|
# exams = ModelMultipleChoiceField(required=False, queryset=Exam.objects.all(),widget=FilteredSelectMultiple(verbose_name="Exams", is_stacked=False))
|
||||||
class Media:
|
class Media:
|
||||||
# Django also includes a few javascript files necessary
|
# Django also includes a few javascript files necessary
|
||||||
# for the operation of this form element. You need to
|
# for the operation of this form element. You need to
|
||||||
@@ -84,11 +84,6 @@ class RapidForm(ModelForm):
|
|||||||
js = ["jsi18n.js", "tesseract.min.js"]
|
js = ["jsi18n.js", "tesseract.min.js"]
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
ModelForm.__init__(self, *args, **kwargs)
|
|
||||||
super(RapidForm, self).__init__(*args, **kwargs)
|
|
||||||
# self.fields['question'].widget.attrs = {'class': 'question-form', 'rows': 10, 'cols': 100}
|
|
||||||
# self.fields['feedback'].widget.attrs = {'class': 'feedback-form', 'rows': 10, 'cols': 100}
|
|
||||||
|
|
||||||
if kwargs.get("instance"):
|
if kwargs.get("instance"):
|
||||||
# We get the 'initial' keyword argument or initialize it
|
# We get the 'initial' keyword argument or initialize it
|
||||||
# as a dict if it didn't exist.
|
# as a dict if it didn't exist.
|
||||||
@@ -97,6 +92,11 @@ class RapidForm(ModelForm):
|
|||||||
# a list of primary key for the selected data.
|
# a list of primary key for the selected data.
|
||||||
initial["exams"] = [t.pk for t in kwargs["instance"].exams.all()]
|
initial["exams"] = [t.pk for t in kwargs["instance"].exams.all()]
|
||||||
|
|
||||||
|
ModelForm.__init__(self, *args, **kwargs)
|
||||||
|
super(RapidForm, self).__init__(*args, **kwargs)
|
||||||
|
# self.fields['question'].widget.attrs = {'class': 'question-form', 'rows': 10, 'cols': 100}
|
||||||
|
# self.fields['feedback'].widget.attrs = {'class': 'feedback-form', 'rows': 10, 'cols': 100}
|
||||||
|
|
||||||
self.fields["abnormality"] = ModelMultipleChoiceField(
|
self.fields["abnormality"] = ModelMultipleChoiceField(
|
||||||
required=False,
|
required=False,
|
||||||
queryset=Abnormality.objects.all(),
|
queryset=Abnormality.objects.all(),
|
||||||
@@ -117,7 +117,11 @@ class RapidForm(ModelForm):
|
|||||||
self.fields["laterality"] = ChoiceField(
|
self.fields["laterality"] = ChoiceField(
|
||||||
choices=Rapid.LATERALITY_CHOICES, required=False, widget=RadioSelect()
|
choices=Rapid.LATERALITY_CHOICES, required=False, widget=RadioSelect()
|
||||||
)
|
)
|
||||||
|
self.fields["exams"] = ModelMultipleChoiceField(
|
||||||
|
required=False,
|
||||||
|
queryset=Exam.objects.all(),
|
||||||
|
widget=FilteredSelectMultiple(verbose_name="Exams", is_stacked=False),
|
||||||
|
)
|
||||||
|
|
||||||
def save(self, commit=True):
|
def save(self, commit=True):
|
||||||
# Get the unsaved Pizza instance
|
# Get the unsaved Pizza instance
|
||||||
@@ -185,7 +189,7 @@ AnswerFormSet = inlineformset_factory(
|
|||||||
},
|
},
|
||||||
exclude=[],
|
exclude=[],
|
||||||
can_delete=True,
|
can_delete=True,
|
||||||
extra=1,
|
extra=0,
|
||||||
max_num=10,
|
max_num=10,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
+17
-2
@@ -99,7 +99,7 @@ class Answer(models.Model):
|
|||||||
self.answer = self.answer.strip()
|
self.answer = self.answer.strip()
|
||||||
|
|
||||||
s = self.answer.lower()
|
s = self.answer.lower()
|
||||||
s = s.translate(str.maketrans('', '', string.punctuation))
|
s = s.translate(str.maketrans('', '', string.punctuation.replace("#", "")))
|
||||||
|
|
||||||
self.answer_compare = s
|
self.answer_compare = s
|
||||||
|
|
||||||
@@ -352,6 +352,21 @@ class Exam(ExamBase):
|
|||||||
help_text="Exam time limit (in seconds). Default is 2100 secondse (35 minutes)", default=2100
|
help_text="Exam time limit (in seconds). Default is 2100 secondse (35 minutes)", default=2100
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def get_normal_abnormal_breakdown(self):
|
||||||
|
# Inefficient but more extendible
|
||||||
|
questions = self.exam_questions.all()
|
||||||
|
|
||||||
|
normal = []
|
||||||
|
abnormal = []
|
||||||
|
for q in questions:
|
||||||
|
if q.normal:
|
||||||
|
normal.append(q)
|
||||||
|
else:
|
||||||
|
abnormal.append(q)
|
||||||
|
|
||||||
|
return len(normal)
|
||||||
|
|
||||||
|
|
||||||
def get_exam_json(self):
|
def get_exam_json(self):
|
||||||
questions = self.exam_questions.all()
|
questions = self.exam_questions.all()
|
||||||
|
|
||||||
@@ -443,7 +458,7 @@ class CidUserAnswer(models.Model):
|
|||||||
self.answer = self.answer.strip()
|
self.answer = self.answer.strip()
|
||||||
|
|
||||||
s = self.answer.lower()
|
s = self.answer.lower()
|
||||||
s = s.translate(str.maketrans('', '', string.punctuation))
|
s = s.translate(str.maketrans('', '', string.punctuation.replace("#", "")))
|
||||||
|
|
||||||
self.answer_compare = s
|
self.answer_compare = s
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,8 @@
|
|||||||
<div class="rapids">
|
<div class="rapids">
|
||||||
<a href="{% url 'admin:rapids_exam_change' exam.id %}" title="Edit the Exam using the admin interface">Admin Edit</a>
|
<a href="{% url 'admin:rapids_exam_change' exam.id %}" title="Edit the Exam using the admin interface">Admin Edit</a>
|
||||||
<h1>Exam: {{ exam.name }}</h1>
|
<h1>Exam: {{ exam.name }}</h1>
|
||||||
This exam has {{question_number}} questions. Time limit: {{exam.time_limit}} seconds.
|
This exam has {{question_number}} questions. Time limit: {{exam.time_limit}} seconds.<br/>
|
||||||
|
Normal {{ exam.get_normal_abnormal_breakdown }}
|
||||||
|
|
||||||
<div class="parent-help" title="Click to enable / disable the exam">
|
<div class="parent-help" title="Click to enable / disable the exam">
|
||||||
Exam active: <input type="checkbox" id="exam-active-switch" {% if exam.active %}checked{% endif %}> <span class="help-text">[When checked the exam will be available to take in the test system]</span>
|
Exam active: <input type="checkbox" id="exam-active-switch" {% if exam.active %}checked{% endif %}> <span class="help-text">[When checked the exam will be available to take in the test system]</span>
|
||||||
|
|||||||
+18
-5
@@ -355,6 +355,10 @@ class RapidUpdate(LoginRequiredMixin, AuthorOrCheckerRequiredMixin, UpdateView):
|
|||||||
return context
|
return context
|
||||||
|
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
|
# save exam orders (there must be a better way to do this)
|
||||||
|
exam_orders = {}
|
||||||
|
for exam in self.object.exams.all():
|
||||||
|
exam_orders[exam] = list(exam.exam_questions.all())
|
||||||
|
|
||||||
self.object = form.save(commit=False)
|
self.object = form.save(commit=False)
|
||||||
self.object.save()
|
self.object.save()
|
||||||
@@ -371,6 +375,14 @@ class RapidUpdate(LoginRequiredMixin, AuthorOrCheckerRequiredMixin, UpdateView):
|
|||||||
image_formset.save()
|
image_formset.save()
|
||||||
answer_formset.instance = self.object
|
answer_formset.instance = self.object
|
||||||
answer_formset.save()
|
answer_formset.save()
|
||||||
|
|
||||||
|
# restore exam orders
|
||||||
|
for exam in self.object.exams.all():
|
||||||
|
if exam in exam_orders and self.object in exam_orders[exam]:
|
||||||
|
print(exam_orders[exam])
|
||||||
|
exam.exam_questions.set(exam_orders[exam])
|
||||||
|
exam.save()
|
||||||
|
|
||||||
return response
|
return response
|
||||||
else:
|
else:
|
||||||
return super().form_invalid(form)
|
return super().form_invalid(form)
|
||||||
@@ -529,15 +541,14 @@ def loadJsonAnswer(answer):
|
|||||||
|
|
||||||
posted_answer = answer["ans"]
|
posted_answer = answer["ans"]
|
||||||
|
|
||||||
|
# qidn 1 does not hold answer data (but should always arrive prior to 2)
|
||||||
|
if answer["qidn"] == "1":
|
||||||
|
posted_answer = ""
|
||||||
|
|
||||||
# Normal answers are just posted with the answer "Normal"
|
# Normal answers are just posted with the answer "Normal"
|
||||||
normal = False
|
normal = False
|
||||||
if posted_answer == "Normal":
|
if posted_answer == "Normal":
|
||||||
normal = True
|
normal = True
|
||||||
posted_answer = ""
|
|
||||||
# We can ignore the first ab
|
|
||||||
elif answer["qidn"] == "1" and posted_answer == "Abnormal":
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
if not exiting_answers:
|
if not exiting_answers:
|
||||||
ans = CidUserAnswer(answer=posted_answer, normal=normal, cid=answer["cid"])
|
ans = CidUserAnswer(answer=posted_answer, normal=normal, cid=answer["cid"])
|
||||||
@@ -551,7 +562,9 @@ def loadJsonAnswer(answer):
|
|||||||
# Update an existing answer
|
# Update an existing answer
|
||||||
# should never be more than one (famous last words)
|
# should never be more than one (famous last words)
|
||||||
ans = exiting_answers[0]
|
ans = exiting_answers[0]
|
||||||
|
if answer["qidn"] == "1":
|
||||||
ans.normal = normal
|
ans.normal = normal
|
||||||
|
elif answer["qidn"] == "2":
|
||||||
ans.answer = posted_answer
|
ans.answer = posted_answer
|
||||||
ans.full_clean()
|
ans.full_clean()
|
||||||
ans.save()
|
ans.save()
|
||||||
|
|||||||
@@ -6,7 +6,9 @@
|
|||||||
<a href="{% url 'anatomy:index'%}">Anatomy</a>
|
<a href="{% url 'anatomy:index'%}">Anatomy</a>
|
||||||
<a href="{% url 'physics:index'%}">Physics</a>
|
<a href="{% url 'physics:index'%}">Physics</a>
|
||||||
<a href="{% url 'rapids:index'%}">Rapids</a>
|
<a href="{% url 'rapids:index'%}">Rapids</a>
|
||||||
|
{% if not request.user.is_authenticated %}
|
||||||
<a href="{% url 'login'%}">Log in</a>
|
<a href="{% url 'login'%}">Log in</a>
|
||||||
|
{% endif %}
|
||||||
{% if request.user.is_staff %}<a href="{% url 'admin:index'%}">Admin</a>{% endif %}
|
{% if request.user.is_staff %}<a href="{% url 'admin:index'%}">Admin</a>{% endif %}
|
||||||
<a href="{% url 'password_reset'%}">Reset password</a>
|
<a href="{% url 'password_reset'%}">Reset password</a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user