Improvements to user management
This commit is contained in:
+4
-1
@@ -15,13 +15,15 @@ from .models import (
|
||||
CidUserExam,
|
||||
UserGrades,
|
||||
UserProfile,
|
||||
Supervisor,
|
||||
Site
|
||||
)
|
||||
|
||||
# from .models import Examination, Sign, Site, Condition
|
||||
|
||||
admin.site.register(Examination)
|
||||
admin.site.register(Sign)
|
||||
# admin.site.register(Site)
|
||||
admin.site.register(Site)
|
||||
admin.site.register(Condition)
|
||||
admin.site.register(Plane)
|
||||
admin.site.register(Contrast)
|
||||
@@ -32,3 +34,4 @@ admin.site.register(CidUserExam)
|
||||
admin.site.register(CidUserGroup)
|
||||
admin.site.register(UserProfile)
|
||||
admin.site.register(UserGrades)
|
||||
admin.site.register(Supervisor)
|
||||
|
||||
+21
-2
@@ -6,12 +6,15 @@ from django.forms import (
|
||||
ChoiceField,
|
||||
CharField,
|
||||
HiddenInput,
|
||||
EmailField,
|
||||
IntegerField
|
||||
|
||||
)
|
||||
from django.forms import inlineformset_factory
|
||||
from atlas.models import CaseCollection
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
from generic.models import CidUser, CidUserGroup, Examination, QuestionNote, UserProfile, UserUserGroup
|
||||
from generic.models import CidUser, CidUserGroup, Examination, QuestionNote, Supervisor, UserProfile, UserUserGroup
|
||||
|
||||
from django.contrib.admin.widgets import FilteredSelectMultiple
|
||||
from django.forms.widgets import RadioSelect, TextInput, Textarea
|
||||
@@ -258,4 +261,20 @@ class UserUserGroupForm(ModelForm):
|
||||
#class UserProfileForm(ModelForm):
|
||||
# class Meta:
|
||||
# model = UserProfile
|
||||
# fields = ["supervisor_name", "supervisor_email", "registration_number", "peninsula_trainee"]
|
||||
# fields = ["supervisor_name", "supervisor_email", "registration_number", "peninsula_trainee"]
|
||||
|
||||
class UserUserForm(Form):
|
||||
username = EmailField(required=True, help_text="Username / email should be the same. Ideally this should be an nhs email.")
|
||||
first_name = CharField(max_length=255, required=True)
|
||||
last_name = CharField(max_length=255, required=True)
|
||||
grade = IntegerField(min_value=1, max_value=6, required=False)
|
||||
supervisor = CharField(max_length=255, required=False) # Needs to be a user/object ref
|
||||
#
|
||||
# class Meta:
|
||||
#
|
||||
# fields = ("username", "first_name", "last_name")
|
||||
|
||||
class SupervisorForm(ModelForm):
|
||||
class Meta:
|
||||
model = Supervisor
|
||||
exclude = ("",)
|
||||
@@ -0,0 +1,26 @@
|
||||
# Generated by Django 3.2.13 on 2022-11-14 09:44
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('generic', '0036_ciduserexam_results_emailed_status'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Supervisor',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('email', models.EmailField(blank=True, max_length=254)),
|
||||
('name', models.CharField(blank=True, max_length=255)),
|
||||
('active', models.BooleanField(default=True)),
|
||||
('user', models.OneToOneField(blank=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,21 @@
|
||||
# Generated by Django 3.2.13 on 2022-11-14 13:18
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('generic', '0037_supervisor'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='supervisor',
|
||||
name='user',
|
||||
field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,21 @@
|
||||
# Generated by Django 3.2.13 on 2022-11-14 13:19
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('generic', '0038_alter_supervisor_user'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='supervisor',
|
||||
name='user',
|
||||
field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 3.2.13 on 2022-11-14 13:23
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('generic', '0039_alter_supervisor_user'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='supervisor',
|
||||
name='email',
|
||||
field=models.EmailField(blank=True, max_length=254, unique=True),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,54 @@
|
||||
# Generated by Django 3.2.13 on 2022-11-14 13:55
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('generic', '0040_alter_supervisor_email'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='site',
|
||||
name='initials',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='site',
|
||||
name='site',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='site',
|
||||
name='full_name',
|
||||
field=models.CharField(blank=True, help_text='Name of the site', max_length=255),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='site',
|
||||
name='short_code',
|
||||
field=models.CharField(blank=True, help_text='Shortcode/name of the site', max_length=255),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='supervisor',
|
||||
name='site',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='generic.site'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='supervisor',
|
||||
name='email',
|
||||
field=models.EmailField(blank=True, help_text='The (nhs.net) email address of the supervisor', max_length=254, unique=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='supervisor',
|
||||
name='name',
|
||||
field=models.CharField(blank=True, help_text='Name of the supervisor', max_length=255),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='supervisor',
|
||||
name='user',
|
||||
field=models.OneToOneField(blank=True, help_text='If the supervisor has an account on the test system that can be associated here', null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,19 @@
|
||||
# Generated by Django 3.2.13 on 2022-11-14 14:01
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('generic', '0041_auto_20221114_1355'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='userprofile',
|
||||
name='supervisor',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='generic.supervisor'),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,19 @@
|
||||
# Generated by Django 3.2.13 on 2022-11-14 14:07
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('generic', '0042_userprofile_supervisor'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='userprofile',
|
||||
name='supervisor',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='trainee', to='generic.supervisor'),
|
||||
),
|
||||
]
|
||||
+29
-4
@@ -56,11 +56,13 @@ class Examination(models.Model):
|
||||
|
||||
|
||||
class Site(models.Model):
|
||||
site = models.CharField(max_length=200)
|
||||
initials = models.CharField(max_length=200)
|
||||
"""Model to hold site details"""
|
||||
full_name = models.CharField(max_length=255, blank=True, help_text="Name of the site")
|
||||
short_code = models.CharField(max_length=255, blank=True, help_text="Shortcode/name of the site")
|
||||
|
||||
|
||||
def __str__(self):
|
||||
return self.site
|
||||
return self.short_code
|
||||
|
||||
|
||||
class Condition(tagulous.models.TagModel):
|
||||
@@ -667,6 +669,7 @@ class UserProfile(models.Model):
|
||||
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
|
||||
supervisor_email = models.EmailField(blank=True)
|
||||
supervisor_name = models.CharField(max_length=100, blank=True)
|
||||
supervisor = models.ForeignKey("Supervisor", on_delete=models.SET_NULL, blank=True, null=True, related_name="trainee")
|
||||
registration_number = models.CharField(max_length=25, blank=True)
|
||||
grade = models.ForeignKey(UserGrades, null=True, blank=True, help_text="User grade", on_delete=models.CASCADE)
|
||||
peninsula_trainee = models.BooleanField(default=False)
|
||||
@@ -675,7 +678,28 @@ class UserProfile(models.Model):
|
||||
def getusername(self):
|
||||
return self.user.username
|
||||
|
||||
def __str__(self):
|
||||
return f"Userprofile {self.user}"
|
||||
|
||||
username = property(getusername)
|
||||
|
||||
class Supervisor(models.Model):
|
||||
"""Model to hold individual supervisor details (email and name)
|
||||
|
||||
This can be linked with a user account.
|
||||
"""
|
||||
email = models.EmailField(blank=True, unique=True, help_text="The (nhs.net) email address of the supervisor")
|
||||
name = models.CharField(max_length=255, blank=True, help_text="Name of the supervisor")
|
||||
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True, blank=True, help_text="If the supervisor has an account on the test system that can be associated here")
|
||||
site = models.ForeignKey("Site", on_delete=models.SET_NULL, null=True, blank=True)
|
||||
active = models.BooleanField(default=True)
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"{self.name} ({self.email})"
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse('generic:supervisor_detail', kwargs={'pk': self.pk})
|
||||
|
||||
|
||||
|
||||
@receiver(post_save, sender=User)
|
||||
@@ -685,4 +709,5 @@ def create_user_profile(sender, instance, created, **kwargs):
|
||||
|
||||
@receiver(post_save, sender=User)
|
||||
def save_user_profile(sender, instance, **kwargs):
|
||||
instance.userprofile.save()
|
||||
instance.userprofile.save()
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
<a href="{% url 'generic:cid_group_view' %}">Cid Groups</a> /
|
||||
<a href="{% url 'generic:user_group_view' %}">User Groups</a> /
|
||||
<a href="{% url 'accounts_list' %}">Manage Users</a> /
|
||||
<a href="{% url 'generic:supervisor' %}">Manage Supervisors</a>
|
||||
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
@@ -91,13 +91,13 @@
|
||||
<summary>Email results</summary>
|
||||
User results emailed: {{exam.exam_results_emailed|default:"Never"}}<br/>
|
||||
<button id="email-results-button"
|
||||
title="Email results to users and their supervisors"
|
||||
title="Email results to users and their supervisor"
|
||||
hx-get="{% url exam.app_name|add:':exam_report_email' exam_id=exam.pk %}"
|
||||
hx-target="#user-details"
|
||||
hx-confirm="This will email results, please make sure scores have been refreshed before continuing"
|
||||
hx-prompt="Please enter an additional email to send to (user and supervisor will automatically be used if available) if required"
|
||||
>Email user results</button>
|
||||
<button id="email-unsent-results-button" title="Email results to users and their supervisors"
|
||||
<button id="email-unsent-results-button" title="Email results to users and their supervisor"
|
||||
hx-get="{% url exam.app_name|add:':exam_report_email_unsent' exam_id=exam.pk %}"
|
||||
hx-target="#user-details"
|
||||
hx-confirm="This will email results, please make sure scores have been refreshed before continuing"
|
||||
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
{% extends 'generic/base.html' %}
|
||||
|
||||
{% block navigation %}
|
||||
{{block.super}}
|
||||
<br/>
|
||||
Supervisors: <a href="{% url 'generic:supervisor' %}">View all</a>
|
||||
<a href="{% url 'generic:supervisor_create' %}">Create new</a>
|
||||
{% endblock %}
|
||||
|
||||
{% block js %}
|
||||
|
||||
{% endblock %}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
{% extends 'generic/supervisor_base.html' %}
|
||||
|
||||
{% block content %}
|
||||
<h2>Supervisor: {{object.name}}</h2>
|
||||
{{object.email}}
|
||||
|
||||
<br/>User account: {{object.user}}
|
||||
<br/>Site: {{object.site}}
|
||||
<br/>Trainee(s): {% for trainee in object.trainee.all %}
|
||||
<a href="{% url 'account_profile' trainee.user.username %}">{{trainee.user}}
|
||||
|
||||
{% endfor %}
|
||||
|
||||
|
||||
<div>
|
||||
<a href="{% url 'generic:supervisor_edit' pk=object.pk %}"> Edit</a>
|
||||
<a href="{% url 'generic:supervisor_delete' pk=object.pk %}"> Delete</a>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block js %}
|
||||
|
||||
<style>
|
||||
td, th { padding-left: 10px }
|
||||
</style>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,32 @@
|
||||
{% extends "generic/supervisor_base.html" %}
|
||||
<!-- {% load static from static %} -->
|
||||
|
||||
{% block css %}
|
||||
<style>
|
||||
</style>
|
||||
|
||||
{% endblock %}
|
||||
{% block js %}
|
||||
<!--<script type="text/javascript" src="/admin/jsi18n/"></script>-->
|
||||
{{form.media}}
|
||||
|
||||
<script type="text/javascript">
|
||||
</script>
|
||||
|
||||
<!-- {{ form.media }} -->
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<h2>Edit Supervisor / {{object.cid}}</h2>
|
||||
Use this form to create / edit a supervisor
|
||||
{% if errors %}
|
||||
<div class="alert alert-info" role="alert">{{errors}}</a></div>
|
||||
{% endif %}
|
||||
<form action="" method="post" enctype="multipart/form-data" id="condition-form">
|
||||
{% csrf_token %}
|
||||
|
||||
<table>
|
||||
{{ form.as_table }}
|
||||
</table>
|
||||
<input type="submit" class="submit-button" value="Submit" name="submit">
|
||||
</form>
|
||||
{% endblock %}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
{% extends 'generic/supervisor_base.html' %}
|
||||
{% block content %}
|
||||
|
||||
<h2>Supervisors</h2>
|
||||
|
||||
<ul>
|
||||
{% for supervisor in object_list %}
|
||||
<li><a href="{% url 'generic:supervisor_detail' pk=supervisor.pk %}">Supervisor: {{supervisor.name}}</a>
|
||||
<br/>{{supervisor.email}}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block js %}
|
||||
<style>
|
||||
td, th { padding-left: 10px }
|
||||
</style>
|
||||
{% endblock %}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
{% extends "generic/base.html" %}
|
||||
<!-- {% load static from static %} -->
|
||||
|
||||
{% block css %}
|
||||
{% endblock %}
|
||||
{% block js %}
|
||||
<!--<script type="text/javascript" src="/admin/jsi18n/"></script>-->
|
||||
{{form.media}}
|
||||
|
||||
<script type="text/javascript">
|
||||
</script>
|
||||
|
||||
<!-- {{ form.media }} -->
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<h2>Edit User / {{ciduser.cid}}</h2>
|
||||
Use this form to create a user.
|
||||
{% if errors %}
|
||||
<div class="alert alert-info" role="alert">{{errors}}</a></div>
|
||||
{% endif %}
|
||||
<form action="" method="post" enctype="multipart/form-data" id="condition-form">
|
||||
{% csrf_token %}
|
||||
|
||||
<table>
|
||||
{{ form.as_table }}
|
||||
</table>
|
||||
<input type="submit" class="submit-button" value="Submit" name="submit">
|
||||
</form>
|
||||
{% endblock %}
|
||||
@@ -92,6 +92,11 @@ urlpatterns = [
|
||||
),
|
||||
path("cids/create", views.manage_cid_users, name="manage_cid_users"),
|
||||
path("cids/create/email", views.create_cid_email, name="create_cid_email"),
|
||||
path("supervisor", views.SupervisorList.as_view(), name="supervisor"),
|
||||
path("supervisor/<int:pk>", views.SupervisorDetail.as_view(), name="supervisor_detail"),
|
||||
path("supervisor/<int:pk>/edit", views.SupervisorUpdate.as_view(), name="supervisor_edit"),
|
||||
path("supervisor/create", views.SupervisorCreate.as_view(), name="supervisor_create"),
|
||||
path("supervisor/<int:pk>/delete", views.SupervisorDelete.as_view(), name="supervisor_delete"),
|
||||
]
|
||||
|
||||
|
||||
|
||||
+87
-2
@@ -1,5 +1,6 @@
|
||||
from collections import defaultdict, Counter
|
||||
from pathlib import Path
|
||||
import secrets
|
||||
import statistics
|
||||
import threading
|
||||
from dal import autocomplete
|
||||
@@ -35,6 +36,8 @@ import urllib
|
||||
|
||||
from django.views import View
|
||||
from django.views.generic.edit import CreateView, UpdateView, DeleteView
|
||||
from django.views.generic.list import ListView
|
||||
from django.views.generic.detail import DetailView
|
||||
from django_filters.views import FilterView
|
||||
from django_filters import FilterSet, OrderingFilter
|
||||
from django_tables2.views import SingleTableMixin
|
||||
@@ -49,10 +52,12 @@ from .forms import (
|
||||
CidUserForm,
|
||||
ExaminationForm,
|
||||
CidUserGroupForm,
|
||||
SupervisorForm,
|
||||
UserUserForm,
|
||||
UserUserGroupForm,
|
||||
)
|
||||
|
||||
from .models import CidUser, CidUserGroup, Examination, QuestionNote, UserUserGroup, get_next_cid
|
||||
from .models import CidUser, CidUserGroup, Examination, QuestionNote, Supervisor, UserGrades, UserProfile, UserUserGroup, get_next_cid
|
||||
|
||||
from rapids.models import Rapid as RapidQuestion
|
||||
from rapids.models import Exam as RapidExam
|
||||
@@ -2500,4 +2505,84 @@ class ExamDeleteBase(RevisionMixin, DeleteView):
|
||||
|
||||
|
||||
def exam_inactive(request, context):
|
||||
return render(request, "exam_inactive.html", context)
|
||||
return render(request, "exam_inactive.html", context)
|
||||
|
||||
#class UserUserCreate(CidManagerRequiredMixin, CreateView):
|
||||
# model = User
|
||||
# form_class = UserUserForm
|
||||
# template_name: str = "generic/user_creation_form.html"
|
||||
#
|
||||
# success_url = reverse_lazy("accounts_list")
|
||||
|
||||
def create_user(request, context=None):
|
||||
# if this is a POST request we need to process the form data
|
||||
if request.method == 'POST':
|
||||
# create a form instance and populate it with data from the request:
|
||||
form = UserUserForm(request.POST)
|
||||
# check whether it's valid:
|
||||
if form.is_valid():
|
||||
try:
|
||||
user_dict = {
|
||||
"username": request.POST["username"],
|
||||
"first_name": request.POST["first_name"],
|
||||
"last_name": request.POST["last_name"],
|
||||
"email": request.POST["username"],
|
||||
"password": secrets.token_hex(nbytes=16)
|
||||
}
|
||||
|
||||
|
||||
new_user = User.objects.create_user(**user_dict)
|
||||
except Exception as error:
|
||||
errors = f"Unable to create account: {error}"
|
||||
return render(request, 'generic/user_creation_form.html', {'form': form, "errors": errors})
|
||||
|
||||
try:
|
||||
|
||||
user_profile = UserProfile.objects.get(user=new_user)
|
||||
user_profile.peninsula_trainee = True
|
||||
#if "supervisor_email" in user:
|
||||
# user_profile.supervisor_email = user["supervisor_email"]
|
||||
#if "supervisor_name" in user:
|
||||
# user_profile.supervisor_name = user["supervisor_name"]
|
||||
|
||||
|
||||
if request.POST["grade"]:
|
||||
grade = UserGrades.objects.get(name=f"ST{ request.POST['grade'] }")
|
||||
user_profile.grade = grade
|
||||
|
||||
user_profile.save()
|
||||
|
||||
except Exception as error:
|
||||
errors = f"Unable to create account profile {error}"
|
||||
return render(request, 'generic/user_creation_form.html', {'form': form, "errors": errors})
|
||||
|
||||
return HttpResponseRedirect(reverse_lazy("accounts_list"))
|
||||
return reverse_lazy("accounts_list")
|
||||
|
||||
# if a GET (or any other method) we'll create a blank form
|
||||
else:
|
||||
form = UserUserForm()
|
||||
|
||||
return render(request, 'generic/user_creation_form.html', {'form': form})
|
||||
|
||||
class SupervisorDetail(CidManagerRequiredMixin, DetailView):
|
||||
model = Supervisor
|
||||
|
||||
|
||||
class SupervisorDelete(CidManagerRequiredMixin, DeleteView):
|
||||
model = Supervisor
|
||||
template_name: str = "confirm_delete.html"
|
||||
success_url = reverse_lazy("generic:supervisor")
|
||||
|
||||
class SupervisorUpdate(CidManagerRequiredMixin, UpdateView):
|
||||
model = Supervisor
|
||||
form_class = SupervisorForm
|
||||
#success_url = reverse_lazy("generic:supervisor_detail", kwargs={'pk': self.pk})
|
||||
|
||||
class SupervisorCreate(CidManagerRequiredMixin, CreateView):
|
||||
model = Supervisor
|
||||
form_class = SupervisorForm
|
||||
#success_url = reverse_lazy("generic:supervisor_detail")
|
||||
|
||||
class SupervisorList(CidManagerRequiredMixin, ListView):
|
||||
model = Supervisor
|
||||
Reference in New Issue
Block a user