I've been trying to make an unit test for a multipart request but without success. What I've been doing is:
json_data = json.dumps({
"group_type" : "1",
"foo" : {
"visibility" : "4",
"description" : "#natureza tranquilidade",
"bars" : [
{
"x_pos" : 28.16901408450704,
"y_pos" : 38.87323943661972,
"bar_name" : "morro"
},
{
"x_pos" : 65.07042253521126,
"y_pos" : 65.07042253521126,
"bar_name" : "cachoeira"
}
]
}
})
photo = Image.new('RGB', (100, 100))
tmp_file = tempfile.NamedTemporaryFile(suffix='.jpg')
photo.save(tmp_file)
post_data = {
"json_data": json_data,
"photo": photo
}
response = self.client.post(
'/api/endpoint/',
data=post_data,
format='multipart',
authentication=self.get_credentials(self.user2)
)
But I get the following error:
File /venv/lib/python2.7/site-packages/tastypie/serializers.py", line 200, in serialize raise UnsupportedFormat("The format indicated '%s' had no available serialization method. Please check your ``formats`` and ``content_types`` on your Serializer." % format)
UnsupportedFormat: The format indicated 'json' had no available serialization method. Please check your ``formats`` and ``content_types`` on your Serializer.
Do you have any Ideas?
Fixed by uploading a real file and using Django's test API instead of the Tastypie's:
def test_post(self):
json_data = json.dumps({
"group_type" : "1",
"look" : {
"visibility" : "4",
"description" : "#natureza tranquilidade",
"photo_tags" : [
{
"x_pos" : 28.16901408450704,
"y_pos" : 38.87323943661972,
"brand_name" : "morro"
},
{
"x_pos" : 65.07042253521126,
"y_pos" : 65.07042253521126,
"brand_name" : "cachoeira"
}
]
}
})
with open('cards/tests/look_test.jpg') as photo:
response = self.client.client.post(
'/api/endpoint/',
data={'json_data': json_data, 'photo': photo},
HTTP_AUTHORIZATION=self.get_credentials(self.user2)
)
print response
self.assertEquals(response.status_code, 201)
Have fun!
Related
I want to update the choices attribute directly through AWS API Gateway.
{
"id" : "1",
"general" : {
"questions : [
"choices" : ["1","2","3"]
]
}
}
Here is my resolver mapping template
#set($inputRoot = $input.path('$'))
{
"TableName" : "models",
"Key" : {
"accountId" : {
"S": "$inputRoot.accountId"
},
"category" : {
"S" : "model"
}
},
"UpdateExpression" : "SET general.questions = :questions",
"ExpressionAttributeValues" : {
":questions" : {
"L" : [
#foreach($elem in $inputRoot.questions)
{
"M" : {
"choices" : {
"L" : [
#foreach($elem1 in $elem.choices)
{"S" : "$elem1"}
#if(foreach.hasNext),#end
#end
]
}
}
}
#if($foreach.hasNext),#end
#end
]
}
}
}
But I am getting Internal server error 500 on execution.
Gateway response body: {"message": "Internal server error"}
Does DynamoDb support updating this expression or is there any error in mapping template ? If so what should be the mapping template for the object I am trying to update.
I'm trying to filter a query with term and range along with query-string. filter(range) and query string works but not filter(term). am i doing something wrong?
es = Elasticsearch([{'host': '192.168.121.121', 'port': 9200}])
index = Index("filebeat-*",using=es)
search = index.search()
searchStr = "OutOfMemoryError"
search = search.query("query_string", query=searchStr)
search = search.filter('range' , **{'#timestamp': {'gte': 1589399137000 , 'lt': 1589399377000, 'format' : 'epoch_millis'}})
search = search.filter('term' , **{'can.deployment': 'can-*' })
response = search.execute(ignore_cache=True)
print(response.hits.total)
print(response.hits.hits._source.can.deployment)
json:
filter-term - ['hits']['hits']['_source']['can']['deployment']
filter-range- ['hits']['hits']['_source']['#timestamp']
{
"hits" : {
"total" : 138351328,
"max_score" : 6.5700893,
"hits" : [
{
"_index" : "filebeat-6.1.2-2020.05.13",
"_type" : "doc",
"_score" : 2.0166037,
"_source" : {
"#timestamp" : "2020-05-13T01:14:03.354Z",
"source" : "/var/log/gw_rest/gw_rest.log",
"message" : "[2020-05-13 01:14:03.354] WARN can_gw_rest [EventLoopGroup-3-2]: An exceptionCaught() event was fired.OutOfMemoryError,
"fileset" : {...},
"can" : {
"level" : "WARN",
>>>>>>>> "message" : "An exceptionCaught() event was fired- OutOfMemoryError,
"timestamp" : "2020-05-13 01:14:03.354",
>>>>>>>> "deployment" : "can-6b721b93965b-w3we4-4074-9903"
}
}
}
]
}
}
I actually didn't need a filter(term). this worked:
dIds=response['hits']['hits'][1]['_source']['can']['deployment']
print(dIds)
#loop through the response
for i in response['hits']['hits']:
id = i['_source']['can']['deployment']
print(id)
This problem has been driving me crazy for days with not solution.
I create a document as follows from my django model.
from django_elasticsearch_dsl import fields
#registry.register_document class QuestionDocument(Document):
complete = fields.CompletionField(attr='title')
class Index:
name = 'questions'
class Django:
model = QuestionModel
fields = ['text', 'title']
Now i want to perform a completion query like this:
matched_questions = list(QuestionDocument.search().suggest("suggestions", word, completion={'field': 'complete'}).execute())
But i keep getting the following error:
elasticsearch.exceptions.RequestError: RequestError(400, 'search_phase_execution_exception', 'Field [complete] is not a completion suggest field')
I think the problem is that The mapping for this field is not created correctly, but i don't know how to fix it. Can anybody help with this it is literally driving me crazy.
UPDATE:
I realized that in my mapping, complete is created as a text field, and i don't know why this is happening or how to fix this. This is my mapping:
{
"questions" : {
"mappings" : {
"doc" : {
"properties" : {
"complete" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"text" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"title" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
}
}
}
}
}
}
I struggled too with a similar issue.
You should try to declare your Document like this:
#registry.register_document
class QuestionDocument(Document):
title = fields.TextField(
fields={
'raw': fields.TextField(analyzer='standard'),
'suggest': fields.CompletionField(),
}
)
class Index:
name = 'questions'
class Django:
model = QuestionModel
fields = ['text']
then to recover suggests from the title field:
from elasticsearch import Elasticsearch
from elasticsearch_dsl import Search
client = Elasticsearch("localhost:9200")
s = Search(using=client)
query = s.suggest('name_suggestion',"your_prefixword",completion={'field':'title.suggest'})
response = query.execute()
response.suggest['name_suggestion']
Hope it helps. Let me know if that do the job.
Your index is being created automatically instead of you creating it with the mappings you need. You need to, before you index any document, create the index. Not sure how this is done in django_elasticsearch_dsl but in elasticsearch_dsl it would be just calling QuestionDocument.init()
Hope this helps!
I want to fill a text input in my form using an autocomplete widget that I have created using jquery ui. Everything works exactly how I want to, except when the form is submitted.
The problem is that when I submit the form, the text input is automatically reseted (I don't know why) and after that, the page reloads saying that the field is required (just validation working how it's supposed to). Of course, if it didn't reset the field everything would go fine.
I dont know if my select event of the autocomplete is working fine, here is the code:
select : function (e, ui) {
// I create a new attribute to store de database primary key of this option. This is
// usefull later on.
$('#%(input_id)s').attr('itemid', ui.item.real_value);
// I set the input text value's.
$('#%(input_id)s').val(ui.item.label);
}
Here is the full code of the autocomplete:
class AutocompleteTextInputWidget (forms.TextInput):
def media(self):
js = ("/js/autocomplete.js", "pepe.js")
def __init__(self, source, options={}, attrs={}):
self.options = None
self.attrs = {'autocomplete': 'off'}
self.source = source
self.minLength = 1
self.delay = 0
if len(options) > 0:
self.options = JSONEncoder().encode(options)
self.attrs.update(attrs)
def render(self, name, value=None, attrs=None):
final_attrs = self.build_attrs(attrs)
options = ''
if value:
final_attrs['value'] = escape(value)
if isinstance(self.source, list) or isinstance(self.source, tuple):
# Crea un Json con las opciones.
source = '['
for i in range(0, len(self.source)):
if i > 0:
source += ', '
source += '"' + self.source[i] + '"'
source += ']'
options = u'''
delay : %(delay)d,
minLength : %(minlength)s,
source : %(source)s
''' % {
'delay' : self.delay,
'minlength' : self.minLength,
'source' : source
}
elif isinstance(self.source, str):
options = u'''
delay : %(delay)d,
minLength : %(minlength)s,
source : function (request, response) {
if ($(this).data('xhr')) {
$(this).data('xhr').abort();
}
$(this).data('xhr', $.ajax({
url : "%(source_url)s",
dataType : "json",
data : {term : request.term},
beforeSend : function(xhr, settings) {
$('#%(input_id)s').removeAttr('itemid');
},
success : function(data) {
if (data != 'CACHE_MISS') {
response($.map(data, function(item) {
return {
label : item[1],
value: item[1],
real_value : item[0]
};
}));
}
},
}))
},
select : function (e, ui) {
$('#%(input_id)s').attr('itemid', ui.item.real_value);
$('#%(input_id)s').val(ui.item.label);
}
''' % {
'delay' : self.delay,
'minlength' : self.delay,
'source_url' : self.source,
'input_id' : final_attrs['id'],
}
if not self.attrs.has_key('id'):
final_attrs['id'] = 'id_%s' % name
return mark_safe(u'''
<input type="text" %(attrs)s/>
<script type="text/javascript">
$("#%(input_id)s").autocomplete({
%(options)s
});
</script>
''' % {
'attrs' : flatatt(final_attrs),
'options' : options,
'input_id' : final_attrs['id']
})
Tip: If I write some text without selecting it from the autocomplete, it still fails.
Another tip: If I set the field as optional it arrives to the view empty.
What should I do to make this work when I submit the form??? I have spent hours trying to
make this work. How can I make the form to recognise that I have allready filled that field?
Here is the code of the form:
test = forms.CharField(label = "autotest", widget = AutocompleteTextInputWidget('/myjsonservice'))
This is the rendered html:
<input type="text" autocomplete="off" id="id_test"/>
<script type="text/javascript">
$("#id_test").autocomplete({
delay : 0,
minLength : 0,
source : function (request, response) {
if ($(this).data('xhr')) {
$(this).data('xhr').abort();
}
$(this).data('xhr', $.ajax({
url : "/myjsonservice",
dataType : "json",
data : {term : request.term},
beforeSend : function(xhr, settings) {
$('#id_test').removeAttr('itemid');
},
success : function(data) {
if (data != 'CACHE_MISS') {
response($.map(data, function(item) {
return {
label : item[1],
value: item[1],
real_value : item[0]
};
}));
}
},
}))
},
select : function (e, ui) {
$('#id_test').attr('itemid', ui.item.real_value);
$('#id_test').val(ui.item.label);
}
});
</script>
Finally found the answer, the problem was that the "name" attribute wasn't rendered. Hence, the field could't get to the view as part of the request.
The final code of the autocomplete widget ended up like this:
class AutocompleteTextInputWidget (forms.TextInput):
def media(self):
js = ("/js/autocomplete.js", "pepe.js")
def __init__(self, source, options={}, attrs={}):
self.options = None
self.attrs = {'autocomplete': 'off'}
self.source = source
self.minLength = 1
self.delay = 0
if len(options) > 0:
self.options = JSONEncoder().encode(options)
self.attrs.update(attrs)
def render(self, name, value=None, attrs=None):
final_attrs = self.build_attrs(attrs)
options = ''
if value:
final_attrs['value'] = escape(value)
if isinstance(self.source, list) or isinstance(self.source, tuple):
# Crea un Json con las opciones.
source = '['
for i in range(0, len(self.source)):
if i > 0:
source += ', '
source += '"' + self.source[i] + '"'
source += ']'
options = u'''
delay : %(delay)d,
minLength : %(minlength)s,
source : %(source)s
''' % {
'delay' : self.delay,
'minlength' : self.minLength,
'source' : source
}
elif isinstance(self.source, str):
options = u'''
delay : %(delay)d,
minLength : %(minlength)s,
source : function (request, response) {
if ($(this).data('xhr')) {
$(this).data('xhr').abort();
}
$(this).data('xhr', $.ajax({
url : "%(source_url)s",
dataType : "json",
data : {term : request.term},
beforeSend : function(xhr, settings) {
$('#%(input_id)s').removeAttr('itemid');
},
success : function(data) {
if (data != 'CACHE_MISS') {
response($.map(data, function(item) {
return {
label : item[1],
value: item[1],
real_value : item[0]
};
}));
}
},
}))
},
select : function (e, ui) {
$('#%(input_id)s').attr('itemid', ui.item.real_value);
$('#%(input_id)s').val(ui.item.label);
}
''' % {
'delay' : self.delay,
'minlength' : self.delay,
'source_url' : self.source,
'input_id' : final_attrs['id'],
}
if not self.attrs.has_key('id'):
final_attrs['id'] = 'id_%s' % name
return mark_safe(u'''
<input type="text" name="%(name)s" %(attrs)s/>
<script type="text/javascript">
$("#%(input_id)s").autocomplete({
%(options)s
});
</script>
''' % {
'attrs' : flatatt(final_attrs),
'options' : options,
'input_id' : final_attrs['id'],
'name' : name
})
If someone knows how to improve this messy code it would be nice.
If someone knows about a nice widget documentation for django 1.4 (Other than the oficial, which sucks by the way) it would be nice too.
Bye, good coding everyone!!!
I'm using django-haystack and ElasticSearch to index Stores.
Until now, each store had one lat,long coordinate pair; we had to change this to represent the fact that one store can deliver products to very different regions (disjunct) I've added up to ten locations (lat,long pairs) to them.
When using one location field everything was working fine and I got right results. Now, with multiple location fields, I can't get any results, not even the previuos one, for the same user and store coordinates.
My Index is as following:
class StoreIndex(indexes.SearchIndex,indexes.Indexable):
text = indexes.CharField(document=True, use_template=True,
template_name='search/indexes/store/store_text.txt')
location0 = indexes.LocationField()
location1 = indexes.LocationField()
location2 = indexes.LocationField()
location3 = indexes.LocationField()
location4 = indexes.LocationField()
location5 = indexes.LocationField()
location6 = indexes.LocationField()
location7 = indexes.LocationField()
location8 = indexes.LocationField()
location9 = indexes.LocationField()
def get_model(self):
return Store
def prepare_location0(self, obj):
# If you're just storing the floats...
return "%s,%s" % (obj.latitude, obj.longitude)
# ..... up to prepare_location9
def prepare_location9(self, obj):
# If you're just storing the floats...
return "%s,%s" % (obj.latitude_9, obj.longitude_9)
Is this the correct way to build my index?
From elasticsearch I get this mapping information:
curl -XGET http://localhost:9200/stores/_mapping?pretty=True
{
"stores" : {
"modelresult" : {
"properties" : {
"django_id" : {
"type" : "string"
},
"location0" : {
"type" : "geo_point",
"store" : "yes"
},
"location1" : {
"type" : "geo_point",
"store" : "yes"
},
"location2" : {
"type" : "geo_point",
"store" : "yes"
},
"location3" : {
"type" : "geo_point",
"store" : "yes"
},
"location4" : {
"type" : "geo_point",
"store" : "yes"
},
"location5" : {
"type" : "geo_point",
"store" : "yes"
},
"location6" : {
"type" : "geo_point",
"store" : "yes"
},
"location7" : {
"type" : "geo_point",
"store" : "yes"
},
"location8" : {
"type" : "geo_point",
"store" : "yes"
},
"location9" : {
"type" : "geo_point",
"store" : "yes"
},
"text" : {
"type" : "string",
"analyzer" : "snowball",
"store" : "yes",
"term_vector" : "with_positions_offsets"
}
}
}
}
}
Then, I try to query this way:
sqs0 = SearchQuerySet().dwithin('location0', usuario, max_dist).distance('location0',usuario).using('stores')
where:
usuario is a Point instance representing the user trying to find stores near his position and
max_dist is a D instance.
If I query directly, using curl I got no results, too.
Here is the result of quering using curl with multiple location fields:
$ curl -XGET http://localhost:9200/stores/modelresult/_search?pretty=true -d '{ "query" : { "match_all": {} }, "filter" : {"geo_distance" : { "distance" : "6km", "location0" : { "lat" : -23.5, "lon" : -46.6 } } } } '
{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"failed" : 0
},
"hits" : {
"total" : 0,
"max_score" : null,
"hits" : [ ]
}
}
If comment out the fields location1-9 from the StoreIndex class everything works fine, but if I leave them to get multiple location points, I get no results for the same query (user position). This happens for the same query, in django as directly, using curl. That is, if I have only one location (say location0), both queries returns correct results. With more locations (location0-9), both queries didn't give any results.
Here's the results of quering directly using curl with only one location field:
$ curl -XGET http://localhost:9200/stores/modelresult/_search?pretty=true -d '{ "query" : { "match_all": {} }, "filter" : {"geo_distance" : { "distance" : "6km", "location0" : { "lat" : -23.5, "lon" : -46.6 } } } } '
{
"took" : 3,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"failed" : 0
},
"hits" : {
"total" : 9,
"max_score" : 1.0,
"hits" : [ {
"_index" : "stores",
"_type" : "modelresult",
"_id" : "store.store.110",
"_score" : 1.0, "_source" : {"django_ct": "store.store", "text": "RESULT OF THE SEARCH \n\n", "django_id": "110", "id": "store.store.110", "location0": "-23.4487554,-46.58912"}
},
lot's of results here
]
}
}
Of course, I rebuild_index after any change in StoreIndex.
Any help on how to get multiple location fields working with elasticsearch and django?
PS.: I've cross posted this question on Django-Haystack and ElasticSearch Google Groups.
https://groups.google.com/d/topic/elasticsearch/85fg7vdCBBU/discussion
https://groups.google.com/d/topic/django-haystack/m2A3_SF8-ls/discussion
Thanks in advance
Mário