简体   繁体   中英

How to get template variables by using FormView?

I am currently following Mozilla's Django tutorial ( https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Forms ). The tutorial mostly shows how to create form using functions. I am trying to make the same function view work by using a generic class view (FormView). I am able to make most of the code to work except for 2 things. First one is that I can't seem to be able to save the due date. And, second one, is that I don't know how to access the model fields in my template using template variables.

Here is my form model from the forms.py file.

class RenewBookModelForm(ModelForm):
    def clean_due_back(self):
        data = self.cleaned_data['due_back']

        # Check if a date is not in the past.
        if data < datetime.date.today():
            raise ValidationError(ugettext_lazy(
                'Invalid date - renewal in past'))

        # Check if a date is in the allowed range (+4 weeks from today).
        if data > datetime.date.today() + datetime.timedelta(weeks=4):
            raise ValidationError(ugettext_lazy(
                'Invalid date - renewal more than 4 weeks ahead'))

        # Remember to always return the cleaned data.
        return data

    class Meta:
        model = BookInstance
        fields = ['due_back']
        labels = {'due_back': ugettext_lazy('New renewal date')}
        help_texts = {'due_back': ugettext_lazy(
            'Enter a date between now and 4 weeks (default 3).')}

The form model implemented as a function:

@permission_required('catalog.can_mark_returned')
def renew_book_lirarian(request, pk):
    book_instance = get_object_or_404(BookInstance, pk=pk)

    # If this is a POST request then process the Form data
    if request.method == 'POST':

        # Create a form instance and populate it with data from the request (binding):
        form = RenewBookModelForm(request.POST)

        # Chech if the form is valid
        if form.is_valid():
            # process that data in form.cleaned_data as required (here we just write to the model due_back field)
            book_instance.due_back = form.cleaned_data['due_back']
            book_instance.save()

            # redirect to a new URL
            return HttpResponseRedirect(reverse('all-borrowed'))

    # If this is a GET (or any other method) create the default form.
    else:
        proposed_renewal_date = datetime.date.today() + datetime.timedelta(weeks=3)
        form = RenewBookModelForm(initial={'due_back': proposed_renewal_date})

    context = {
        'form': form,
        'book_instance': book_instance
    }

    return render(request, 'catalog/book_renew_librarian.html', context=context)

This is my class-based view from my views.py file:

class RenewBookLibrarian(LoginRequiredMixin, PermissionRequiredMixin, generic.FormView):
    """Generic class-based view for forms."""
    template_name = 'catalog/book_renew_librarian.html'
    permission_required = 'catalog.can_mark_returned'
    form_class = RenewBookModelForm
    success_url = reverse_lazy('all-borrowed')

    def get_initial(self):
        proposed_renewal_date = datetime.date.today() + datetime.timedelta(weeks=3)
        initial = {'due_back': proposed_renewal_date}

        return initial

And finally this is my template file where I wish to access the model fields:

{% extends 'base_generic.html' %}

{% block content %}
<h1>Renew: {{ book_instance.book.title }}</h1>
<p>Borrower: {{ book_instance.borrower }}</p>
<p {% if book_instance.is_overdue %} class="text-danger" {% endif %}>Due date: {{ book_instance.due_back }}</p>

<form action="" method="POST">
    {% csrf_token %}
    <table>
        {{ form.as_table }}
    </table>
    <input type="submit" value="submit">
</form>
{% endblock %}

The book_instance variable in the template is not working, hence I would like to know how I can display fields from my BookInstance model.

To add book_instance to the template context, you can override get_context_data .

In the FormView , instead of checking if form.is_valid() , you override the form_valid method (see the class based view docs for basic forms ).

class RenewBookLibrarian(LoginRequiredMixin, PermissionRequiredMixin, generic.FormView):
   ...

   def get_context_data(self, **kwargs):
       context = super().get_context_data(**kwargs)
       context['book_instance'] = get_object_or_404(BookInstance, pk=self.kwargs['pk'])

   def form_valid(self, form):
       book_instance = get_object_or_404(BookInstance, pk=self.kwargs['pk'])
       book_instance.due_date = form.cleaned_data['due_date']
       book_instance.save()
       return super().form_valid(form) # will redirect to the success url

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM