Search code examples
pythondjangoformsdjango-formsdjango-request

Access request from the forms.Form to get data from dB related to user


So basic task is: add the template name and text to the choices in the ChoiceField with Selector widget to the form using the data from dB linked to the authenticated User only. Template is a model linked to user as a ForeignKey.

I'd like to access the request data(user) via the Form class linked to the connected view as django.views.generic.View class.

I've checked similar questions here: Curious about get_form_kwargs in FormView

and here: Sending request.user object to ModelForm from class based generic view in Django

and here: Django: Accessing request in forms.py clean function

However they don't touch base with non-FormView classes. And as it's fairly old solutions, I was curious if there's more likely approach to reach request from forms.Form class.

Here's my code:

views.py

class InformFill(View):
form_class = InformForm
temlate_name = 'distrib_db/inform_fill.html'

def get(self, request):
    if request.user.is_authenticated():
        form = self.form_class(None)
        return render(request, self.temlate_name, context={'form': form})
    else:
        return redirect('distrib_db:login')

def post(self, request):
    if request.user.is_authenticated():
        form = self.form_class(request.POST)
        if form.is_valid():
            inform = Inform(flt_numbr=form.cleaned_data['flight_number'], date=form.cleaned_data['date'],
                            template=form.cleaned_data['text'], user=request.user)
            inform.save()
            date = form.cleaned_data['date']
            flt_numbr = form.cleaned_data['flight_number']
            try:
                emails, contacts = get_mail_cnt(date, flt_numbr)
                # inform = get_object_or_404(Inform, pk=request['pk'])
                paxdata = PaxData(inform=inform, emails=' '.join(emails), contacts=' '.join(contacts))
                paxdata.save()
                return redirect('/inform/{0}/'.format(inform.pk))
            # 'distrib_db:detail', context={'pk': inform.id}
            except Exception as e:
                return render(request, 'distrib_db/sample.html',
                              context={'date': date, 'flight_number': flt_numbr, 'error': e})

                # return render(request, 'distrib_db/sample.html', context={'date': date, 'flt_numbr': flt_numbr})

        return render(request, self.temlate_name, context={'form': form})
    else:
        return redirect('distrib_db:login')

forms.py

class InformForm(forms.Form):
flight_number = forms.CharField(5, widget=forms.TextInput())
date = forms.DateField(widget=forms.DateInput(attrs={'class': 'datepicker'}))
template = forms.ChoiceField(choices=templates, widget=forms.Select(attrs={'id': 'select_box',
                                                                          'onchange': 'javascript:changer();'}))
text = forms.CharField(widget=forms.Textarea(attrs={'id': 'txt_box', 'class': 'latin',
                                                    'maxlength': "160", 'onchange': 'javascript:validateTextArea();'}))

Generally speaking i'd like to achieve smth like this:

`class InformForm(forms.Form):
    def get_template_choices(self):
        templates = self.request.user.template_set.all()
        choices = []
        for t in templates: 
            choices.append((t.text, t.name))
        return choices

    flight_number = forms.CharField(5, widget=forms.TextInput())
    date = forms.DateField(widget=forms.DateInput(attrs={'class':                                                    
                                                      'datepicker'}))
    template = forms.ChoiceField(choices=get_template_choices(), 
                                         widget=forms.Select(attrs=
                                        {'id': 'select_box',

                                         'onchange': 'javascript:changer();'}))
    text = forms.CharField(widget=forms.Textarea(attrs={'id': 'txt_box', 
                                                    'class': 'latin',
                                                    'maxlength': "160", 
                              'onchange': 'javascript:validateTextArea();'}))`

I'd appreciate any approach, mb I lack knowledge and asking newbie questions, sorry about it.

I just wanna get the python-way solution rather then build some js/jinja walk-arounds.

Thank you for your time!

#

After @Danielius comments, I've made some adjustments:

`class InformForm(forms.Form):
    def __init__(self, user=None, *args, **kwargs):
        if user:
            self.fields['template'] = forms.ChoiceField(choices=tuple([(template.text, template.name) for template in user.template_set.all()]),
                                                        widget=forms.Select(attrs={'id': 'select_box', 'onchange': 'javascript:changer();'}))

    flight_number = forms.CharField(5, widget=forms.TextInput())
    date = forms.DateField(widget=forms.DateInput(attrs={'class': 'datepicker'}))
    # template = forms.ChoiceField(choices=templates, widget=forms.Select(attrs={'id': 'select_box',
    #                                                                           'onchange': 'javascript:changer();'}))
    text = forms.CharField(widget=forms.Textarea(attrs={'id': 'txt_box', 'class': 'latin',
                                                        'maxlength': "160", 'onchange': 'javascript:validateTextArea();'}))`

Got an error AttributeError: 'InformForm' object has no attribute 'fields'


Solution

  • You can pass request to your form by changing your __init__ method like this :

    class InformForm(forms.Form):
    ...
       def __init__(self, user=None,*args, **kwargs):
            super(InformForm, self).__init__(**kwargs)
            if user:  
                self.fields['somefield'] = forms.ChoiceField()                  
                self.fields['somefield'].widget = forms.Select()
                self.fields['somefield'].queryset = Someobject.objects.filter(User=user)
    ...
    

    If the User is linked to other object in db by Foreign key, then you will get all the values of other object as select items.

    Also , when creating form you could pass user like this :

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