Paul Johnson
Paul Johnson

Reputation: 13

django forms logged in user problem

I am writing an application to help employees track projects the are working on.

Part of the form should allow logged in employees to click a drop down and see all projects they are working on. This is the part I am struggling with; specifically getting ONLY the logged in user's projects populated in a drop down. Any help or insight is much appreciated. Thanks……

models.py

class Photo(models.Model):
    image = models.ImageField(upload_to='uploads/images/photo')
    title = models.CharField(max_length=50)

    def __unicode__(self):
        return self.title


class Employee(models.Model):
    user = models.ForeignKey(User, unique=True)
    photo = models.ImageField(upload_to='uploads/images')
    department = models.ForeignKey(Department, null=True)
    phone = PhoneNumberField("Phone")

    def __unicode__(self):
        return self.user.get_full_name()


class Projects(models.Model):
    name = models.CharField(max_length=40)
    student = models.ForeignKey(Student)
    photos = models.ManyToManyField(Photo, blank=True, null=True)

forms.py

class ProjectsForm(forms.ModelForm):
    employee = get_object_or_404(Employee, user=user)
    employee_projects = employee.projects_set.all()
    name = forms.ModelChoiceField(queryset=employee_projects,
            empty_label="(Select a Project)", required=True)


    class Meta:
        model = Projects

Upvotes: 1

Views: 269

Answers (2)

Anton Strogonoff
Anton Strogonoff

Reputation: 34032

You need to put first two lines from ProjectsForm class definition to its initialization method and change them a bit.

class ProjectsForm(forms.ModelForm):
    name = forms.ModelChoiceField(queryset=Employee.objects.all(),
            empty_label="(Select a Project)", required=True)

    class Meta:
        model = Projects

    def __init__(self, user, *args, **kwargs):
        super(self, ProjectsForm).init(*args, **kwargs)
        employee = get_object_or_404(Employee, user=user)
        self.fields['name'].queryset = employee.projects_set.all()

Now, some explanation. Hope someone will find it useful.

In your original ProjectsForm definition, you're trying to get employee's projects when your class is defined. But this happens once your forms.py file is compiled, which takes place rarely (when you change code, for example). Also, you of course have no data that is necessary to filter projects, i.e., no user object, at that stage.

Instead, you need to do this each time the class is initialized. Initialization in Python takes place in special __init__() method. For example, when you're doing something like

form = ProjectsForm(data=request.POST)

in your view, what happens is that ProjectsForm.__init__(data=request.POST) is called to initialize ProjectsForm into an instance.

So, in our new definition, we're requiring a new argument (user) to be passed to the form when it's instantiated. So you can do something like this in your view:

form = ProjectsForm(request.user, data=request.POST)

In new initialization method, first we're calling the initialization method of parent class (which does some internal django things and should be called anyway), then use argument user to get related employee, and then assign a queryset with that employee's projects to the name field.

Sorry if I'm being too verbose.

See also:

Upvotes: 1

Bruk Habtu
Bruk Habtu

Reputation: 113

Why not have a many to many field in the Employee model that points to all the projects the employee can work on?

https://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.ManyToManyField

I think that would be the best way to do it.

Upvotes: 0

Related Questions