How do I accept multiple choices for a Charfield from CheckboxSelectMultiple widget in Django?

402 views Asked by At

I'm trying to build a form in Django 1.11, where I have a set of checkboxes on a watch list to allow a user to set multiple alerts on an item they want to receive notifications on later. However, I'm not sure how to represent multiple options on a field like this.

Here's my model code:

class Watchlist(models.Model):

    CLOSES_IN_2_WEEKS, CLOSES_IN_1_WEEKS, CLOSES_IN_3_DAYS, CLOSES_TOMORROW = (
        "CLOSES_IN_2_WEEKS",
        "CLOSES_IN_1_WEEKS",
        "CLOSES_IN_3_DAYS",
        "CLOSES_TOMORROW"
    )

    ALERT_OPTIONS = (
        (CLOSES_IN_2_WEEKS, "Closes in 2 weeks",),
        (CLOSES_IN_1_WEEKS, "Closes in 1 weeks",),
        (CLOSES_IN_3_DAYS, "Closes in 3 days",),
        (CLOSES_TOMORROW, "Closes tomorrow",),
    )

    # I want to store more than one option
    alert_options = models.CharField(max_length=255, blank=True)


    def save(self):
        """
        If this is submitted create 1 alert:

        "CLOSES_IN_1_WEEKS"

        If this submitted, create 3 alerts:

        "CLOSES_IN_2_WEEKS",
        "CLOSES_IN_1_WEEKS",
        "CLOSES_IN_3_DAYS",

        """

        # split the submitted text values, to create them

        # yes, this should probably be a formset. I wasn't sure how I'd
        # handle the logic of showing 4 optional alerts, and only creating models
        # on the form submission, and remembering to delete them when a user
        # unchecked the choices in the form below

And here's the form I'm using, below. I'm hooking into the __init__ method to pre-populate the form with possible choices.

class WatchlistForm(forms.ModelForm):

    alert_options = forms.ChoiceField(
        choices=[],
        label="Alert Options",
        required=False,
        widget=forms.CheckboxSelectMultiple(),
    )

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
            self.fields["alert_options"].choices = WatchlistForm.ALERT_OPTIONS

    def clean_alert_options(self):

        # I'm dropping into ipython to look around here
        import ipdb; ipdb.set_trace()

        return data["alert_options"]

    class Meta:
        model = WatchlistForm
        fields = ("alert_options")

This currently works fine for a single checked checkbox, but once I have more than one, only the last choice is selected, and I can't quite figure out how to access it.

How can I capture all the choices here, rather than just the one?

I'm aware I probably should be using a formset here. The thing is it wasn't obvious to me how to create a set of pre-populated formset options to represent some active and some inactive alert choices.

Using a test to show what I'm going for

If it helps, I'm trying to save the information so it would be stored like so - I've added some pseudo code based on me using pytest in a test suite.

def test_form_accepts_multiple_alert_values(self, db, verified_user):

    form_data = {
        "user_id": verified_user.id,
        "alert_options": "CLOSES_IN_2_WEEKS CLOSES_IN_3_DAYS",
    }

    submission = forms.WatchlistForm(form_data)
    instance = submission.save()

    assert instance.alert_options == "CLOSES_IN_2_WEEKS CLOSES_IN_3_DAYS",
0

There are 0 answers