Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django form - what's the right form/template to create a many to many object inline

I have two models Directors and JobProject. A JobProject can have multiple directors through a many-to-many relationship.

Currently, when I create a new JobProject I choose from the directors I have saved who the director will be. However, I am trying to understand how can I code a form/view for creating a JobProject where I can also create a director in-line (in case I don't have the director already saved in the DB).

Ideally, the user flow would be:

1) Start entering a JobProject details. 
2) If the director already exists in the DB, pick it.
3) If the director doesn't exist, allow users to enter the details of a new director object in-line
4) Users go ahead and finish entering JobProject details.
5) Users click save and the BE first saves the new director and then saves the new project with the director pointing at the newly created director.

I basically have 1,2,4,5 figured out but I can't understand how to do 3. Any help? This is my code right now.

Model

class Director(models.Model):
    ...
    name_surname = models.CharField(max_length=60)


class JobProject(models.Model):
    ...
    director = models.ManyToManyField(Director, blank=True, )

Form

class DirectorForm(forms.ModelForm):
    class Meta:
        model = Director
        fields = '__all__'
        exclude = ('id', 'owner', 'matching_user')

class JobProjectForm(forms.ModelForm):
    class Meta:
        model = JobProject
        fields = '__all__'
        exclude = ('id', 'owner')
        ...

    def __init__(self, *args, **kwargs):

        ...

        if 'director' in self.data:
            self.fields['director'].queryset = Director.objects.all()
        elif self.instance:
            self.fields['director'].queryset = self.instance.director

View

def new_jobproject(request):
    form = JobProjectForm()
    if request.is_ajax():
        term = request.GET.get('term')
        source = request.GET.get('source')
        response_content = []

        ...

        elif source == 'director':
            directors_retrieved = Director.objects.filter(Q(name_surname__istartswith=term)
                                                        & (Q(owner__isnull=True) | Q(owner=request.user))
                                                            )
            response_content = list(directors_retrieved.values())
    
    # if this is a POST request we need to process the form data
    if request.method == 'POST':
        # create a form instance and populate it with data from the request:
        form = JobProjectForm(request.POST)
        # check whether it's valid:
        if form.is_valid():
            # process the data in form.cleaned_data as required
            jobproject_added = form.save()
            jobproject_added.owner = request.user
            jobproject_added.save()

            # redirect to precedent url:
            return redirect('action:dashboard')
    # if a GET (or any other method) we'll create a blank form
    return render(request, 'action/forms/jobproject_form.html', {'form': form, 'source': 'new'})


like image 275
giaggi Avatar asked Nov 07 '22 00:11

giaggi


1 Answers

Try to use django-taggit: https://django-taggit.readthedocs.io/en/latest/ with django-autocomplete-light: https://django-autocomplete-light.readthedocs.io/en/master/taggit.html. With these, you can add new many-to-many relationships to the form.

like image 89
ilsurealism Avatar answered Nov 12 '22 11:11

ilsurealism