How do I use Select on a Foreign Key Field in a Django ModelForm?

28 Views Asked by At

The purpose is to display a dropdown list of rubriques at the time of creating a discussion.

Models.py

class Discussion(models.Model):
    creator = models.ForeignKey(User,
                                on_delete=models.DO_NOTHING,
                                related_name="is_creator")
    communaute = models.ForeignKey(Communaute,
                                   on_delete=models.CASCADE,
                                   related_name="belongs_to")
    title = models.CharField(max_length=100, blank=False, null=False, unique=True)
    a_propos = models.CharField(max_length=500, blank=False, null=False)
    slug = models.SlugField(null=False, unique=True)
    rubrique = models.ForeignKey(Rubrique, models.SET_NULL, blank=True, null=True)
    created_at = models.DateTimeField(default=datetime.now, blank=True)
class Rubrique(models.Model):
    title = models.CharField(max_length=20, blank=False, null=False)
    explication = models.CharField(max_length=80, blank=True, null=True)
    communaute = models.ForeignKey(Communaute,
                                   related_name="has_rubrique",
                                   on_delete=models.CASCADE)
    slug = models.SlugField(null=False, unique=False)
    created_at = models.DateTimeField(auto_now_add=True, blank=True, null=True)

html

            <form method="post" action="{% url 'discussion_create' communaute.slug %}" enctype="multipart/form-data">
                {% csrf_token %}

                <!-- Modal feed header START -->
                ...
                <!-- Modal feed header END -->
                <!-- Modal feed body START -->
                <div class="modal-body">
                    <!-- Add Feed -->
                    <div class="mb-3">
                        <!-- Feed box  -->
                        <div class="w-100">
                            {{ form_discussion.title.label }}
                            {{ form_discussion.title }}
                        </div>
                    </div>
                    <div class="mb-3">
                        <div class="w-100">
                            {{ form_discussion.a_propos.label }}
                            {{ form_discussion.a_propos }}
                        </div>
                    </div>

                    <div class="col-lg-3 mb-3">
                            {{ form_discussion.rubrique.label }}
                            {{ form_discussion.rubrique }}
                    </div>

                    <!-- Dropzone image START -->
                    <div class="mb-3">
                        {{ form_discussion.bg_image.label }}
                        {{ form_discussion.bg_image }}
                    </div>
                    <!-- Dropzone image END -->

                </div>
                <!-- Modal feed body END -->

                <!-- Modal feed footer -->
                ...
                <!-- Modal feed footer -->
            </form>

To do so, I used a forms.Select because i need to define the attrs in order to preserve the Bootstrap tag


class DiscussionForm(forms.ModelForm):
    class Meta:
        model = Discussion
        fields = ('title', 'a_propos', 'rubrique', 'bg_image')

        # https://stackoverflow.com/questions/5329586/django-modelchoicefield-filtering-query-set-and-setting-default-value-as-an-obj

        widgets = {
            'title': forms.TextInput(attrs={
                'class': 'form-control',
                'placeholder': 'Création de discussion'}
            ),
            'a_propos': forms.Textarea(attrs={
                'class': 'form-control',
                'placeholder': 'En quelques mots ... 500 max',
                'rows': 3}
            ),
            'rubrique': forms.Select(attrs={
                'class': 'form-control',
            }),
            'bg_image': forms.FileInput(attrs={
                'class': 'form-control',
            }
            ),
        }
        labels = {
            'title': 'Titre :',
            'a_propos': 'Description :',
            'rubrique': 'Rubrique :',
            'bg_image': 'Image de fond :',
        }

I tried with modelchoicefield but I found no way to define attrs so the bootstrap is lost.

So, I expected to list only the coprresponding rubriques to the communaute and In fact, I obtain all the records in table Rubrique.

List of Rubriques

It seems that I should override the form.Select but I have no idea how to perform that.

1

There are 1 best solutions below

0
Loran Miniuk On

For the community:

First point was to select the items Rubrique:

def __init__(self, *args, **kwargs):
    communaute_id = kwargs.pop('communaute_id', None)
    super(DiscussionForm, self).__init__(*args, **kwargs)
    if communaute_id:
        self.fields['rubrique'].queryset = Rubrique.objects.filter(communaute=communaute_id)

This made the job !

You can refer to the following post Django ModelChoiceField: filtering query set and setting default value as an object

Consequently, need to render the template as following

return render(request, 'communaute/discussions/list_discussions.html', {
    ...
    'form_discussion': DiscussionForm(communaute_id=communaute.id),
    ...
    })

Second point was to initialize with one item in the list: Unfortunately I could not succesfully use the initial keyword in my widget definition. So i stated'required': True

    widgets = {
        'rubrique': forms.Select(attrs={
            'class': 'form-control',
            'required': True,
        }),
    }

which provided the applicative result expected