Using inline formsets with manytomany relationship

672 views Asked by At

I have AbstractUser and Relationship models. The user model has a manytomany field through relationship model

class User(AbstractUser):
    username = models.CharField(
        verbose_name="username", max_length=256, unique=True)
    first_name = models.CharField(verbose_name="first name", max_length=30)
    last_name = models.CharField(verbose_name="last name", max_length=30)
    slug = models.SlugField(max_length=255, unique=True, blank=True)
    date_joined = models.DateTimeField(
        verbose_name="joined date", auto_now_add=True)
    friends = models.ManyToManyField('self', through='Relationship', symmetrical=False,
                                     related_name='following')
    is_active = models.BooleanField(default=True)
    is_superuser = models.BooleanField(default=False)
    is_staff = models.BooleanField(default=False)

    def __str__(self):
        return str(self.username)

    def save(self, *args, **kwargs):
        if not self.slug:
            self.slug = slugify(self.username)
        super().save(*args, **kwargs)


class Relationship(models.Model):
    from_person = models.ForeignKey(
        User, related_name='from_people', on_delete=models.CASCADE)
    to_person = models.ForeignKey(
        User, related_name='to_people', on_delete=models.CASCADE)

    def __str__(self):
        return f"from {self.from_person} to {self.to_person}"

How to create an inline formset with fields=['from_person' and 'to_person'] to assign users to each others That is what I tried to do but I couldn't have both fields because of fk_name Any help please!

def staff_profile_view(request):
    user = User.objects.get_by_natural_key(request.user)
    AssignFriendsFormSet = inlineformset_factory(
        User, Relationship, fk_name='from_person', fields=('to_person', 'from_person',))

    formset = AssignFriendsFormSet(
        queryset=Relationship.objects.none(), instance=user)

    if request.method == "POST":
        formset = AssignFriendsFormSet(request.POST, instance=user)
        if formset.is_valid():
            formset.save()

    return render(request, 'staff_profile.html',{"formset": formset})
1

There are 1 answers

0
SamSparx On

An inline formset won't let you change the 'line' between models, so you can't include 'from_person' as a changeable field. In this case it looks like you're trying to get a list of people following the user/requester (the 'from_person') with the possibility of changing them so they don't follow the user anymore.

Inline formsets are just an abstraction, though - a shorthand for a particular type of queryset. You can achieve exactly the same effect through a normal formset, something like

AssignFriendsFormSet = modelformset_factory(Relationship, fields=('from_person', 'to_person'))
queryset = Relationship.objects.filter(from_person=user)
formset = AssignFriendsFormSet (
        queryset=queryset,
    )

The many-to-many field is really just a record in the through table, so you can update it there.