0

I have a question related this one: How to handle the validation of the model form when the model has a clean method if the model form excluded some fields?

This is my model:

class StudentIelts(Model):

    SCORE_CHOICES = [(float(i/2), float(i/2)) for i in range(0, 19)]
    IELTS_TYPE_CHOICES = [('General', 'General'), ('Academic', 'Academic'), ]

    student = OneToOneField(Student, on_delete=CASCADE)
    has_ielts = BooleanField(default=False, )
    ielts_listening = FloatField(choices=SCORE_CHOICES, null=True, blank=True, )
    ielts_reading = FloatField(choices=SCORE_CHOICES, null=True, blank=True, )
    ielts_writing = FloatField(choices=SCORE_CHOICES, null=True, blank=True, )
    ielts_speaking = FloatField(choices=SCORE_CHOICES, null=True, blank=True, )
    ielts_overall = FloatField(choices=SCORE_CHOICES, null=True, blank=True, )
    ielts_exam_type = CharField(max_length=10,  null=True, blank=True, choices=IELTS_TYPE_CHOICES, )
    ielts_exam_date = DateField(null=True, blank=True, )
    ielts_file = FileField(upload_to=student_directory_path, null=True, blank=True, )

    student_ielts_non_empty_fields = \
        {
            'ielts_listening': 'please enter your listening score',
            'ielts_reading': 'please enter your reading score',
            'ielts_writing': 'please enter your writing score',
            'ielts_speaking': 'please enter your speaking score',
            'ielts_overall': 'please enter your overall score',
            'ielts_exam_type': 'please enter your exam type',
            'ielts_exam_date': 'please specify your exam date',
        }

    def clean(self):
        errors = {}
        if self.has_ielts:
            for field_name, field_error in self.student_ielts_non_empty_fields.items():
                if getattr(self, field_name) is None:
                    errors[field_name] = field_error
        if errors:
            raise ValidationError(errors)
class StudentIeltsFilterForm(ModelForm):

    class Meta:
        model = StudentIelts
        fields = ['has_ielts', 'ielts_listening', 'ielts_reading', 'ielts_writing', 'ielts_speaking', 'ielts_overall', 'ielts_exam_type', ]

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.instance.student_ielts_non_empty_fields.pop('ielts_exam_date')

But when I check the has_ielts field and submit the form I see the error below:

Exception Type: KeyError
Exception Value: 'ielts_exam_date'

My view is as below:

def home(request):
    template_name = 'programs/home.html'
    home_context = {}
    if request.POST:
        return HttpResponse('We did not expect a POST request')

    else:
        if request.GET.get('hidden'):
            student_ielts_filter_form = StudentIeltsFilterForm(request.GET)

            if student_ielts_filter_form.is_valid():

                querystring = urlencode(request.GET)
                return redirect(reverse('programs') + '?' + querystring)
        else:

            student_ielts_filter_form = StudentIeltsFilterForm()
    home_context.update({
        'student_ielts_filter_form': student_ielts_filter_form,
    })
    return render(request, template_name, home_context)
Amin Ba
  • 1,603
  • 1
  • 13
  • 38
  • Show the entire stack trace – dirkgroten Oct 06 '19 at 14:32
  • I am passing the form data to another view tp pre-occupy my form in the second page with the data inserted in the home page – Amin Ba Oct 06 '19 at 14:41
  • I have included a hidden input in my home template to distinguish the get request is a direct request by entering the url or is request passed from the home page – Amin Ba Oct 06 '19 at 14:43
  • Please show the error trace – dirkgroten Oct 06 '19 at 14:46
  • The error trace: in View: ``` student_ielts_filter_form = StudentIeltsFilterForm(request.GET) ``` in form: ``` self.instance.student_ielts_non_empty_fields.pop('ielts_exam_date') ``` – Amin Ba Oct 06 '19 at 15:00
  • even when I send a direct get request, I encounter an error in this line: `student_ielts_filter_form = StudentIeltsFilterForm() ` and this: `response = wrapped_callback(request, *callback_args, **callback_kwargs)` and this 'response = self.process_exception_by_middleware(e, request)` and this `response = get_response(request) ' – Amin Ba Oct 06 '19 at 15:05
  • Can you inspect `self.instance` in your debugger? Check the non empty fields dictionary. – dirkgroten Oct 06 '19 at 15:12
  • Whats your IDE? You really need to use an IDE with integrated debugger. Pycharm or VSCode – dirkgroten Oct 06 '19 at 15:16
  • Then run your project in debug mode (click on the bug symbol instead of play symbol) and click in the margin of the line where you want a breakpoint. – dirkgroten Oct 06 '19 at 15:18
  • I don’t know what you’re running in debug mode but it’s not runserver. – dirkgroten Oct 06 '19 at 15:59
  • Read the pycharm docs on how to run django. – dirkgroten Oct 06 '19 at 16:00
  • 1
    I've updated my original answer here: https://stackoverflow.com/questions/58254333/how-to-handle-the-validation-of-the-model-form-when-the-model-has-a-clean-method/58257277?noredirect=1#comment102885108_58257277 – dirkgroten Oct 06 '19 at 16:49
  • @dirkgroten I also would appreciate having your evaluation and modification recommendations of the method I am sending query to the next view (from home view to the next view) and working with Get request. – Amin Ba Oct 06 '19 at 17:27
  • 1
    Your view looks fine to me. Using GET is also fine when you’re just filtering data and not modifying anything in your db. – dirkgroten Oct 06 '19 at 17:31
  • @dirkgroten I also have a related question about using hidden input to find out the get request is original or not: https://stackoverflow.com/questions/58091630/how-to-differentiate-an-http-request-submitted-from-a-html-form-and-a-http-reque – Amin Ba Oct 06 '19 at 17:31

1 Answers1

0

This is the answer given by @dirkgroten . I am documenting his answer:

class StudentIelts(Model):

    SCORE_CHOICES = [(float(i/2), float(i/2)) for i in range(0, 19)]
    IELTS_TYPE_CHOICES = [('General', 'General'), ('Academic', 'Academic'), ]

    student = OneToOneField(Student, on_delete=CASCADE)
    has_ielts = BooleanField(default=False, )
    ielts_listening = FloatField(choices=SCORE_CHOICES, null=True, blank=True, )
    ielts_reading = FloatField(choices=SCORE_CHOICES, null=True, blank=True, )
    ielts_writing = FloatField(choices=SCORE_CHOICES, null=True, blank=True, )
    ielts_speaking = FloatField(choices=SCORE_CHOICES, null=True, blank=True, )
    ielts_overall = FloatField(choices=SCORE_CHOICES, null=True, blank=True, )
    ielts_exam_type = CharField(max_length=10,  null=True, blank=True, choices=IELTS_TYPE_CHOICES, )
    ielts_exam_date = DateField(null=True, blank=True, )
    ielts_file = FileField(upload_to=student_directory_path, null=True, blank=True, )

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.student_ielts_non_empty_fields = \
            {
                'ielts_listening': 'please enter your listening score',
                'ielts_reading': 'please enter your reading score',
                'ielts_writing': 'please enter your writing score',
                'ielts_speaking': 'please enter your speaking score',
                'ielts_overall': 'please enter your overall score',
                'ielts_exam_type': 'please enter your exam type',
                'ielts_exam_date': 'please specify your exam date',
            }

    def clean(self):
        errors = {}
        if self.has_ielts:
            for field_name, field_error in self.student_ielts_non_empty_fields.items():
                if getattr(self, field_name) is None:
                    errors[field_name] = field_error
        if errors:
            raise ValidationError(errors)

and

class StudentIeltsFilterForm(ModelForm):

    class Meta:
        model = StudentIelts
        fields = ['has_ielts', 'ielts_listening', 'ielts_reading', 'ielts_writing', 'ielts_speaking', 'ielts_overall', 'ielts_exam_type', ]

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.instance.student_ielts_non_empty_fields.pop('ielts_exam_date')

read his explanation: How to handle the validation of the model form when the model has a clean method if the model form excluded some fields?

Amin Ba
  • 1,603
  • 1
  • 13
  • 38