Greetings,
I’ve been struggling trying to figure out how to display a form that allows users to add/remove Users from a single, given Organization (which contains a ManyToManyField). The form should provide a checkbox and a list of all Users for a given Organization, so we can add/remove rows in the through table (i.e., MemberWithUser).
Right now, I have two problems even getting my form to display the way I’d like:
- I cannot figure out how to render a checkbox in the first column without the labels for the users.
- How would I display the columns of User data (e.g. first_name, last_name, email, etc.), so we can see information about the user we’re selecting to add/remove from the given group?
Eventually, I will need to figure out how to validate/save this information to the through model (i.e., OrganizationWithMember), but one step at a time.
I have very limited experience with Forms, so this is very perplexing to me. My project is still very early, so if there are better ways to go about this, I’m all ears. I just need it to work. I have been working on this problem for a couple of days with limited success, so any assistance would be really appreciated!
Below is all of my code.
# models.py
uuid_field = partial(
models.UUIDField,
auto_created=True,
default=uuid4,
editable=False,
primary_key=True,
unique=True,
)
class Organization(models.Model):
members_users = models.ManyToManyField(
User,
blank=True,
related_name="organization_users",
through="OrganizationWithMember",
verbose_name="Internal Directory",
)
def __str__(self) -> str:
return str(self.name)
def get_absolute_url(self) -> str:
"""Return the url for a specific record via it's PK"""
return reverse("organizations:detail", kwargs={"pk": self.pk})
class User(AbstractUser):
nickname = models.CharField("Nickname or Preferred name", max_length=150, blank=True)
def get_absolute_url(self):
return reverse("users:detail", kwargs={"pk": self.pk})
def __str__(self):
if self.nickname:
firstname = self.nickname
else:
firstname = self.first_name
return f"{firstname} {self.last_name}".strip()
class OrganizationWithMember(models.Model):
"""Organizations and their associated members"""
uuid = uuid_field(db_column="organization_with_user_uuid")
organization = models.ForeignKey(
Organization,
on_delete=models.CASCADE,
db_column="organization_uuid_fk",
)
user = models.ForeignKey(User, on_delete=models.PROTECT, db_column="user_uuid_fk")
class Meta:
verbose_name = "Organization and its associated Member"
verbose_name_plural = "Organizations with their associated Members"
def __str__(self) -> str:
return f"{self.organization.__str__()}_{self.user.__str__()}"
def get_absolute_url(self) -> str:
"""Return the url for a specific record via it's PK"""
return reverse("organization_with_member", kwargs={"pk": self.pk})
# views.py
class OrganizationMembershipUpdateView(UpdateView):
context_object_name = "org"
model = Organization
# fields = ["members_users"]
# table_class = OrganizationMembershipTable
form_class = OrganizationMembershipUpdateForm
template_name = "organizations/members/update.html"
# forms.py
class OrganizationMembershipUpdateForm(ModelForm):
members_users = ModelMultipleChoiceField(
queryset=User.objects.all(), widget=CheckboxSelectMultiple
)
class Meta:
model = Organization
fields = ["members_users"]
# update.html
{% block content %}
<div class="container mt-2">
<form method="post">
{% csrf_token %}
<table>
{% for field in form.members_users %}
<tr>
<td>{{ field }}</td>
<td>{{ field.instance.members_users.user.first_name }}</td>
<td>{{ field.instance.members_users.user.last_name }}</td>
<td>{{ field.instance.members_users.user.email }}</td>
</tr>
{% endfor %}
</table>
<div class="mt-3 mb-4">
<button type="submit" class="btn btn-primary">Save</button>
</div>
</form>
</div>
{% endblock content %}
edit: I was able to make a small bit of progress tonight getting all the Users to render in the form at least.