Django class-based form with dropdowns populated with data from model / db

Question:

This my Django code:

forms.py

from django import forms

class MyForm(forms.Form):
    name = forms.CharField()
    location = forms.CharField()

views.py

class MyFormView(FormView):
    template_name = 'form.html'
    form_class = MyForm
    success_url = 'home'

    def get(self, request, *args, **kwargs):
        form = self.form_class
        return render(request, 'form.html', {'form': form})

    def post(self, request, *args, **kwargs):
        form = self.form_class(request.POST)
        if form.is_valid():
            form.save()
            return redirect('home')
        else:
            return render(request, self.template_name, {'form': form})

template form.html

   <form method="post" action="{% url 'form' %}">
        {% csrf_token %}
        {{ form.as_p }}
        <input type="submit" class="btn btn-primary btn-block py-2" value="OK">
   </form>

models.py

class MyModel(models.Model):
    # ...
    name = models.OneToOneField(Person, on_delete=models.CASCADE))
    location = models.ForeignKey(Location, on_delete=models.CASCADE)
    date = models.DateTimeField(auto_now_add=True)
    # ...

I want both two fields (name, location) to be drop-downs (combobox-es) not CharFields, and I want to populate their entries / values with data coming from db (django models). How can I do that? I am completely new to CBV idea.

Asked By: PrertoQuebas

||

Answers:

You should use ModelChoiceField instead of CharField so:

from django import forms
from .models import YourModelName

class ReleaseForm(forms.Form):
    name = forms.ModelChoiceField(queryset=YourModelName.objects.all())
    location = forms.ModelChoiceField(queryset=YourModelName.objects.all())

Form class doesn’t have a save() method unlike modelforms so you should manually save the form using cleaned_data in form_valid() method as:

from django.shortcuts import render, redirect
from django.urls import reverse_lazy
from django.views.generic import FormView

from .forms import MyForm
from .models import MyModel

class MyFormView(FormView):
    template_name = 'form.html'
    form_class = MyForm
    success_url = reverse_lazy('home')

    def form_valid(self, form):
        name = form.cleaned_data['name']
        location = form.cleaned_data['location']
     
        MyModel.objects.create(name=name, location=location)
        return super().form_valid(form)
Answered By: Sunderam Dubey