0

I am trying to query a table where I have many records with the same name, on purpose. In my example, I'm using the make of the car, and unfortunately I've already ruled out using a foreignkey. Long story. Anyway, I've been able to determine that I can query the table using a ModelChoiceField and using the distinct command as I'm using Postgresql as shown below:

class Vehicle(forms.Form):

    dropdown = forms.ModelChoiceField(queryset=Car.objects.none())

    def __init__(self, *args, **kwargs):
        super(Vehicle, self).__init__(*args, **kwargs)
        self.fields['dropdown'].empty_label = ''     
        qs = Car.objects.distinct('vehicle_make')  

The code above does what I need related to the dropdown, it limits the ModelChoiceField to just the unique values of the vehicle_make of the car.

The challenge is when I go to try to display all of the records with that vehicle_make in my template. I've tried to do a Detail View, but it is only showing me that individual record. That make sense since detail view is just for that record, but I'm trying to figure out how to query the table to show me all of the records with that vehicle_make. I've explored the ChoiceField as well, but can't seem to get this to work either. I've tried several variations of the code below in the template, but nothing seems to work.

{% for vehicle_make in car.queryset %}
   {{ vehicle_make }}
{% endfor %}

My model is as follows:

Car(models.Model):
    vehicle_make = models.Charfield(max_length=264,unique=False)

    def __str__(self):
        return self.vehicle_make

Thanks in advance for your input and suggestions.

Steve Smith
  • 1,019
  • 3
  • 16
  • 38

1 Answers1

0

You can query for all Car objects with a given value for vehicle_make with Car.objects.filter(vehicle_make = 'foo'). For example, this ListView would list all cars:

from django.views.generic.list import ListView
from .models import Car

class CarListView(ListView):
    context_object_name = "car_list"
    queryset = Car.objects.all()

Whereas this view would list all cars of make 'foo':

class FooCarListView(ListView):
    context_object_name = "car_list"
    queryset = Car.objects.filter(vehicle_make = 'foo')

One easy way to make this more "dynamic" would be to look for a search query in the url, either as a keyword argument or as a querystring. You could use your existing form to create a URL like this, then parse it in a view. For instance, this view would look for URLs appended with ?search=bar:

class SearchableCarListView(ListView):
    context_object_name = "car_list"
    def get_queryset(self):
        search_term = self.request.GET.get('search', None)
        if search_term is not None:
            return Car.objects.filter(vehicle_make = search_term)
        return Car.objects.all()

Your use case may be better served by using an icontains or iexact lookup, or even by making use of Django's full text search.

In the template for any of these views, you can access all of the Car objects in your queryset like so:

{% for car in car_list %}
    {{car}}
{% endfor %} 

I hope that I have understood and addressed your question. I am not 100% sure how you are using your form right now, so please let me know if I have overlooked anything there.


After our discussion in the comments, I think you are overcomplicating things with your form, and I think that your lookup might not be doing what you want.

We will get a ValuesQuerySet of all distinct vehicle_make values:

qs = Car.objects.values('vehicle_make').distinct()

(See: Select DISTINCT individual columns in django?)

This returns a ValuesQuerySet that looks like this:

<QuerySet [{'vehicle_make': 'vehicle_make_1'}, {'vehicle_make': 'vehicle_make_2'}...]

Where vehicle_make_1, vehicle_make_2 etc. are your distinct values.

We can give this queryset qs to our template and construct a select element. We could also simplify it first to a list of values to make it easier to work with in the template:

values_list = [ c['vehicle_make'] for c in qs.all() ]

Pass that value to our template and use it to make our select element:

<select name='search'>
    {% for vehicle_make in values_list %}
    <option value = {{vehicle_make}} > {{vehicle_make}} </option>
    {% endfor %}
</select>

From here you have several options. In my opinion, the simplest thing would be using this select element in a form that uses the GET method to construct a search URL like we discussed earlier. Check out the first answer to this question for more info: <form method="link" > or <a>? What's the difference? There is a code snippet in the first answer to that question that can easily be adapted to create a GET-based search form with your newly-created select element.

souldeux
  • 3,615
  • 3
  • 23
  • 35
  • Thanks for the response. I am using the form to try and get the value to feed to the ListView. In this case, should I then use the URL approach you suggest? You indicate I can use the same form, but do I need to create a new URL as well? – Steve Smith Nov 01 '17 at 16:54
  • You could use the value selected in your form to construct a URL like the one we've discussed. Then you could redirect your user to that URL, or use that URL to fetch data from your server to populate your existing template. The second approach would involve an AJAX request. – souldeux Nov 01 '17 at 16:58
  • Thanks for the help. I tested all of the code above and yes, I'm ultimately trying to do something dynamic, getting the vehicle_make in the drop down box and then trying to search the records with their details. I've seen the list is helpful, but I am ultimately trying to get all of the records from one table with all of their attributes, essentially all of the records in a detail view after the user selects the value in the dropdown. I'm new to Django...I just need to add the search value into the URL in order to get the detailed view for the records? – Steve Smith Nov 01 '17 at 17:29
  • Take some time to read up on the difference between a ListView and a DetailView: https://docs.djangoproject.com/en/1.11/ref/class-based-views/generic-display/#detailview. These views will return the things you tell them to return; the example I've given shows one way to filter the queryset a ListView returns. I hope this helps. – souldeux Nov 01 '17 at 17:37
  • souldeux Thanks again for the help. I'm pretty comfortable with the difference between the views. The issue I'm having is that I can't get the dropdown form to limit my selection. The ListView approach you suggested seems to be giving me all of the records unless I hardcode a value in the filter. I'm trying to do the dynamic approach you've suggested, just need to work through the URL piece. – Steve Smith Nov 01 '17 at 17:45
  • I can't seem to get it to work. I've been researching many options but this seems to be more complicated than it should be. I'm trying to basically populate a drop down box with distinct values from a ModelChoiceField but then can seem to be able to use those values. Perhaps I need to reevalutate my whole foreignkey issue? Is there a simple way to leverage duplicate names in a table without a foreign key? – Steve Smith Nov 01 '17 at 18:49
  • To be honest I think you need to refactor a good bit of your current approach. Carefully read the documents on using `distinct` - does this lookup really do what you want, or should you be using `values` as well? https://stackoverflow.com/questions/3852104/select-distinct-individual-columns-in-django – souldeux Nov 01 '17 at 18:54
  • Is using a ChoiceField a better approach? I'm experimenting with that presently. I am now able to get the values as distinct values, and am now trying to see how to leverage that data and use it to look up the records I am interested in. – Steve Smith Nov 01 '17 at 19:01
  • StackOverflow tends to frown on extended discussions in the comments such as this. I will edit some information into my answer. – souldeux Nov 01 '17 at 19:07
  • I appreciate your help. I am pursuing alternate methods as this is very complicated. Thanks for your time today. – Steve Smith Nov 01 '17 at 21:28