11

I'm trying to assign Project Manager to Employee.

  • Every Employee, can be Project Manager.

  • Project Managers can have multiple Employees.

  • Employees can have only 1 Project Manager.

But When I do Employee.objects.get(name='HereHere').get_xxx()

I got AttributeError: 'ManyToManyField' object has no attribute '_m2m_reverse_name_cache'

class Employee(models.Model):
    name = models.CharField(max_length=20, unique=True)
    pm = models.ManyToManyField('self', symmetrical=False, through='PM', related_name='related_to', )

    def add_pm(self, employee, ):
        pm, created = PM.objects.get_or_create(from_employee=self, to_employee__in=employee,)
        return pm

    def remove_pm(self, employee, ):
        PM.objects.filter(
            from_employee=self,
            to_employee=employee,
        ).delete()
        return

    def get_relationships(self, ):
        return self.pm.filter(
            to_employee__from_employee=self)   #<----- AttributeError: 'ManyToManyField' object has no attribute '_m2m_reverse_name_cache'

    def get_related_to(self,):
        return self.related_to.filter(
            from_employee__to_employee=self)    #<----- AttributeError: 'ManyToManyField' object has no attribute '_m2m_reverse_name_cache'


    def __str__(self):
        return '%s' % self.name


class PM(models.Model):
    from_employee = models.ForeignKey(Employee, related_name='from_employee')
    to_employee = models.ManyToManyField(Employee, related_name='to_employee') #<----- This cause the problem
M.javid
  • 6,387
  • 3
  • 41
  • 56
HereHere
  • 734
  • 1
  • 7
  • 24

1 Answers1

8

I made an app with your code above and managed to recreate the issue.

I tried switching 'self' to 'Employee' as suggested here and tried tweaking a couple other things (like on_delete=models.CASCADE) in the field, but still instantiating an Employee object and calling .pm on it threw the error.

I think django has expectations about what classes you can use as the through parameter for a ManyToMany and it has to have two foreign keys, not a foreign key and a ManyToMany.

So...

If you switch to this:

class PM(models.Model):
    from_employee = models.ForeignKey(Employee, related_name='from_employee')
    to_employee = models.ForeignKey(Employee, related_name='to_employee')

it works. And that's actually the normal pattern for ManyToMany relationships anyways -- each PM represents a Project Manager relationship, not a person.

Alternatively,

You could have project manager be a foreign key from Employee to Employee, named something like managed_by to make sure each employee can only have one project manager.

Community
  • 1
  • 1
Brendan W
  • 3,303
  • 3
  • 18
  • 37
  • Can you show me how to make a fireign key to make each employee can have only one pm? – HereHere Aug 19 '15 at 13:04
  • `to_employee = models.ManyToMany()`- I am using, because In forms.py I can assign multiple employees to PM. If I change `to_employee` to use ForeignKey then I can only assign one employee to PM. – HereHere Aug 19 '15 at 13:28
  • If you make the assignment from the employee *to* the project manager, then each employee can only have one PM, but each PM can have many employees. Just make a foreign key field in Employee – Brendan W Aug 19 '15 at 16:00