which is updated by UpdateView. And I wanted to add radio select to this. All solutions I have found with are forms.py, but since I use UpdateView I won't use widget in forms. Any ideas?

views.py

class AddPersonView(LoginRequiredMixin, UserPassesTestMixin, UpdateView)
    model = Trip
    template_name = 'tripplanner/add_new_member.html'
    fields = ["members"]
    success_url = '/'


    def form_valid(self, form):
        form.instance.author = self.request.user
        return super().form_valid(form)

    def test_func(self):
        detailView = self.get_object()
        if self.request.user in detailView.members.all() or self.request.user in detailView.owners.all():
            return True
        return False

.html

{% extends "tripplanner/base.html" %}
{% load crispy_forms_tags %}
{% load i18n %}
{% block content %}
    <div class="content-section">
        <form method="POST">
            {% csrf_token %}
            <fieldset class="form-group">
                <legend class="border-bottom mb-4">{% trans "New member" %}</legend>
                {{ form|crispy }}
            </fieldset>
            <div class="form-group">
                <button class="btn btn-outline-info" type="submit">{% trans "Add" %}</button>
            </div>
        </form>
    </div>
{% endblock content %}

1 Answers

1
Willem Van Onsem On Best Solutions

All solutions I have found with are forms.py, but since I use UpdateView I won't use widget in forms.

Well the one does not exclude the other at all. In fact, it is very common to specify the form class in a CreateViews and UpdateViews. Even if you do not specify a Form yourself, behind the curtains your UpdateView will construct one for you with default elements. Indeed, in the ModelFormMixin class [GitHub], we see:

class ModelFormMixin(FormMixin, SingleObjectMixin):

    # ...

    def get_form_class(self):
        # ...
        return model_forms.modelform_factory(model, fields=self.fields)

so behind the curtains, it uses a modelform_factory to construct a ModelForm for you with the fields you provided. But nothing is stopping you from specifying your own form, and using that form.

In forms.py, you can thus specify in your AddPersonForm that you want to use a RadioSelect [Django-doc], although since members is likely a many-to-many relation, a CheckboxSelectMultiple [Django-doc] is more appropriate:

# app/forms.py

from app.models import Trip
from django import forms, RadioSelect

class AddPersonForm(forms.ModelForm):

    class Meta:
        model = Trip
        fields = ['members']
        widgets = {
            'members': RadioSelect()
        }

In your views, you can then make use of your AddPersonForm:

# app/views.py

from django.views.generic.edit import UpdateView
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from app.models import Trip
from app.forms import AddPersonForm

class AddPersonView(LoginRequiredMixin, UserPassesTestMixin, UpdateView)
    model = Trip
    template_name = 'tripplanner/add_new_member.html'
    form_class = AddPersonForm
    success_url = '/'

    # ...

    def test_func(self):
        detailView = self.get_object()
        user = self.request.user
        return user in detailView.members.all() or user in detailView.owners.all()