Django Exception Type: MultiValueDictKeyError - django

I am using Django 1.6. And I am experiencing the error
**Exception Type**: MultiValueDictKeyError
**Exception Value**:"'chat_room_id'"
in the mentioned part of the code. Can anyone help me out regarding this?
#login_required
def join(request):
'''
Expects the following POST parameters:
chat_room_id
message
'''
p = request.POST
r = Room.objects.get(id=int(p['chat_room_id']))
r.join(request.user)
return HttpResponse('')

Seems like chat_room_id is not in p. request.POST is a MultiValueDict. It has a .get() method to fetch the values. Use that with a default value so that if there is no value for the key, you can use a default value. E.g.
#login_required
def join(request):
'''
Expects the following POST parameters:
chat_room_id
message
'''
p = request.POST
room_id = p.get('chat_room_id', False)
# ------------------------------^ Returns False if `chat_room_id` is not in `p`
if room_id:
r = Room.objects.get(id=int(room_id))
r.join(request.user)
else:
# throw error
return HttpResponse('')

Related

Django: 'Q' object is not iterable

I have following APIView:
class SubmitFormAPIView(APIView):
def put(self, request, pk):
# some other codes
form = Form.objects.get(id=pk)
tu_filter, target_user = self._validate_target_user(request, form)
user_status, created = UserFormStatus.objects.get_or_create(
tu_filter,
form_id=pk,
user_id=request.user.pk
)
# Some other codes.
def _validate_target_user(request, form):
if some_conditions:
return Q(), None
else:
try:
target_user_id = int(request.GET.get('target_user_id))
except ValueError:
raise ValidationError()
target_user = get_user_model().objects.get(id=target_user_id)
return Q(target_user_id=target_user_id), target_user
but when django wants to execude get_or_create method, raises following error:
TypeError: 'Q' object is not iterable
Note: If _validate_target_user() returns Q(), None, no errors raised and view works fine. The error will be raised when return Q(target_user_id=target_user_id), target_user is returned.
I know, question information is not completed, just I want to know, what may cause this error?
From the source of get_or_create(...), def get_or_create(self, defaults=None, **kwargs):
which indicating that the get_or_create(...) doesn't not accept any args unlike the get() or filter(...) methods.
Since your are executing the function as below, Python thinks that the tu_filter is the value for default parameter, which is expected to be an iterable.
get_or_create(
tu_filter,
form_id=pk,
user_id=request.user.pk
)
Instead of returning a Q object, you can also just pass a dictionary of filters instead, like
{ 'target_user_id': target_user_id }
The you can run the get_or_create with **tu_filter as arguments, bypassing the need for Q.
class SubmitFormAPIView(APIView):
def put(self, request, pk):
# some other codes
form = Form.objects.get(id=pk)
tu_filter, target_user = self._validate_target_user(request, form)
user_status, created = UserFormStatus.objects.get_or_create(
**tu_filter,
form_id=pk,
user_id=request.user.pk
)
# Some other codes.
def _validate_target_user(request, form):
if some_conditions:
return {}, None
else:
try:
target_user_id = int(request.GET.get('target_user_id))
except ValueError:
raise ValidationError()
target_user = get_user_model().objects.get(id=target_user_id)
return { 'target_user_id': target_user_id }, target_user
Edit: As to what causes the error, my guess would be that using Q as part of your get_or_create statement is unclear to Django, because it doesn't know what to do with it in case the object needs to be created. A better approach would therefor be:
UserFormStats.objects.filter(tu_filter).get_or_create(form_id=pk, user_id=request.user.pk)

Pass parameter to cursor.execute in Django

I have the following view definition Django
def getEiNumberByFeatures(request):
# request should be ajax and method should be GET.
if request.is_ajax and request.method == "GET":
# get the nick name from the client side.
id = request.GET.get("id", None)
sqlQuery = """SELECT names
FROM Costumer
WHERE id = %s """
cursor.execute(sqlQuery, (id))
eiNumbers = cursor.fetchall()
context = {"EiNumber": eiNumbers}
return JsonResponse(context, status=200)
I am getting the following error
pyodbc.ProgrammingError: ('The SQL contains 0 parameter markers, but 1 parameters were supplied', 'HY000')
Have somebody any idea why this can happens? Even when I am sending the parameter
first is necessary to convert to JSON Serializer
for ei in eiNumbers:
data.append(list(ei))
context = {"EiNumber": data}

Django TypeError missing 1 required positional argument when trying to use form input in another function

I'm really a noob.
What I'm trying to do is to use an input (a category to display) from a ModelForm and pass it to another function, which would render a table accordingly on the next page.
Here is the first function from my views.py
def index(request):
form1 = PrimarySearchForm(request.POST)
if form1.is_valid():
return results(request, form1.cleaned_data['actor'])
template = 'main/index.html'
context = {'form1': form1}
return render(request, template, context)
Here is the second function from views.py
def results(request, actor):
table = FactTable(Sawn_Areas_Fact.objects.get(actors=actor))
RequestConfig(request).configure(table)
return render(request, 'main/results.html', {'table': table})
Here is the form
class PrimarySearchForm(forms.ModelForm):
class Meta:
model = Actors_Dim
fields = ('actor',)
So, when I run the server, select an entry and click submit I get the following error message:
TypeError: results() missing 1 required positional argument: 'actor'
[29/Jul/2018 17:10:04] "POST /results/ HTTP/1.1" 500 59914
Thanks in advance for any help!
Your code is not doing what you claim it is. The log shows that your form is not posting to the index view at all; it is posting to the results view. This is certainly because that is what you have put in the action attribute of the form tag in the template.
Actually, you shouldn't be doing either of these; you should be posting to index, but then redirecting to results when the form is valid.
is the actor field required in the ModelForm? form1.cleaned_data['actor'] returns an empty string that's why you get this error. Make a print statement and check if form1.cleaned_data['actor'] is returning a string as expected.

How do I filter sensitive Django POST parameters out of Sentry error reports?

To quote the Django docs:
#sensitive_post_parameters('pass_word', 'credit_card_number')
def record_user_profile(request):
UserProfile.create(user=request.user,
password=request.POST['pass_word'],
credit_card=request.POST['credit_card_number'],
name=request.POST['name'])
In the above example, the values for the pass_word and credit_card_number POST parameters will be hidden and replaced with stars (******) in the request’s representation inside the error reports, whereas the value of the name parameter will be disclosed.
To systematically hide all POST parameters of a request in error reports, do not provide any argument to the sensitive_post_parameters decorator:
#sensitive_post_parameters()
def my_view(request):
...
As a test, I added the following code to my Django 1.6 application:
views.py:
#sensitive_post_parameters('sensitive')
def sensitive(request):
if request.method == 'POST':
raise IntegrityError(unicode(timezone.now()))
return render(request, 'sensitive-test.html',
{'form': forms.SensitiveParamForm()})
forms.py:
class SensitiveParamForm(forms.Form):
not_sensitive = forms.CharField(max_length=255)
sensitive = forms.CharField(max_length=255)
When I submit this form via POST, I can see the values of both fields (including sensitive) clear as day in the Sentry report.
What am I doing wrong here? I'm using Django 1.6 and Raven 3.5.2.
Thanks in advance for your help!
Turns out that this stemmed from a bug in Django itself!
If you haven't changed DEFAULT_EXCEPTION_REPORTER_FILTER in your settings file, you get the default filter of SafeExceptionReporterFilter.
If you've used the sensitive_post_parameters decorator, this will result in your calling SafeExceptionReporterFilter's get_post_parameters method:
def get_post_parameters(self, request):
"""
Replaces the values of POST parameters marked as sensitive with
stars (*********).
"""
if request is None:
return {}
else:
sensitive_post_parameters = getattr(request, 'sensitive_post_parameters', [])
if self.is_active(request) and sensitive_post_parameters:
cleansed = request.POST.copy()
if sensitive_post_parameters == '__ALL__':
# Cleanse all parameters.
for k, v in cleansed.items():
cleansed[k] = CLEANSED_SUBSTITUTE
return cleansed
else:
# Cleanse only the specified parameters.
for param in sensitive_post_parameters:
if param in cleansed:
cleansed[param] = CLEANSED_SUBSTITUTE
return cleansed
else:
return request.POST
The problem with the above is that while it will correctly return a QuerySet with the sensitive POST parameters set to CLEANSED_SUBSTITUTE ('********************')...it won't in any way alter request.body.
This is a problem when working with Raven/Sentry for Django, because it turns out that the get_data_from_request method of Raven's DjangoClient first attempts to get the request's POST parameters from request.body:
def get_data_from_request(self, request):
[snip]
if request.method != 'GET':
try:
data = request.body
except Exception:
try:
data = request.raw_post_data
except Exception:
# assume we had a partial read.
try:
data = request.POST or '<unavailable>'
except Exception:
data = '<unavailable>'
else:
data = None
[snip]
The fastest fix turned out to just involve subclassing DjangoClient and manually replacing its output with the cleansed QuerySet produced by SafeExceptionReporterFilter:
from django.views.debug import SafeExceptionReporterFilter
from raven.contrib.django.client import DjangoClient
class SafeDjangoClient(DjangoClient):
def get_data_from_request(self, request):
request.POST = SafeExceptionReporterFilter().get_post_parameters(request)
result = super(SafeDjangoClient, self).get_data_from_request(request)
result['sentry.interfaces.Http']['data'] = request.POST
return result

How to process Django validation errors

I'm having some trouble grokking Django forms and validation.
#views.py:
def create(request):
if request.method == 'POST':
form = CreateDocumentForm(request.POST)
if form.is_valid():
doc = Document.objects.create(name=form.cleaned_data['name'])
#snip
#forms.py:
class CreateDocumentForm(forms.ModelForm):
name = forms.CharField()
def clean_name(self):
cleaned_name = self.cleaned_data['name']
rgx = re.compile('^(\w|-|\.)+$')
if rgx.match(cleaned_name) == None:
raise ValidationError("invalidchars")
return cleaned_name
The logic is working properly, but I don't know how to tell which kind of VaidationError was raised. Also - This is handled by an Ajax request, so I won't be using templating in the repsonse. I need to get the status of what failed in this view.
thx
You generally won't see the ValidationErrors themselves. If you call form.is_valid, then the errors that occur during validation are all collected and returned to you as a dictionary, form.errors
You can check that dictionary for errors relating to any specific field. The result for any field with errors should be the string value of any ValidationErrors that were raised for that field.
In your view, then, if form.is_valid() returns False, then you can do this:
if 'name' in form.errors:
for err_message in form.errors['name']:
# do something with the error string