Integrated models for teams & members page
This commit is contained in:
parent
8394de0dcb
commit
8afd3fa905
@ -19,9 +19,9 @@ class PegAdmin(admin.ModelAdmin):
|
|||||||
class MemberAdmin(admin.ModelAdmin):
|
class MemberAdmin(admin.ModelAdmin):
|
||||||
"""Admin model for the Member model."""
|
"""Admin model for the Member model."""
|
||||||
|
|
||||||
list_display = ("first_name", "last_name", "user", "team", "peg")
|
list_display = ("first_name", "last_name", "team")
|
||||||
search_fields = ("first_name", "last_name", "user", "team", "peg")
|
search_fields = ("first_name", "last_name", "team")
|
||||||
list_filter = ("team", "peg")
|
list_filter = ("team",)
|
||||||
|
|
||||||
|
|
||||||
@admin.register(Team)
|
@admin.register(Team)
|
||||||
|
0
src/mainapp/management/__init__.py
Normal file
0
src/mainapp/management/__init__.py
Normal file
0
src/mainapp/management/commands/__init__.py
Normal file
0
src/mainapp/management/commands/__init__.py
Normal file
68
src/mainapp/management/commands/create_members_fixture.py
Normal file
68
src/mainapp/management/commands/create_members_fixture.py
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
import random
|
||||||
|
import names
|
||||||
|
import json
|
||||||
|
from django.core.management.base import BaseCommand
|
||||||
|
from mainapp.models import Member, Team
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
help = "Creates a fixture with randomly generated Member objects"
|
||||||
|
|
||||||
|
def add_arguments(self, parser):
|
||||||
|
parser.add_argument("num_members", type=int)
|
||||||
|
|
||||||
|
def handle(self, *args, **options):
|
||||||
|
num_members = options["num_members"]
|
||||||
|
teams = Team.objects.all()
|
||||||
|
if not teams:
|
||||||
|
print("No teams found. Please create some teams first.")
|
||||||
|
return
|
||||||
|
|
||||||
|
members = []
|
||||||
|
for team in teams:
|
||||||
|
for _ in range(num_members):
|
||||||
|
first_name = names.get_first_name()
|
||||||
|
last_name = names.get_last_name()
|
||||||
|
member = Member(first_name=first_name, last_name=last_name, team=team)
|
||||||
|
members.append(member)
|
||||||
|
|
||||||
|
Member.objects.bulk_create(members)
|
||||||
|
|
||||||
|
self.stdout.write(self.style.SUCCESS(f"Created {num_members} members."))
|
||||||
|
|
||||||
|
|
||||||
|
# create a team fixture file
|
||||||
|
teams_fixture = []
|
||||||
|
for team in teams:
|
||||||
|
team_fixture = {
|
||||||
|
"model": "mainapp.team",
|
||||||
|
"pk": team.pk,
|
||||||
|
"fields": {
|
||||||
|
"team_number": team.team_number,
|
||||||
|
"section": team.section_id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
teams_fixture.append(team_fixture)
|
||||||
|
|
||||||
|
with open("src/mainapp/fixtures/teams_fixture.json", "w") as f:
|
||||||
|
f.write(json.dumps(teams_fixture, indent=2))
|
||||||
|
self.stdout.write(self.style.SUCCESS("Created teams_fixture.json."))
|
||||||
|
|
||||||
|
|
||||||
|
# create a members fixture file
|
||||||
|
members_fixture = []
|
||||||
|
for member in members:
|
||||||
|
member_fixture = {
|
||||||
|
"model": "mainapp.member",
|
||||||
|
"pk": member.pk,
|
||||||
|
"fields": {
|
||||||
|
"first_name": member.first_name,
|
||||||
|
"last_name": member.last_name,
|
||||||
|
"team": member.team_id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
members_fixture.append(member_fixture)
|
||||||
|
|
||||||
|
with open("src/mainapp/fixtures/members_fixture.json", "w") as f:
|
||||||
|
f.write(json.dumps(members_fixture, indent=2))
|
||||||
|
self.stdout.write(self.style.SUCCESS("Created members_fixture.json."))
|
37
src/mainapp/management/commands/create_teams_fixture.py
Normal file
37
src/mainapp/management/commands/create_teams_fixture.py
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
from django.core.management.base import BaseCommand
|
||||||
|
from mainapp.models import Team
|
||||||
|
import random
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
help = "Creates a fixture file for Team objects"
|
||||||
|
|
||||||
|
def add_arguments(self, parser):
|
||||||
|
parser.add_argument("num_teams", type=int, help="Number of teams to create")
|
||||||
|
|
||||||
|
def handle(self, *args, **options):
|
||||||
|
num_teams = options["num_teams"]
|
||||||
|
|
||||||
|
teams = []
|
||||||
|
for i in range(num_teams):
|
||||||
|
team = Team.objects.create()
|
||||||
|
teams.append(team)
|
||||||
|
|
||||||
|
for team in teams:
|
||||||
|
self.stdout.write(self.style.SUCCESS(f"Created team {team.team_number}"))
|
||||||
|
|
||||||
|
filename = f"src/mainapp/fixtures/teams_{num_teams}.json"
|
||||||
|
with open(filename, "w") as f:
|
||||||
|
self.stdout.write(f"Writing fixture to {filename}")
|
||||||
|
f.write("[\n")
|
||||||
|
for i, team in enumerate(teams):
|
||||||
|
f.write(" {\n")
|
||||||
|
f.write(f' "model": "mainapp.team",\n')
|
||||||
|
f.write(f' "pk": {team.team_number},\n')
|
||||||
|
f.write(' "fields": {}\n')
|
||||||
|
f.write(" }")
|
||||||
|
if i < len(teams) - 1:
|
||||||
|
f.write(",")
|
||||||
|
f.write("\n")
|
||||||
|
f.write("]\n")
|
||||||
|
|
||||||
|
self.stdout.write(self.style.SUCCESS("Fixture created successfully"))
|
@ -1,6 +1,5 @@
|
|||||||
# Generated by Django 4.1.5 on 2023-01-26 14:24
|
# Generated by Django 4.1.5 on 2023-05-06 15:53
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
import mainapp.models
|
import mainapp.models
|
||||||
@ -11,7 +10,6 @@ class Migration(migrations.Migration):
|
|||||||
initial = True
|
initial = True
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
@ -40,8 +38,7 @@ class Migration(migrations.Migration):
|
|||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
('first_name', models.CharField(max_length=255)),
|
('first_name', models.CharField(max_length=255)),
|
||||||
('last_name', models.CharField(max_length=255)),
|
('last_name', models.CharField(max_length=255)),
|
||||||
('team', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='mainapp.team')),
|
('team', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='mainapp.team', validators=[mainapp.models.validate_team_size])),
|
||||||
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
@ -1,25 +0,0 @@
|
|||||||
# Generated by Django 4.1.5 on 2023-01-26 14:31
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
import django.db.models.deletion
|
|
||||||
import mainapp.models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('mainapp', '0001_initial'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='member',
|
|
||||||
name='peg',
|
|
||||||
field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='mainapp.peg'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='member',
|
|
||||||
name='team',
|
|
||||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='mainapp.team', validators=[mainapp.models.validate_team_size]),
|
|
||||||
),
|
|
||||||
]
|
|
@ -49,13 +49,16 @@ class Member(models.Model):
|
|||||||
|
|
||||||
first_name = models.CharField(max_length=255)
|
first_name = models.CharField(max_length=255)
|
||||||
last_name = models.CharField(max_length=255)
|
last_name = models.CharField(max_length=255)
|
||||||
user = models.OneToOneField("auth.User", on_delete=models.CASCADE)
|
team = models.ForeignKey("Team", on_delete=models.SET_NULL, null=True, blank=True, validators=(validate_team_size,), related_name='members')
|
||||||
team = models.ForeignKey("Team", on_delete=models.SET_NULL, null=True, blank=True, validators=(validate_team_size,))
|
# peg = models.OneToOneField("Peg", on_delete=models.SET_NULL, null=True, blank=True)
|
||||||
peg = models.OneToOneField("Peg", on_delete=models.SET_NULL, null=True, blank=True)
|
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"{self.first_name} {self.last_name} (team {self.team.team_number}))"
|
return f"{self.first_name} {self.last_name} (team {self.team.team_number}))"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def fullname(self) -> str:
|
||||||
|
return f"{self.first_name} {self.last_name}"
|
||||||
|
|
||||||
|
|
||||||
class Team(models.Model):
|
class Team(models.Model):
|
||||||
"""Represents a team"""
|
"""Represents a team"""
|
||||||
@ -66,6 +69,10 @@ class Team(models.Model):
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"Team {self.team_number}"
|
return f"Team {self.team_number}"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def members(self) -> list[Member]:
|
||||||
|
Member.objects.filter(team=self)
|
||||||
|
|
||||||
|
|
||||||
def validate_section_character(value):
|
def validate_section_character(value):
|
||||||
"""Validates the section character"""
|
"""Validates the section character"""
|
||||||
|
@ -62,7 +62,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
||||||
<button type="button" class="btn btn-primary">Save Changes</button>
|
<button type="button" class="btn btn-primary" id="saveEditModal">Save Changes</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -101,7 +101,6 @@
|
|||||||
*
|
*
|
||||||
* **/
|
* **/
|
||||||
function isEmptyOrSpaces(string) {
|
function isEmptyOrSpaces(string) {
|
||||||
console.log(string === null || string.match(/^ *$/) !== null);
|
|
||||||
return string === null || string.match(/^ *$/) !== null;
|
return string === null || string.match(/^ *$/) !== null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,43 +108,53 @@
|
|||||||
$("#teamsContainer").html(""); // Clear the previous listed teams
|
$("#teamsContainer").html(""); // Clear the previous listed teams
|
||||||
|
|
||||||
if (teams.length < 1) {
|
if (teams.length < 1) {
|
||||||
$("#teamsNotFound").show()
|
$("#teamsNotFound").show();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Iterate over and add each team
|
// Iterate over and add each team
|
||||||
teams.forEach((team, index) => {
|
teams.forEach((team, index) => {
|
||||||
|
$("#teamsContainer").append(
|
||||||
const teamColumn = $(
|
`<div class='col-12 col-md-6 col-xl-4 mb-4'>
|
||||||
`<div class='col-12 col-md-6 col-xl-4 mb-4 team-column'>
|
<div
|
||||||
<div class='p-4 bg-body-tertiary rounded h-100 fluid-hover-zoom shadow-sm shadow-on-hover'>
|
class='team p-4 bg-body-tertiary rounded h-100 fluid-hover-zoom shadow-sm shadow-on-hover'
|
||||||
<h4>${team.identifier}</h4>
|
data-number='${team.team_number}'
|
||||||
|
>
|
||||||
|
<h4>${team.team_number}</h4>
|
||||||
<ul class='list-unstyled ul-cols-2 team-members'>
|
<ul class='list-unstyled ul-cols-2 team-members'>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>`
|
</div>`
|
||||||
);
|
);
|
||||||
|
|
||||||
teamColumn.css("opacity", 1);
|
// Whilimage.pnge we have the team, iterate over and add it's members
|
||||||
$("#teamsContainer").append(teamColumn);
|
|
||||||
|
|
||||||
// While we have the team, iterate over and add it's members
|
|
||||||
team.members.forEach((member) => {
|
team.members.forEach((member) => {
|
||||||
|
const fullname = member.first + " " + member.last;
|
||||||
|
|
||||||
$("#teamsContainer").find(".team-members").last().append(
|
$("#teamsContainer").find(".team-members").last().append(
|
||||||
`<li>
|
`<li>
|
||||||
<span
|
<span
|
||||||
type='button'
|
type='button'
|
||||||
class='team-member'
|
class='team-member'
|
||||||
onclick='javascript:openEditModal("${member.name}");'
|
data-first='${member.first}'
|
||||||
>
|
data-last='${member.last}'
|
||||||
${member.name}
|
data-member-id='${member.id}'
|
||||||
|
data-team-number='${member.team}'
|
||||||
|
>
|
||||||
|
${fullname}
|
||||||
</span>
|
</span>
|
||||||
</li>`
|
</li>`
|
||||||
)
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Highlight all instances where the text matches the search critera
|
||||||
if (!isEmptyOrSpaces(highlightText)) {
|
if (!isEmptyOrSpaces(highlightText)) {
|
||||||
$("#teamsContainer").find(`.team-member:icontains('${highlightText}')`).addClass("border-bottom text-primary fw-bold");
|
$("#teamsContainer").find(`.team-member:icontains('${highlightText}')`).addClass("border-bottom text-primary fw-bold");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$(".team-member").on("click", function() {
|
||||||
|
openEditModal($(this).data("member-id"));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function fetchAndLoadTeams(search="") {
|
function fetchAndLoadTeams(search="") {
|
||||||
@ -158,7 +167,7 @@
|
|||||||
},
|
},
|
||||||
error: (xhr, textStatus, errorThrown) => { alert(errorThrown); },
|
error: (xhr, textStatus, errorThrown) => { alert(errorThrown); },
|
||||||
success: (result) => {
|
success: (result) => {
|
||||||
teamsLoading(false)
|
teamsLoading(false);
|
||||||
loadTeams(result.teams, search);
|
loadTeams(result.teams, search);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -177,17 +186,62 @@
|
|||||||
$("#teamsLoadingSpinner").hide();
|
$("#teamsLoadingSpinner").hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
function openEditModal(name) {
|
function openEditModal(memberId) {
|
||||||
|
|
||||||
var [first, last] = name.split(" ");
|
// Member data
|
||||||
var teamIdentifier = $(`.team-member:contains('${name}')`).parent().parent().parent().find("h4").text();
|
const member = $(`.team-member[data-member-id='${memberId}']`);
|
||||||
|
const first = member.data("first");
|
||||||
|
const last = member.data("last");
|
||||||
|
const teamNumber = member.data("team-number");
|
||||||
|
|
||||||
$("#editMemberName").text(name);
|
// Load teams as options
|
||||||
|
$("#editMemberTeam").html("");
|
||||||
|
$(".team").map(function() {
|
||||||
|
return $(this).data("number");
|
||||||
|
}).get().forEach((team) => {
|
||||||
|
$("#editMemberTeam").append($(`<option value='${team}'>${team}</option>`));
|
||||||
|
});
|
||||||
|
|
||||||
|
// Load data to form
|
||||||
|
$("#editMemberName").text(first + " " + last);
|
||||||
$("#editMemberFirstName").val(first);
|
$("#editMemberFirstName").val(first);
|
||||||
$("#editMemberLastName").val(last);
|
$("#editMemberLastName").val(last);
|
||||||
$("#editMemberTeam").val(teamIdentifier)
|
$("#editMemberTeam").val(teamNumber);
|
||||||
|
|
||||||
$("#editMemberModal").modal("show");
|
$("#editMemberModal").modal("show");
|
||||||
|
|
||||||
|
// Update the submit button
|
||||||
|
$("#saveEditModal").off("click").on("click", () => { saveEditModal(memberId); });
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveEditModal(memberId) {
|
||||||
|
|
||||||
|
// Grab the updated data
|
||||||
|
const first = $("#editMemberFirstName").val();
|
||||||
|
const last = $("#editMemberLastName").val();
|
||||||
|
const teamNumber = $("#editMemberTeam").val();
|
||||||
|
const search = $("#search").val();
|
||||||
|
|
||||||
|
teamsLoading(true);
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: "{% url 'update-member' %}",
|
||||||
|
type: "post",
|
||||||
|
data: {
|
||||||
|
"csrfmiddlewaretoken": "{{ csrf_token }}",
|
||||||
|
"memberId": memberId,
|
||||||
|
"first": first,
|
||||||
|
"last": last,
|
||||||
|
"teamNumber": teamNumber,
|
||||||
|
"search": !isEmptyOrSpaces(search) ? search : null
|
||||||
|
},
|
||||||
|
error: (xhr, textStatus, errorThrown) => { alert(errorThrown); },
|
||||||
|
success: (result) => {
|
||||||
|
teamsLoading(false);
|
||||||
|
loadTeams(result.teams, search);
|
||||||
|
$("#editMemberModal").modal("hide");
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
{% endblock scripts %}
|
{% endblock scripts %}
|
@ -9,4 +9,5 @@ urlpatterns = [
|
|||||||
|
|
||||||
path('bulk-peg/', views.bulk_create_pegs, name='bulk-peg'),
|
path('bulk-peg/', views.bulk_create_pegs, name='bulk-peg'),
|
||||||
path('get-teams/', views.get_teams, name='get-teams'),
|
path('get-teams/', views.get_teams, name='get-teams'),
|
||||||
|
path('update-member/', views.update_member, name='update-member')
|
||||||
]
|
]
|
@ -1,11 +1,13 @@
|
|||||||
"""Views for the main app."""
|
"""Views for the main app."""
|
||||||
|
|
||||||
from string import ascii_lowercase
|
from functools import reduce
|
||||||
|
|
||||||
from django.shortcuts import render, redirect
|
from django.shortcuts import render, redirect
|
||||||
from django.http import JsonResponse
|
from django.http import JsonResponse
|
||||||
|
from django.db.models import Q
|
||||||
|
|
||||||
|
from .models import Peg, Team, Member
|
||||||
|
|
||||||
from .models import Peg
|
|
||||||
|
|
||||||
def index(request):
|
def index(request):
|
||||||
return render(request, 'index.html')
|
return render(request, 'index.html')
|
||||||
@ -30,39 +32,69 @@ def bulk_create_pegs(request):
|
|||||||
return redirect(request.META.get('HTTP_REFERER'))
|
return redirect(request.META.get('HTTP_REFERER'))
|
||||||
|
|
||||||
def get_teams(request):
|
def get_teams(request):
|
||||||
"""Returns list of teams."""
|
"""Returns a JsonResponse containing a dictionary with a k/v pair for a list of teams.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
request: the web request object.
|
||||||
|
Returns:
|
||||||
|
JsonResponse: dictionary of teams like so {'teams': [{}, {}, {}]}.
|
||||||
|
"""
|
||||||
|
|
||||||
if not request.POST:
|
if not request.POST:
|
||||||
return
|
return
|
||||||
|
|
||||||
search = request.POST.get("search")
|
search = request.POST.get("search")
|
||||||
|
teams = Team.objects.order_by("team_number").all()
|
||||||
|
|
||||||
from .teams_demo_test import created_teams
|
# Filter out teams that don't contain members being searched for
|
||||||
|
|
||||||
if search:
|
if search:
|
||||||
unfiltered_teams = created_teams.copy()
|
search_terms = search.split()
|
||||||
created_teams = [
|
members = Member.objects.filter(
|
||||||
team for team in unfiltered_teams
|
reduce(
|
||||||
if any(
|
lambda x, y: x | y,
|
||||||
search.lower() in name for name in
|
[
|
||||||
[member["name"].lower() for member in team["members"]]
|
Q(first_name__icontains=term) | Q(last_name__icontains=term)
|
||||||
|
for term in search_terms
|
||||||
|
]
|
||||||
)
|
)
|
||||||
]
|
)
|
||||||
|
teams = teams.filter(members__in=members)
|
||||||
|
|
||||||
created_teams.sort(reverse=False, key=lambda team: team["identifier"])
|
# Create a dictionary for the data that is JSON safe
|
||||||
return JsonResponse({"teams": created_teams})
|
response_data = {"teams": []}
|
||||||
|
for team in teams:
|
||||||
|
team_data = {
|
||||||
|
"team_number": team.team_number,
|
||||||
|
"section": team.section.name if team.section else None,
|
||||||
|
"members": [
|
||||||
|
{"first": member.first_name, "last": member.last_name, "id": member.id, "team": team.team_number}
|
||||||
|
for member in team.members.all()
|
||||||
|
]
|
||||||
|
}
|
||||||
|
response_data["teams"].append(team_data)
|
||||||
|
|
||||||
# if not search:
|
return JsonResponse(response_data)
|
||||||
# created_teams.sort(reverse=False, key=lambda team: team["identifier"])
|
|
||||||
# return JsonResponse({"teams": created_teams})
|
|
||||||
|
|
||||||
# # Create a new list only containing teams that meet the search criteria
|
def update_member(request):
|
||||||
# filtered_teams = []
|
"""Update a member. Returns a JsonResponse with the updated teams."""
|
||||||
# for team in created_teams:
|
|
||||||
# member_names = [member["name"].lower() for member in team["members"]]
|
|
||||||
# if any(search.lower() in name for name in member_names):
|
|
||||||
# filtered_teams.append(team)
|
|
||||||
|
|
||||||
# filtered_teams.sort(reverse=False, key=lambda team: team["identifier"])
|
if not request.POST:
|
||||||
|
return
|
||||||
|
|
||||||
# return JsonResponse({"teams": filtered_teams})
|
# Get the updated values
|
||||||
|
member_id = request.POST.get("memberId")
|
||||||
|
first = request.POST.get("first")
|
||||||
|
last = request.POST.get("last")
|
||||||
|
team_number = request.POST.get("teamNumber")
|
||||||
|
|
||||||
|
# Get the member and team
|
||||||
|
member = Member.objects.get(id=member_id)
|
||||||
|
team = Team.objects.get(team_number=team_number)
|
||||||
|
|
||||||
|
# Update the member
|
||||||
|
member.first_name = first
|
||||||
|
member.last_name = last
|
||||||
|
member.team = team
|
||||||
|
member.save()
|
||||||
|
|
||||||
|
return get_teams(request)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user