1

I have a form to make POST data to database.

I'm using Django 1.11

views.py

class BusinessCreate(CreateView):
    model = Business
    fields = '__all__'

    @method_decorator(login_required)
    def dispatch(self, *args, **kwargs):
        messages.success(self.request, 'dispatch')
        return super(BusinessCreate, self).dispatch(*args, **kwargs)

    def form_valid(self, form):
        messages.success(self.request, 'valid')
        form.instance.user = self.request.user   # set user_id field to session user
        form.save()

    def get_success_url(self):
        messages.success(self.request, 'Business Added Successfully')
        return reverse('business:list')

template

<form class="card" method="POST">
    {% csrf_token %}

    {{ form.non_field_errors }}
    {{ form.non_field_errors }}

    {% render_field form.name class='form-control' placeholder='Business Title' %}
    {{ form.name.errors }}

    {% render_field form.business_type class='form-control' %}
    {{ form.business_type.errors }}

    <button class="btn">Add Business</button>
</form>

When I submit the form, it doesn't save and also does not return any error.

The messages in three methods in views.py are to check which method is called and it always prints dispatch since the only dispatch is called.

I used debug_toolbar to check for debug whether request is POST or GET or none of the two and it show.

enter image description here

Anuj TBE
  • 9,198
  • 27
  • 136
  • 285

2 Answers2

2

Try the better way.

mixins.py

 from django.contrib.auth.decorators import login_required
 from django.core.exceptions import PermissionDenied
 from django.views.generic import View
 from django.utils.decorators import method_decorator

 class LoginRequired(View):
    @method_decorator(login_required)
    def dispatch(self, *args, **kwargs):
        return super(LoginRequired, self).dispatch(*args, **kwargs)

views.py

Now whenever you need login required for any model just include it in your class.

from .mixins import LoginRequired

class BusinessCreate(LoginRequired, CreateView):
    template = 'business/create.html'
    model = Business
    fields = '__all__'    

    def form_valid(self, form):
        messages.success(self.request, 'valid')
        form.instance.user = self.request.user # set user_id field to session user
        return super(BusinessCreate, self).form_valid(form)

    def get_success_url(self):
        messages.success(self.request, 'Business Added Successfully')
        return reverse('business:list')

This should work fine!!!

Astik Anand
  • 12,757
  • 9
  • 41
  • 51
1

Firstly, you should add form.errors to the template to help debug the problem.

{{ form.errors }}

You will probably have an error that the user is required. You are telling Django to include all fields in the form with fields = __all__', but you are only including two fields in the template. The form doesn't know that you only rendered two fields, it just thinks that the user is missing.

You should set fields on the view to be the same as the fields you are rendering in the template.

class BusinessCreate(CreateView):
    model = Business
    fields = ['name', 'business_type']

If you have a custom model form class, then you can set form_class instead of fields:

class BusinessCreate(CreateView):
    model = Business
    form_class = BusinessForm

Note that if you are using self.request.user, you need to handle the case where the user is not logged in. You can use the LoginRequiredMixin to do this.

Alasdair
  • 298,606
  • 55
  • 578
  • 516
  • I did what you said, but now it has started giving error as `Using ModelFormMixin (base class of BusinessCreate) without the 'fields' attribute is prohibited.` – Anuj TBE Oct 07 '17 at 10:29
  • Oops, I always forget whether `fields` is required when you set `form` for the create view. Actually, I don't think you need a custom model form at all, just set `fields` correctly on the view. – Alasdair Oct 07 '17 at 11:27
  • I do have created custom Form as I have to use `inline formset` – Anuj TBE Oct 07 '17 at 11:54
  • Then I believe you'll have to set `fields` correctly in your model form and view. – Alasdair Oct 07 '17 at 11:59
  • so it means, instead of defining `fields` in `Form`, I need to define it in `view`? Which I don't think is best way. Actually I was thinking of to use `exclude` instead of `include` because there are few columns which are set with default value and number of such fields are far less than `required fields`. – Anuj TBE Oct 07 '17 at 12:07
  • You can use `exclude` instead of `include` if you prefer. The key thing is that the fields in the form/view must match the fields in the template. Note that if you use `exclude`, then your template may get out of sync with your view if you add a new field to the model in future. Note that if a field is included (or not excluded) then you must render the field in the template. Missing out the field in the template is not the same as saying "use the default value". – Alasdair Oct 07 '17 at 12:11
  • as far I have understood the documentation, if I use `exclude`, other fields are automatically added to `fields` and thus no longer required to include new field if added in future. – Anuj TBE Oct 07 '17 at 12:13
  • Yes, that's right. My point is that you are manually rendering the fields in the template. If you add a new field to the model, then it will automatically be added to the form in the view, so you must remember to add it to the template at the same time. – Alasdair Oct 07 '17 at 12:16
  • Yes I understand that, I'll take care of that for sure. But for now, I want to separate `fields/exclude` from `view` and use it in `Form`. How can I resolve the error message `'fields' attribute is prohibited`? – Anuj TBE Oct 07 '17 at 12:30
  • If you have a custom form class, then make sure you have set `form_class` and not `form`. If that's not the problem, then I can't tell what the problem is from the info you've posted. My example above wouldn't cause that error because I have set `fields`. – Alasdair Oct 07 '17 at 12:44