Pass parameter to cursor.execute in Django - 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}

Related

django send json patch request during test

I am using django 3.0. Here is my view that I am trying to test:
def myview(request):
values = {}
if request.method == 'PATCH':
keys = QueryDict(request.body)
print(keys)
for key in keys:
cache.set(key, keys[key], timeout=300)
values[key] = keys[key]
return JsonResponse(values, status=200)
and my test case:
class ValueViewTestCase(TestCase):
def setUp(self):
self.c = Client()
def test_value_updated(self):
data = {'key_1': 'updated_val'}
response = self.c.patch('/values/', data)
print(response.json())
# self.assertEqual(response.json(), data) # ->> test failing
console logs:
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
<QueryDict: {'{"key_1": "updated_val"}': ['']}>
{'{"key_1": "updated_val"}': ''}
I want to send data as key value pair, but somehow it malformed , right now whole request acting as a key.
Your data format is wrong.
A querydict would not contain a json, but a sequence of request parameters like key_1=1&key_2=2&key3=3. Try this:
def test_value_updated(self):
data = 'key_1=1&key_2=2&key3=3'
response = self.c.patch('/values/', data)
print(response.json())
Hope this helps.

REQUEST certain Elements in Django POST API from User

I want to Request a dictionary like
{
"username": "a",
"password": "b",
"year": "2019-20",
"start": 1,
"end": 2,
"reference_id": "two"
}
from a user so that a user can hit the API and get the desired result.
My view looks like
def post(self,request, *args, **kwargs):
# self.http_method_names.append("post")
user = request.POST.get("user")
pasd = request.POST.get("pasd")
year = request.POST.get("year")
start = request.POST.get("start")
end = request.POST.get("end")
reference_id = request.POST.get("reference_id")
#Passing the parameters to another function to get the result.
status = main_function(user=user,pasd=pasd,year=year,start=start,end=end,reference_id=reference_id)
return Response(status)
Now the problem when I'm posting something in Django like
I'm getting None in every field. Ideally, I should get the values passed in the Dictionary.
Can someone please help me here.
In django rest framework, you should use request.data instead of request.POST, as it requires parser to receive JSON data. More info can be found in drf docs.
Change your code to:
def post(self,request, *args, **kwargs):
# self.http_method_names.append("post")
user = request.data.get("username") # <-- this used incorrect key
pasd = request.data.get("password") # <-- this used incorrect key
year = request.data.get("year")
start = request.data.get("start")
end = request.data.get("end")
reference_id = request.data.get("reference_id")
#Passing the parameters to another function to get the result.
status = main_function(user=user,pasd=pasd,year=year,start=start,end=end,reference_id=reference_id)
return Response(status)
I Got The Answer. SO if You Want to take input from a user then You should write this in your views.py file.
But First you have to tell Django Which Fields input you want. So you have to create a serializer.py file in the Django APP.
from rest_framework import serializers
class userdetailSerializer(serializers.Serializer):
username = serializers.CharField(max_length=20)
password = serializers.CharField(max_length=20)
year = serializers.CharField(max_length=8)
start = serializers.IntegerField()
end = serializers.IntegerField()
reference_id = serializers.CharField(max_length=50)
I need all the Above values from the User that's why i have added all. If you want Only certain values you can delete it from your serializer file.
After this goto your Views.py file and get the response entered by user using below code.
Serializer will autovalidate the input and if the input is not correct it will give a dictionary of error(In else Statement)
def post(self,request, *args, **kwargs):
# self.http_method_names.append("post")
serializer = self.serializer_class(data=request.data)
if serializer.is_valid():
username = serializer.validated_data.get('username')
password = serializer.validated_data.get('password')
year = serializer.validated_data.get('year')
start = serializer.validated_data.get('start')
end = serializer.validated_data.get('end')
reference_id = serializer.validated_data.get('reference_id')
response_status = main_function(user=username, pasd=password,year=year,start=start,end=end,reference_id=reference_id)
return Response("The File Upload Response Will Come HEre",response_status)
# return Response({'name':username, 'pass':password,'year':year,'start':start,'end':end,'reference_id':reference_id})
else:
return Response(serializer.errors)
The POST API will LOOk Like this.
If you guys are facing an error here then Plese comment.
Upvote if it helps.

Django 1.11: "global name 'user' is not defined"

I have a survey app - you create a Survey and it saves the Response. It's registered in Django Admin. I can see the Survey and submit a Response. When I click Response in Admin, I get the following error:
ValueError at /admin/django_survey/response/
Cannot query "response 5f895af5999c49929a522316a5108aa0": Must be "User" instance.
So I checked the SQL database and for django_survey_response I can see that there is a response, but the column user_id is NULL.
I suspected that there's an issue with my Views and/or Forms and I'm not saving the logged in User's details, so I've tried to address that.
However, now I get
NameError at /survey/1/
global name 'user' is not defined
How do I resolve this? I want the form to save Response with the logged in user's ID.
The Traceback:
django_survey\views.py
def SurveyDetail(request, id):
survey = Survey.objects.get(id=id)
category_items = Category.objects.filter(survey=survey)
categories = [c.name for c in category_items]
print 'categories for this survey:'
print categories
if request.method == 'POST':
form = ResponseForm(request.POST, survey=survey) <.........................
if form.is_valid():
response = form.save()
return HttpResponseRedirect("/confirm/%s" % response.interview_uuid)
else:
form = ResponseForm(survey=survey)
print form
django_survey\forms.py
def __init__(self, *args, **kwargs):
# expects a survey object to be passed in initially
survey = kwargs.pop('survey')
self.survey = survey
self.user = user <.........................
super(ResponseForm, self).__init__(*args, **kwargs)
self.uuid = random_uuid = uuid.uuid4().hex
# add a field for each survey question, corresponding to the question
# type as appropriate.
data = kwargs.get('data')
It might be worth noting that previously, instead of user, the model's field was called interviewee. I changed this and ran migrations again.
I am also using userena.
The error message in this instance is python trying to tell you that you are attempting to access a variable user that has not been defined in the scope of your method.
Let's look at the first few lines of the __init__() method:
def __init__(self, *args, **kwargs):
# expects a survey object to be passed in initially
survey = kwargs.pop('survey')
self.survey = survey
self.user = user
We can see where the survey variable is defined: survey = kwargs.pop('survey'). It is passed into the form as a keyword argument and extracted in the forms __init__. However underneath you attempt to do the same thing with user but haven't actually defined it above. The correct code would look like:
def __init__(self, *args, **kwargs):
# expects a survey object to be passed in initially
survey = kwargs.pop('survey')
user = kwargs.pop('user')
self.survey = survey
self.user = user
However, this still won't work because we aren't passing the user variable to the form via kwargs. To do that we pass it in when we initialise the form in your views.py. What isn't clear is what user object you are expecting to pass in. the request.user? or does the Survey object have a user attribute? in which case you would not need to pass user in and would just use survey.user etc.
django_survey\views.py
def SurveyDetail(request, id):
survey = Survey.objects.get(id=id)
category_items = Category.objects.filter(survey=survey)
categories = [c.name for c in category_items]
print 'categories for this survey:'
print categories
if request.method == 'POST':
form = ResponseForm(request.POST, survey=survey, user=request.user)
if form.is_valid():
response = form.save()
return HttpResponseRedirect("/confirm/%s" % response.interview_uuid)
else:
form = ResponseForm(survey=survey, user=request.user)
print form
In your view when you initialize your form you need to pass it the user (current user in this case)? similar to this form = ResponseForm(request.POST, survey=survey, user=request.user). Then in the __init__ of your form pop the user object user = kwargs.pop('user'). I believe that will resolve your issue.

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