I am making a post via jquery to my backend. I first look to see if a pledge has already been made. If not, I create one.
#csrf_exempt
def pledgeReceive(request):
fname = request.POST.get('fname', '')
lname = request.POST.get('lname', '')
participantName = request.POST.get('participantName', '')
participantID = request.POST.get('participantID', '')
ppl = request.POST.get('ppl', '')
maxi = request.POST.get('maxi', '')
sponsor = fname + ' ' + lname
participant_obj = Participant.objects.get(pk = participantID)
try:
pledge = Pledge.objects.get(sponsor = sponsor, participant = participant_obj, pledge_amount = ppl, max_pledge_amount = maxi, datetime = datetime.now())
except Pledge.DoesNotExist:
pledge = Pledge(sponsor = sponsor, participant = participant_obj, pledge_amount = ppl, max_pledge_amount = maxi, datetime = datetime.now())
pledge.save()
response = HttpResponse()
response.content = serialized_obj = serializers.serialize('json', [ pledge, ])
response['Content-Type'] = 'application/json'
return response
I get a 500 internal server error. With the following traceback:
ValidationError at /pledgeReceive/
No exception supplied
Traceback:
File "/home/vtrelayc/lib/python2.6/site-packages/django/core/handlers/base.py" in get_response
111. response = callback(request, *callback_args, **callback_kwargs)
File "/home/vtrelayc/lib/python2.6/site-packages/django/views/decorators/csrf.py" in wrapped_view
77. return view_func(*args, **kwargs)
File "/home/vtrelayc/projects/relay/relayapp/views.py" in pledgeReceive
461. pledge.save()
File "/home/vtrelayc/lib/python2.6/site-packages/django/db/models/base.py" in save
463. self.save_base(using=using, force_insert=force_insert, force_update=force_update)
File "/home/vtrelayc/lib/python2.6/site-packages/django/db/models/base.py" in save_base
551. result = manager._insert([self], fields=fields, return_id=update_pk, using=using, raw=raw)
File "/home/vtrelayc/lib/python2.6/site-packages/django/db/models/manager.py" in _insert
203. return insert_query(self.model, objs, fields, **kwargs)
File "/home/vtrelayc/lib/python2.6/site-packages/django/db/models/query.py" in insert_query
1593. return query.get_compiler(using=using).execute_sql(return_id)
File "/home/vtrelayc/lib/python2.6/site-packages/django/db/models/sql/compiler.py" in execute_sql
911. for sql, params in self.as_sql():
File "/home/vtrelayc/lib/python2.6/site-packages/django/db/models/sql/compiler.py" in as_sql
872. for obj in self.query.objs
File "/home/vtrelayc/lib/python2.6/site-packages/django/db/models/fields/__init__.py" in get_db_prep_save
873. return connection.ops.value_to_db_decimal(self.to_python(value),
File "/home/vtrelayc/lib/python2.6/site-packages/django/db/models/fields/__init__.py" in to_python
850. raise exceptions.ValidationError(msg)
Exception Type: ValidationError at /pledgeReceive/
I am providing an exception though with except Pledge.DoesNotExist:?
Why not just use get_or_create? It is a shortcut for what you are attempting to do.
pledge, created = Pledge.objects.get_or_create(sponsor = sponsor, participant = participant_obj, pledge_amount = ppl, max_pledge_amount = maxi, datetime = datetime.now())
Now you have a pledge object and a boolean, created, that lets you know whether the object was created or fetched.
Other than that, the error is probably caused by the fact that you are just getting the GET parameters without casting them to the types that your Pledge object expects. They are getting passed as strings even though most of your fields probably aren't expecting strings. Maybe use a form (for it's built in validation/type casting) or manually convert your GET parameters to the correct types.
ValidationError exception is raised when data fails form or model field validation but because your not using form.is_valid() or any validator which validate your input values this will result to No Exception Supplied. Even your Pledge.DoesNotExist cannot catch the error because it's only check when an object is not found for the given parameters of a query.
Based on your code, I found invalid values.
ppl = request.POST.get('ppl', '')
maxi = request.POST.get('maxi', '')
If I'm not wrong the code above pass an integer. But you didn't know your passing a string not an int. It must be,
ppl = int(request.POST.get('ppl', 0))
maxi = int(request.POST.get('maxi', 0))
I don't know your model code pattern, if your passing a value for foreignkey or date your must also check that because they are very sensitive. You don't have to worry about CharField because they can handle it unless if required. But I suggest you use form, if you can't handle this error.
Related
I have views like:
class StudentAPIPerformanceReport(
generics.RetrieveAPIView,
):
def get(self, request, *args, **kwargs):
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename="report.csv"'
writer = csv.writer(response)
for student in Student.objects.filter(pk=self.kwargs['pk']):
assigned_courses = CourseParticipant.objects.filter(student=student)
completed_courses = assigned_courses.filter(completed=True)
headings = (
"student full Name",
"number of assigned courses to student",
"number of completed courses by student"
)
rows = (
student.full_name,
assigned_courses.count(),
completed_courses.count()
)
writer.writerow(headings)
writer.writerow(rows)
return response
Urls:
path(
'student/report/<int:pk>/',
StudentAPIPerformanceReport.as_view(),
name='student_performance'
)
And test for it view:
class StudentAPIPerformanceReportTestCase(APITestCase):
def setUp(self):
self.student_obj = Student.objects.create(
first_name='test',
last_name='student',
email='test_student#gmail.com',
)
self.course_obj = Course.objects.create(
name='test',
)
student_obj = CourseParticipant.objects.create(
course_id=self.course_obj.pk,
student_id=self.student_obj.pk,
)
def test_student_unassigned_from_course(self):
data_id = self.student_obj.pk
rud_url = api_reverse('student:student_performance', kwargs={'pk': data_id})
get_response = self.client.get(rud_url, data_id)
self.assertEqual(get_response.status_code, status.HTTP_200_OK)
But i have Traceback:
Error
Traceback (most recent call last):
File "/home/project/test_task/student/tests.py", line 120, in test_student_unassigned_from_course
get_response = self.client.get(rud_url, data_id)
File "/home/project/test_task/venv/lib/python3.7/site-packages/rest_framework/test.py", line 292, in get
response = super(APIClient, self).get(path, data=data, **extra)
File "/home/project/test_task/venv/lib/python3.7/site-packages/rest_framework/test.py", line 199, in get
'QUERY_STRING': urlencode(data or {}, doseq=True),
File "/home/project/test_task/venv/lib/python3.7/site-packages/django/utils/http.py", line 93, in urlencode
for key, value in query:
TypeError: 'int' object is not iterable
Api which i wont to test just make some csv file in format:
test student,1,0
How i can test it? I will be grateful for the help
The error you are receiving is from the way you call self.client.get.
TypeError: 'int' object is not iterable
is about the second parameter that you are passing in this particular line:
get_response = self.client.get(rud_url, data_id)
# ______________________________________^
data_id itself is the student object's primary key, which is a simple integer id.
If you look closer at the Django docs here, the second parameter of get() is data, which is a dictionary, not an integer. That's why it tries to iterate this parameter, but it is not iterable.
Since you've already attached your primary key in the url (in the reverse()), there is no need to attach it as a query parameter of the GET request performed by self.client.get().
Once you remove data_id from the get() function call
get_response = self.client.get(rud_url)
it should work and you will successfully get the CSV file in the response, which you can test further.
I know, this problem happens because the code is trying to add an entry to the database with a combination of unique keys that already exist. But my question is: why and how can I prevent this? It doesn't make sense to me that this is happening, given my logic.
I have this piece of code that basically stores some static label for an invoice. The idea is to create the label on the fly if it doesn't exist, instead of manually inserting it in a lot of places in the code.
Whenever an Item is generated, an ItemInv is also created, and by saving the latter, I check if a static label exists. If it doesn't, a new one is created. The code to get (or create) the static label is also called when displaying an Invoice / Draft.
The error seems to happen right there. The label doesn't exist, a new one is created, but somehow this happens twice? I mean, I really don't get why that code would try to add the same item two times. Could it be a thread issue?
I am not using get_or_create because some attributes on ItemStaticInv (static_account_label, static_agreement_label...) can be updated and not unique. Before creating the invoice, a draft has the same structure and the data can be changed, including these labels.
class ItemInv(managers.Model):
"""
Relation between Item and Invoice
"""
item = models.ForeignKey('Item')
invoice = models.ForeignKey('Invoice')
[...]
class Meta:
unique_together = ('item', 'invoice')
def save(self, *args, **kwargs):
iteminv = super(ItemInv, self).save(*args, **kwargs)
# If the item does not have the static information, one should be created
self.item.get_invoice_static(self.invoice)
return iteminv
class Item(managers.Model):
"""
Item to be put on an invoice
"""
serial = models.AutoField(primary_key=True) # Software license
product = models.ForeignKey('Product', verbose_name='Product')
account = models.ForeignKey('Account', verbose_name='Account', related_name='items')
[...]
def get_invoice_static(self, document):
try:
return self.document_labels.get(invoice=document)
except ObjectDoesNotExist:
return ItemStaticLabel.objects.create(
item=self,
invoice=document,
static_account_label=str(self.account),
static_customer_label=str(self.account.customer),
static_agreement_label=str(self.account.agreement)
)
class ItemStaticLabel(managers.Model):
"""
We must store static information about the Item on an invoice.
"""
item = models.ForeignKey('Item', related_name='document_labels')
invoice = models.ForeignKey('Invoice', related_name='item_labels')
static_account_label = models.CharField(max_length=256, null=True, blank=True)
static_customer_label = models.CharField(max_length=256, null=True, blank=True)
static_agreement_label = models.CharField(max_length=256, null=True, blank=True)
static_expiration_label = models.DateField(max_length=256, null=True, blank=True)
class Meta:
unique_together = ('item', 'invoice')
This has several flaws, but this system was developed by someone else and is on production. The amount of structural changes I can do are pretty much limited. Therefore I gotta try to understand what is causing this issue.
Traceback:
File "/home/apps/sites/invoice/source/v3/models.py" in get_invoice_static
1105. return self.document_labels.get(invoice=document)
File "/home/apps/sites/invoice/env/lib/python3.4/site-packages/django/db/models/manager.py" in manager_method
85. return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/home/apps/sites/invoice/env/lib/python3.4/site-packages/django/db/models/query.py" in get
380. self.model._meta.object_name
During handling of the above exception (ItemStaticLabel matching query does not exist.), another exception occurred:
File "/home/apps/sites/invoice/env/lib/python3.4/site-packages/django/db/backends/utils.py" in execute
65. return self.cursor.execute(sql, params)
The above exception (duplicate key value violates unique constraint "v3_itemstaticlabel_item_id_f9405967_uniq"
DETAIL: Key (item_id, invoice_id)=(1840, 1578) already exists.
) was the direct cause of the following exception:
File "/home/apps/sites/invoice/env/lib/python3.4/site-packages/django/core/handlers/exception.py" in inner
41. response = get_response(request)
File "/home/apps/sites/invoice/env/lib/python3.4/site-packages/django/core/handlers/base.py" in _legacy_get_response
249. response = self._get_response(request)
File "/home/apps/sites/invoice/env/lib/python3.4/site-packages/django/core/handlers/base.py" in _get_response
187. response = self.process_exception_by_middleware(e, request)
File "/home/apps/sites/invoice/env/lib/python3.4/site-packages/django/core/handlers/base.py" in _get_response
185. response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/usr/local/lib/python3.4/contextlib.py" in inner
30. return func(*args, **kwds)
File "/home/apps/sites/invoice/env/lib/python3.4/site-packages/django/views/generic/base.py" in view
68. return self.dispatch(request, *args, **kwargs)
File "/home/apps/sites/invoice/env/lib/python3.4/site-packages/django/views/generic/base.py" in dispatch
88. return handler(request, *args, **kwargs)
File "/home/apps/sites/invoice/env/lib/python3.4/site-packages/django/views/generic/detail.py" in get
116. context = self.get_context_data(object=self.object)
File "/home/apps/sites/invoice/source/web/views/invoice.py" in get_context_data
280. context['document_html'] = services.document_to_html(obj)
File "/home/apps/sites/invoice/source/v3/services.py" in document_to_html
1550. 'account': set_[0].get_invoice_static(document).static_account_label,
File "/home/apps/sites/invoice/source/v3/models.py" in get_invoice_static
1112. static_agreement_label=str(self.account.agreement)
File "/home/apps/sites/invoice/env/lib/python3.4/site-packages/django/db/models/manager.py" in manager_method
85. return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/home/apps/sites/invoice/env/lib/python3.4/site-packages/django/db/models/query.py" in create
394. obj.save(force_insert=True, using=self.db)
File "/home/apps/sites/invoice/source/v3/managers.py" in save
724. super().save(*args, **kwargs)
File "/home/apps/sites/invoice/env/lib/python3.4/site-packages/django/db/models/base.py" in save
808. force_update=force_update, update_fields=update_fields)
File "/home/apps/sites/invoice/env/lib/python3.4/site-packages/django/db/models/base.py" in save_base
838. updated = self._save_table(raw, cls, force_insert, force_update, using, update_fields)
File "/home/apps/sites/invoice/env/lib/python3.4/site-packages/django/db/models/base.py" in _save_table
924. result = self._do_insert(cls._base_manager, using, fields, update_pk, raw)
File "/home/apps/sites/invoice/env/lib/python3.4/site-packages/django/db/models/base.py" in _do_insert
963. using=using, raw=raw)
File "/home/apps/sites/invoice/env/lib/python3.4/site-packages/django/db/models/manager.py" in manager_method
85. return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/home/apps/sites/invoice/env/lib/python3.4/site-packages/django/db/models/query.py" in _insert
1076. return query.get_compiler(using=using).execute_sql(return_id)
File "/home/apps/sites/invoice/env/lib/python3.4/site-packages/django/db/models/sql/compiler.py" in execute_sql
1107. cursor.execute(sql, params)
File "/home/apps/sites/invoice/env/lib/python3.4/site-packages/django/db/backends/utils.py" in execute
65. return self.cursor.execute(sql, params)
File "/home/apps/sites/invoice/env/lib/python3.4/site-packages/django/db/utils.py" in __exit__
94. six.reraise(dj_exc_type, dj_exc_value, traceback)
File "/home/apps/sites/invoice/env/lib/python3.4/site-packages/django/utils/six.py" in reraise
685. raise value.with_traceback(tb)
File "/home/apps/sites/invoice/env/lib/python3.4/site-packages/django/db/backends/utils.py" in execute
65. return self.cursor.execute(sql, params)
Exception Type: IntegrityError at /invoice-menu/customer/251/invoices/1578/
Exception Value: duplicate key value violates unique constraint "v3_itemstaticlabel_item_id_f9405967_uniq"
DETAIL: Key (item_id, invoice_id)=(1840, 1578) already exists.
View
class InvoiceDetailView(DetailView):
model = Invoice
template_name = 'invoice_detail.html'
pk_url_kwarg = 'invoice_key'
context_object_name = 'invoice'
def get_context_data(self, **kwargs):
context = super(InvoiceDetailView, self).get_context_data(**kwargs)
obj = context[self.context_object_name]
obj = models.Invoice.objects.filter(pk=obj.pk).select_related(
'customer',
'customer__original',
'currency',
).prefetch_related(
'citems',
'citems__assocs',
'citems__assocs__product',
'iteminv_set',
'iteminv_set__item',
).first()
context['document_html'] = services.document_to_html(obj)
return context
Services
def document_to_html(document):
"""
Renders the invoice to html.
"""
from v3.models import Item, Maintenance, Invoice, CustomInvoiceLine
from web.collection_utils import collapse_list
data = {}
items = Item.objects.on_invoice(document)
mains = Maintenance.objects.on_invoice(document)
rows = get_invoice_product_rows(document)
# merge the lists
rows['itemrows'].extend(rows['mainrows'])
include_summary = len(rows['itemrows']) > 0 and not Invoice.objects.filter(creditted_by=document)
# calc VAT lines
vats = {}
for ir in rows['itemrows']:
row = ir['line']
vat = ir['objs'][0].vat
rate = ir['objs'][0].vat_rate
total = (Decimal(rate / 100) * ir['rowtotal']).quantize(Decimal('.01'), rounding=ROUND_HALF_UP)
try:
vats[vat]['rownums'].append(row)
vats[vat]['total'] += total
except:
vats[vat] = dict(rownums=[row, ], message=ir['objs'][0].vat_message, total=total, rate=rate)
for mr in rows['mainrows']:
row = mr['line']
vat = mr['objs'][0].vat
rate = mr['objs'][0].vat_rate
total = (Decimal(rate / 100) * mr['rowtotal']).quantize(Decimal('.01'), rounding=ROUND_HALF_UP)
try:
vats[vat]['rownums'].append(row)
# Changed it to not add any value because that will produce wrong vat output.
vats[vat]['total'] += 0
except:
vats[vat] = dict(rownums=[row, ], message=mr['objs'][0].vat_message, total=total, rate=rate)
for cr in rows['citemrows']:
row = cr['line']
vat = cr['obj'].vat
rate = cr['obj'].vat_rate
total = (Decimal(rate / 100) * cr['rowtotal']).quantize(Decimal('.01'), rounding=ROUND_HALF_UP)
try:
vats[vat]['rownums'].append(row)
vats[vat]['total'] += total
except:
vats[vat] = [row, ]
vats[vat] = dict(rownums=[row, ], message=cr['obj'].vat_message, total=total, rate=rate)
vats = [(k, collapse_list(v['rownums']), v['message'], v['total'], v['rate']) for (k, v) in vats.items()]
vats = sorted(vats, key=lambda x: x[1])
# Gather data for the license agreement overview
# A list of lists, where the inner lists contain items that match on product and account
matched_item_sets = []
items = list(items) + list([m.serial for m in mains])
for item in items:
# Find a set to add this item to
for set_ in matched_item_sets:
if item.product == set_[0].product and item.account == set_[0].account:
if item not in set_:
set_.append(item)
break
else:
# No matching set found. Create a new one
matched_item_sets.append([item])
# Package the item sets nicely with meta information
summary = []
for set_ in matched_item_sets:
summary.append({
'account': set_[0].get_invoice_static(document).static_account_label,
'owner': set_[0].get_invoice_static(document).static_customer_label,
'agreement': set_[0].get_invoice_static(document).static_agreement_label,
'product': set_[0].product,
'licenses': collapse_list(set_),
})
data['inv'] = document
data['lines'] = rows['itemrows']
data['citems'] = rows['citemrows']
data['vats'] = vats
data['lagree'] = summary
data['includeSummary'] = include_summary
data['cilines'] = CustomInvoiceLine.objects.filter(invoice=document, on_invoice=True)
data['base_url'] = settings.SITE_BASE_URL
tpl = document.template
tpl = DjangoTemplate(tpl.content)
return tpl.render(Context(data))
How can i print the id from the response in the below code.The user does exist in the DB.Also i come across this error.
from django.test import Client
c = Client(enforce_csrf_checks=False)
response = c.post('/reg/_user/', {'firstname': 'test', 'lastname' : '_test'})
views get_user
def _user(request):
try:
response_dict = {}
qd = request.POST
firstname = qd.__getitem__('firstname')
lastname = qd.__getitem__('lastname')
up = UserProfile.objects.get(first_name=firstname,last_name=lastname)
print up.id
return up.id
except:
pass
Error:
response = c.post('/reg/_user/', {'firstname': 'test', 'lastname' : '_test'})
File "/usr/local/lib/python2.7/dist-packages/django/test/client.py", line 483, in post
response = super(Client, self).post(path, data=data, content_type=content_type, **extra)
File "/usr/local/lib/python2.7/dist-packages/django/test/client.py", line 302, in post
return self.request(**r)
File "/usr/local/lib/python2.7/dist-packages/django/test/client.py", line 444, in request
six.reraise(*exc_info)
File "/usr/local/lib/python2.7/dist-packages/django/core/handlers/base.py", line 201, in get_response
response = middleware_method(request, response)
File "/usr/local/lib/python2.7/dist-packages/django/middleware/clickjacking.py", line 30, in process_response
if response.get('X-Frame-Options', None) is not None:
AttributeError: 'UserProfile' object has no attribute 'get'
The problem is not with your tests, but with the view itself. In Django a view always has to return a HttpResponse object. Sometimes this is achieved using a shortcut function like render(), but it in turn also returns an HttpResponse object.
If for some reason you just want to return an otherwise empty page with this single value you could change
return up.id
to
return HttpResponse(up.id)
Also, I wonder: Did you create the view just to test UserProfile and don't use it as a view on the actual site? If so, this code doesn't belong in a view, it should be put into the unittest itself. You should only use the test client to test actual, real views.
On an mostly unrelated, but quite important note. This:
try:
# your view code
except:
pass
is a strong antipattern. Why would you want to silence all the potential problems? You should really stop doing that.
I'm building an API with Tastypie, and I've run into an issue when saving a many-to-many field.
I have a model call Pest and another called Call, and Call has a field called pests representing the pests that can be applied to a call. These already exist and the user can choose one or more to apply to that call - there is no intention to create them at the same time as the Call object.
By default, I get the following error when I try to create a new Call via POST:
{"error_message": "Cannot resolve keyword 'url' into field. Choices are: baitpoint, call, description, id, name, operator", "traceback": "Traceback (most recent call last):\n\n File \"/home/matthew/Projects/Pestability/venv/local/lib/python2.7/site-packages/tastypie/resources.py\", line 217, in wrapper\n response = callback(request, *args, **kwargs)\n\n File \"/home/matthew/Projects/Pestability/venv/local/lib/python2.7/site-packages/tastypie/resources.py\", line 459, in dispatch_list\n return self.dispatch('list', request, **kwargs)\n\n File \"/home/matthew/Projects/Pestability/venv/local/lib/python2.7/site-packages/tastypie/resources.py\", line 491, in dispatch\n response = method(request, **kwargs)\n\n File \"/home/matthew/Projects/Pestability/venv/local/lib/python2.7/site-packages/tastypie/resources.py\", line 1357, in post_list\n updated_bundle = self.obj_create(bundle, **self.remove_api_resource_names(kwargs))\n\n File \"/home/matthew/Projects/Pestability/venv/local/lib/python2.7/site-packages/tastypie/resources.py\", line 2150, in obj_create\n return self.save(bundle)\n\n File \"/home/matthew/Projects/Pestability/venv/local/lib/python2.7/site-packages/tastypie/resources.py\", line 2300, in save\n m2m_bundle = self.hydrate_m2m(bundle)\n\n File \"/home/matthew/Projects/Pestability/venv/local/lib/python2.7/site-packages/tastypie/resources.py\", line 964, in hydrate_m2m\n bundle.data[field_name] = field_object.hydrate_m2m(bundle)\n\n File \"/home/matthew/Projects/Pestability/venv/local/lib/python2.7/site-packages/tastypie/fields.py\", line 853, in hydrate_m2m\n m2m_hydrated.append(self.build_related_resource(value, **kwargs))\n\n File \"/home/matthew/Projects/Pestability/venv/local/lib/python2.7/site-packages/tastypie/fields.py\", line 653, in build_related_resource\n return self.resource_from_uri(self.fk_resource, value, **kwargs)\n\n File \"/home/matthew/Projects/Pestability/venv/local/lib/python2.7/site-packages/tastypie/fields.py\", line 573, in resource_from_uri\n obj = fk_resource.get_via_uri(uri, request=request)\n\n File \"/home/matthew/Projects/Pestability/venv/local/lib/python2.7/site-packages/tastypie/resources.py\", line 838, in get_via_uri\n return self.obj_get(bundle=bundle, **self.remove_api_resource_names(kwargs))\n\n File \"/home/matthew/Projects/Pestability/venv/local/lib/python2.7/site-packages/tastypie/resources.py\", line 2125, in obj_get\n object_list = self.get_object_list(bundle.request).filter(**kwargs)\n\n File \"/home/matthew/Projects/Pestability/venv/local/lib/python2.7/site-packages/django/db/models/query.py\", line 655, in filter\n return self._filter_or_exclude(False, *args, **kwargs)\n\n File \"/home/matthew/Projects/Pestability/venv/local/lib/python2.7/site-packages/django/db/models/query.py\", line 673, in _filter_or_exclude\n clone.query.add_q(Q(*args, **kwargs))\n\n File \"/home/matthew/Projects/Pestability/venv/local/lib/python2.7/site-packages/django/db/models/sql/query.py\", line 1266, in add_q\n can_reuse=used_aliases, force_having=force_having)\n\n File \"/home/matthew/Projects/Pestability/venv/local/lib/python2.7/site-packages/django/db/models/sql/query.py\", line 1134, in add_filter\n process_extras=process_extras)\n\n File \"/home/matthew/Projects/Pestability/venv/local/lib/python2.7/site-packages/django/db/models/sql/query.py\", line 1332, in setup_joins\n \"Choices are: %s\" % (name, \", \".join(names)))\n\nFieldError: Cannot resolve keyword 'url' into field. Choices are: baitpoint, call, description, id, name, operator\n"}
So I had a look and found this answer, which seemed to cover a similar situation. I added the hydrate_pests method to the CallResource class as follows:
class AbstractModelResource(ModelResource):
class Meta:
authorization = DjangoAuthorization()
authentication = ApiKeyAuthentication()
cache = SimpleCache(timeout=10)
always_return_data = True
class FilteredByOperatorAbstractModelResource(AbstractModelResource):
def authorized_read_list(self, object_list, bundle):
user = bundle.request.user
site_user = SiteUser.objects.get(user=user)
return object_list.filter(operator=site_user.operator)
class PestResource(FilteredByOperatorAbstractModelResource):
class Meta(AbstractModelResource.Meta):
queryset = Pest.objects.all()
resource_name = 'pest'
allowed_methods = ['get']
class CallResource(AbstractModelResource):
client = fields.ForeignKey(ClientResource, 'client')
operator = fields.ForeignKey(OperatorResource, 'operator')
pests = fields.ManyToManyField(PestResource, 'pests', null=True)
class Meta(AbstractModelResource.Meta):
queryset = Call.objects.all()
resource_name = 'call'
def hydrate_pests(self, bundle):
pests = bundle.data.get('pests', [])
pest_ids = []
for pest in pests:
m = re.search('\/api\/v1\/pests\/(\d+)\/', str(pest))
try:
id = m.group(1)
pest_ids.append(id)
except AttributeError:
pass
bundle.data['pests'] = Pest.objects.filter(id__in=pest_ids)
return bundle
The pests field is getting passed through as follows:
0: "/api/v1/pests/6/"
1: "/api/v1/pests/7/"
And the pest URL's are showing up correctly when I run bundle.data.get('pests', []) - if I use PDB to set a trace, I can verify that the URLs are being passed through, and Pest.objects.filter(id__in=pest_ids) is returning the correct items. However, although the HTTP POST request is successful, the pests field is not being updated to reflect the new data.
Can anyone see where I've gone wrong? Am I correct in passing through a list of the Pest objects to bundle.data['pests'], or is this not how I should be passing this data through to that field?
What actually gets passed through to bundle.data is as follows:
{'pests': [<Pest: Rats>, <Pest: Mice>], 'notes': u'Blah', 'first_choice_visit_time': u'2013-07-18T02:02', 'client': u'/api/v1/client/28/', 'date': u'2013-07-18', 'second_choice_visit_time': u'2014-03-03T03:02'}
The bundle data holds dictionaries. You're passing it a list of QuerySet objects. Try appending .values() to your queryset.
After using HttpResponseRedirect and reverse to redirect to another view, I am getting a ValueError. This is the view that processes a posted form (the form uses a ModelChoiceField to get a dropdown set of options from my Make model:
def browse(request):
thing_list = Thing.objects.all()
if request.method == 'POST':
form = BrowseForm(request.POST)
if form.is_valid():
make = form.cleaned_data['make']
return HttpResponseRedirect(reverse('browse_makes', kwargs={'make':make}))
else:
form = BrowseForm()
return render(request, 'browse.html', {'form':form, 'thing_list':thing_list})
.. then redirects to next view adding make as a kwarg to use to filter the next queryset:
def makes(request, make):
thing_list = Thing.objects.filter(make=make)
return render(request, 'browse-makes.html', {'thing_list':thing_list})
urls:
url(r'^browse/$', 'myapp.views.browse.browse', name='browse'),
url(r'^browse/(?P<make>[\w-]+)/$', 'myapp.views.browse.makes', name='browse_makes'),
Results in ValueError: invalid literal for int() with base 10: 'Samsung' when selecting an option from the form. After googling, still not sure how to solve this.. Thanks for any ideas how to solve this error!
EDIT:
abbreviated model:
class Thing(models.Model):
user = models.ForeignKey(User)
created_on = models.DateTimeField(auto_now_add=True)
updated_on = models.DateTimeField(auto_now=True)
slug = models.SlugField()
make = models.ForeignKey(Make)
Traceback:
Traceback: File "/lib/python2.7/django/core/handlers/base.py" in get_response
111. response = callback(request, *callback_args, **callback_kwargs) File "/myproject/myapp/views/browse.py" in makes
21. thing_list = Thing.objects.filter(make=make) File "/lib/python2.7/django/db/models/manager.py" in filter
143. return self.get_query_set().filter(*args, **kwargs) File "/lib/python2.7/django/db/models/query.py" in filter
624. return self._filter_or_exclude(False, *args, **kwargs) File "/lib/python2.7/django/db/models/query.py" in _filter_or_exclude
642. clone.query.add_q(Q(*args, **kwargs)) File "/lib/python2.7/django/db/models/sql/query.py" in add_q
1250. can_reuse=used_aliases, force_having=force_having) File "/lib/python2.7/django/db/models/sql/query.py" in add_filter
1185. connector) File "/lib/python2.7/django/db/models/sql/where.py" in add
69. value = obj.prepare(lookup_type, value) File "/lib/python2.7/django/db/models/sql/where.py" in prepare
320. return self.field.get_prep_lookup(lookup_type, value) File "/lib/python2.7/django/db/models/fields/related.py" in get_prep_lookup
137. return self._pk_trace(value, 'get_prep_lookup', lookup_type) File "/lib/python2.7/django/db/models/fields/related.py" in _pk_trace
210. v = getattr(field, prep_func)(lookup_type, v, **kwargs) File "/lib/python2.7/django/db/models/fields/__init__.py" in get_prep_lookup
310. return self.get_prep_value(value) File "/lib/python2.7/django/db/models/fields/__init__.py" in get_prep_value
537. return int(value)
Exception Type: ValueError at /browse/Samsung/ Exception Value: invalid literal for int() with base 10: 'Samsung'
If you post your Make model, I can give a complete answer. But in general you are referencing the make foreign key directly - which is an int (the Make ID). You are comparing this int to the string 'samsung' at make=make causing the error.
Depending on what string fields your Make model has, you need to reference one of those fields. For instance, if Make had a name field that accepted strings:
thing_list = Thing.objects.filter(make__name=make)
Otherwise, you need to pass the make ID instead of 'samsung'