Search code examples
djangofilterdrop-down-menudjango-formschoicefield

Django : Dynamically update front end dropdown based on the end user's data in a product model


I would like to have dropdowns filters for users browsing their book collection. The dropdown values are currently populated with every corresponding field value in the model, I only want users to get values relevant to them e.g. I have only publisher associatted to my books, 'Marvel', so I should only see Marvel in the publisher drop down when I go to filter my books.

I am not able to pass the user value to the form drop downs, even after setting up the initialization function. I keep getting error no such attribute as 'uid' or'user' in the view when I am passing the value to the form.

Models.py

class ComicInput(models.Model):
        Publisher = models.CharField(max_length=20, default='Marvel', choices=Publisher_Choices, null=True, blank=True )
        Title = models.CharField(max_length=50,default='', blank=False)
        Type = models.CharField(max_length=30, choices=Type_Choices, null=True, blank=True ) #default='Reg'
        Number = models.IntegerField(default='', blank=False)
        Category = models.CharField( max_length=12,default="Hold",choices=Category_Choices,blank=True, null=True)
        uid = models.ForeignKey(User,on_delete=models.CASCADE, editable=False) #default=False, null=True)

        def __unicode__(self):
            return '%s %s %s' % (self.uid,self.Title, self.Number, self.Grade, self.Series, self.CoverPic, self.Category)

        class Meta:
            ordering = ('Title', 'Series', 'Number')

Views.py

###################### Collection Viewer #############

@login_required(login_url="/login/") 
def ComicInventory(self):

    title_list = TitleChoiceField()
    publisher_list = PublisherChoiceField()
    sellingnotes_list = NotesChoiceField()
    category_list = CategoryChoiceField()

    if self.GET.get('titles'): # On screen drop down Filter for titles
        selected_title = self.GET.get('titles')
        displayInventory=ComicInput.objects.filter(Title=selected_title,uid=self.user)
        DisplaySumValue=ComicInput.objects.all().filter(Title=selected_title,uid=self.user).aggregate(Sum('Value'))
       
    else:
        displayInventory=ComicInput.objects.filter(uid=self.user)
        DisplaySumValue=ComicInput.objects.all().aggregate(Sum('Value'))
    context = {
        'displayInventory': displayInventory,
        'DisplaySumValue': DisplaySumValue,
        'title_list': title_list,
    }

    return render(self, 'app/viewer.html',context)

HTML

<body>
    <h1><Strong>Here are your comics;</Strong></h1>
    <div class="panel-heading">
        **<!.. this is the Choice Field on HTML ..!>**           
        <div class="panel-title pull-left">
            <form method="get" action="{% url 'ComicInventory' %}">
                {{ category_list }}
                <input type="submit" value="Filter">
            </form>
        </div>
        

    <div class="container">
    <table class="table table-striped">
        <thead class="thead-dark">
            <tr>
                <th scope="col">Publisher</th>
                <th scope="col">Title</th>
                <th scope="col">Number</th>
                <th scope="col">Edition</th>
            </tr>
        </thead>
        {% for inv in  displayInventory %}
        <tbody class="table table-hover">
            <tr>
                <td>{{inv.Publisher}}</td>
                <td>{{inv.Title}}</td>
                <td>{{inv.Number}}</td>
                <td>{{inv.Edition}}</td>
alt="{{inv.Publisher}} image",height="60", width="100" /></a></td>
                <td> <a href="/edit/{{inv.id}}">Edit</a> </td>
                <td> <a href="/delete/{{inv.id}}">Delete</a> </td>
                
            </tr>
            
            {% endfor %}
       
        </tbody>
        <tfoot>
           <tr>
               <td><b>Total Value: {{DisplaySumValue}} </b></td>
           </tr>
        </tfoot>
    </table>



    </div>
</body>

EDIT Form.py ##Updated Model ChoiceField that initiates self, so I can get the user and pass it to the view ##

class TitleChoiceField(forms.Form):

    class Meta:
        model = ComicInput
        fields = ('Title', 'uid',)
    
    def __init__(self,uid, *args, **kwargs):
        super(TitleChoiceField, self).__init__(*args, **kwargs)
        self.fields['titles'].queryset=ComicInput.objects.filter(uid=self.user).values_list("Title", flat=True).distinct().order_by('Title')

Solution

  • Django AttributeError: Form object has no attribute '_errors'

    Updated the forms like so based on the above post:

    Forms.py

    class TitleChoiceField(forms.Form):
        
    
        class Meta:
            model = ComicInput
            fields = ('Title','uid',)
        
        titles = forms.ModelChoiceField(queryset =ComicInput.objects.all())
    
        def __init__(self, uid=None, *args, **kwargs):
            super(TitleChoiceField, self).__init__(*args, **kwargs)
            
            self.user = uid
            usrqry = ComicInput.objects.filter(uid=self.user).values_list('Title', flat=True).distinct().order_by('Title')
            
            self.fields['titles'].queryset=usrqry