pythondjangopostgresqldjango-formsdjango-postgresql

Render dropdown in django view using values from postgres arrayfield


Here is an example from the model:

class Shipment(models.Model):
    shipment_id = models.BigAutoField(null=False, primary_key=True)
    potential_shipping_dates = ArrayField(models.DateField(), verbose_name='Ship Dates', null=True)

Here is what I'm sort of attempting in my form:

class ShippingForm(forms.Form):
    potential_shipping_dates = forms.ModelChoiceField(queryset=Shipment.objects.all())
    def __init__(self, *args, **kwargs):
        super(ShippingForm, self).__init__(*args, **kwargs)

And here is where my form is added to context:

context['shippingForm'] = ShippingForm(initial=??what_goes_here_maybe??)

My form renders fine but I want to show a dropdown with a date for each option.


Solution

  • Okay this is a bit complex, but I think I understand what you're trying to do, and where you're going wrong.

    So you have a Shipment model, and each Shipment instance has a field with a few different potential_shipping_dates.

    Say you have 2 shipments:

    IN : ship1 = Shipment.objects.first()
    OUT:
    
    IN : ship1.potential_shipping_dates
    OUT: ['01/01/2021', '02/02/2021']
    
    IN : ship2 = Shipment.objects.last()
    OUT:
    
    IN : ship2.potential_shipping_dates
    OUT: ['03/03/2021', '04/04/2021']
    

    Now, do you want the dropdown to have all 4 dates as possibilities, and that will select the Shipment?

    Or do you want to select a date after selecting the shipment in the form?

    ^^ Answered in comments

    Okay so you will need to pass the instance through to the form:

    views.py

    # Inherit from Django's UpdateView to have `instance` passed through to the form
    class ShippingFormView(UpdateView):
        model = Shipment
        form_class = ShippingForm
    
    
    # Or if you don't want to inherit from inherit from UpdateView
    class ShippingFormView(Blah):
        model = Shipment
        form_class = ShippingForm
    
        def get_form_kwargs(self):
            kwargs = super().get_form_kwargs()
            kwargs['instance'] = self.get_object()
            return kwargs
    
    
    # Or if you're using function based views
    def shipping_form_view(request, pk):
        shipment = get_object_or_404(Shipment, pk=pk)
        form = ShippingForm(request, instance=shipment)
        ...
    
    

    forms.py

    class ShippingForm(forms.Form):
        potential_shipping_dates = forms.ChoiceField(choices=[])
    
        def __init__(self, *args, instance, **kwargs):
            super(ShippingForm, self).__init__(*args, **kwargs)
            self.fields['potential_shipping_dates'].choices = ((dt, dt) for dt in instance.potential_shipping_dates)
    

    ModelChoiceFields are used when selecting an object, not an attribute on one.