1

I'm trying to do something fairly simple. Allow a user to type in a text field the searchterm, and select the search field from a drop down box. But I seem to be getting the above error.

Template

<form method='post' action=''>
<input type='text' id='searchterm'>
<select id='searchfield'>
    <option value='username'>Username</option>
    <option value='status'>Status</option>
</select>
</form>

View

def existing(request):
        if request.method == 'POST':
                searchterm = request.POST['searchterm']
                searchfield = request.POST['searchfield']
                records = User.objects.filter(searchfield=searchterm)
        else:
                records = User.objects.all()
        return render_to_response('gpon_table.html',locals())

Models

class User(models.Model):
    username = models.CharField(max_length=50)
    status = models.CharField(max_length=50)

Perhaps I am doing something wrong in the view.

Any help much appreciated.

dlyxzen
  • 243
  • 7
  • 17

1 Answers1

5

I believe the problem might be with how you're asking User.objects to search data. Since you're trying to pass in a dynamic keyword into the filter, you might have to pass it in as a **kwargs instead of directly as a filter parameter. I suspect that Django is reading "searchfield" as the literal keyword field name to search for rather than reading its value.

This link might provide more clarity on a possible solution. https://stackoverflow.com/a/659419/1011998

Here's an example of how you might implement the dynamic field with your current code setup.

As always, sanitize and restrict user input, otherwise a malicious user may be able to expose sensitive data other than that which is intended for filtering. (note: this hasn't been tested locally)

searchterm = request.POST.get('searchterm')
searchfield = request.POST.get('searchfield', 'username')

# Better to replace/populate this with form field choices
available_fields = ['username', 'status']

if not searchfield in available_fields:
    searchfield = 'username'

kwargs = {'{0}__{1}'.format(searchfield, 'icontains'): searchterm}
records = User.objects.filter(**kwargs)
Community
  • 1
  • 1
Tim Selaty Jr.
  • 599
  • 4
  • 6
  • 1
    You **do** realize this would allow any malicious user to search any of the fields from your model, traverse relationships, and potentially expose data that is meant to be private? Please, at least mention that **validation is required if using such a setup**. – Thomas Orozco Apr 19 '13 at 01:19
  • Thomas, the snippet of code provided was for example purposes in how baz00r might implement the kwargs with a dynamic parameter passed into it. I'd expect with any data passed from the client side to always be sanitized, constrained, and validated, which is not included in this example to avoid bogging it up. Thanks for noting the possibilities of attacks if the code isn't secure. I'll update the snippet to avoid confusion. Gracias. – Tim Selaty Jr. Apr 19 '13 at 01:33
  • Thanks for updating & upvoted your answer. Just putting it out there because using an ORM usually means that we're expecting security, validation & sanitization out of the box, which isn't there in this case ; ) – Thomas Orozco Apr 19 '13 at 02:24
  • Hey Tim, thanks so much for your reply. I understand what you are saying, and I was unfamiliar with the theory behind args/kwargs. After a bit of reading its starting to make more sense. The only part of your solution that I don't fully understand is the 'kwargs = {'{0}__{1}'.format(searchfield, 'icontains'): searchterm}' . Can you explain this to me in further detail? I do not understand what the '{0}__{1}' is doing? Again, thanks for the help so far. – dlyxzen Apr 19 '13 at 02:34
  • baz00r, no problem! In python, there is a series of shortcuts which help concatenate, or replace concatenation of strings. Instead of: kwargs = { searchfield + '__icontains': searchterm } a shortcut and more safe way of injecting variable data into strings might be: kwargs = {'{0}__{1}'.format(searchfield, 'icontains'): searchterm} In many instances, you may see people use: new_string = "%s__%s" % (searchfield, 'icontains') The end results should all be the same, just different ways of doing it with elegance. – Tim Selaty Jr. Apr 19 '13 at 04:37
  • To be clear, {0} and {1} stand for the variable positions in the format function which follows. (e.g. (searchfield, 'icontains')). It stands for "replace me {0} with the first argument of the format function" since list indexes start at 0. – Tim Selaty Jr. Apr 19 '13 at 04:44
  • Hi Tim, I understand, thank you for that explanation. I have implemented the code you suggested and it seems to work. You have put me on the right path. Thanks again. – dlyxzen Apr 19 '13 at 06:01
  • If you could, please mark this answer as the suitable answer for this question so others can look for the answer too. Thanks! – Tim Selaty Jr. Apr 20 '13 at 11:31