Home > front end >  How do I make a post request work after using get_queryset?
How do I make a post request work after using get_queryset?

Time:12-06

I would like to have a list of a user's devices with a checkbox next to each one. The user can select the devices they want to view on a map by clicking on the corresponding checkboxes then clicking a submit button. I am not including the mapping portion in this question, because I plan to work that out later. The step that is causing problems right now is trying to use a post request.

To have the user only be able to see the devices that are assigned to them I am using the get_queryset method. I have seen a couple questions regarding using a post request along with the get_queryset method, but they do not seem to work for me. Using the view below, when I select a checkbox and then click submit, it looks like a post request happens followed immediately by a get request and the result is my table is empty when the page loads.

Portion of my views.py file:


class DeviceListView(LoginRequiredMixin, ListView):
    model = Device
    template_name = 'tracking/home.html'
    context_object_name = 'devices'

    def get_queryset(self, *args, **kwargs):
        return super().get_queryset(*args, **kwargs).filter(who_added=self.request.user)       

    def post(self, request):
        form = SelectForm(request.POST)   
        return render(request, self.template_name, {'form': form})


Portions of my template:

                <div >
                    <form action="" method="post" name="devices_to_check"> 
                        {% csrf_token %}
                        <table id="registered_devices" 
                         
                        style="width:100%; border: 1px solid black; font-size: 10px">
                            <thead  
                            style="text-align:center; border: 1px solid black">
                                <tr>
                                    <th>IMEI</th>
                                    <th>Label</th>
                                    <th>Device Type</th>
                                    <th>Group</th>
                                    <th>Subgroup</th>
                                    <th>Description</th>
                                    <th>Display</th>
                                </tr>    
                            </thead>
                            
                            <tbody>
                                {% for device in devices %}
                                    <tr>
                                        <td>{{device.imei}}</td>
                                        <td>{{device.label}}</td>
                                        <td style="text-transform:uppercase">{{device.device_type}}</td>
                                        <td>{{device.main_group}}</td>
                                        <td>{{device.subgroup}}</td>
                                        <td>{{device.description}}</td>
                                        <td style="text-align:center">
                                            <a href="{% url 'device-detail' device.id %}">i    </a>
                                            <input type="checkbox" id="{{device.imei}}" name="chk" 
                                            value="{{device.imei}}" onclick="show_info_icon()" 
                                            />
                                        </td>
                                    </tr>
                                {% endfor %}
                            </tbody>
                        </table>
                            <input type="button"  onclick='selects()' 
                            value="Select All"/>  
                            <input type="button"  onclick='deSelect()' 
                            value="Deselect All"/>                            
                            <button type="submit" >Show on Map</button>
                    </form>    
                </div>

CodePudding user response:

I think you're better off using a function based view with the typical "if request.method = POST" logic, this isn't really what the generic list view is for. (edits to snippet added)

@login_required
def device_list_view(request):
    context = {}
    if request.method == 'POST':
        form = SelectForm(request.POST)
        if form.is_valid():
            # if a request was posted and is valid, do your thing:
            # maybe your thing is to give your map view the device id
            # and render it
            # assuming your form has a field called device_id:
            context['device_id'] = form.device_id 
            return render(request, 'tracking/device_map.html', context)
   
    # either request method is not post or the form wasn't valid
    user_devices = Device.objects.filter(who_added=request.user)
    device_forms = []
    for i, device in enumerate(user_devices):
        form = SelectForm(instance=device, prefix=i)
        device_forms.append(form)
   context['device_forms'] = device_forms
  return render(request, 'tracking/home.html', context)
    

The key part here is the if-else logic of checking whether the request was POST or not, you'll need to tweak it based on exactly what you want to happen. It sounds like what you're really doing is creating one form from which you're pulling multiple device_ids. This is a good reference for what's going on with the prefix bit and should help you decide whether to do things that way or with one form like you're trying.

CodePudding user response:

you need to handle the post request in the get function of your view besides creating a separate post function because the get function is called when the page is loaded and then calls post function when you submit. Update your queryset when you submit the form and only to those selected devices and render the template with the new queryset. Anyways, you can do this just by doing conditions in your get function to see if the request is a post then update accordingly your queryset like so:

class DeviceListView(LoginRequiredMixin, ListView):
model = Device
template_name = 'tracking/home.html'
context_object_name = 'devices'

def get_queryset(self, *args, **kwargs):
    queryset = super().get_queryset(*args, **kwargs).filter(who_added=self.request.user)

    # If the request is a post request, update the queryset to only include the selected devices
    if self.request.method == 'POST':
        selected_devices = self.request.POST.getlist('chk')
        queryset = queryset.filter(imei__in=selected_devices)

    return queryset

def get(self, request, *args, **kwargs):
    form = SelectForm(request.POST or None)
    return render(request, self.template_name, {'form': form})
  • Related