Haystack and elasticsearch not working with one character - elasticsearch

I am trying to make searches using haystack and elasticsearch but for some reason it only returns results when I search a word with more than one character.
How do I enable one character searches?
This is my index
class CustomerIndex(CelerySearchIndex, indexes.Indexable):
text = indexes.CharField(document=True)
first_name_auto = indexes.CharField(model_attr='first_name', default='')
last_name_auto = indexes.CharField(model_attr='last_name', default='')
full_name_auto = indexes.EdgeNgramField(model_attr='get_full_name', default='')
address1 = indexes.CharField(model_attr='address1', indexed=False,
default='')
accounts_customer_auto = indexes.MultiValueField()
def get_model(self):
return Customer
def prepare_accounts_customer_auto(self, obj):
return [a.id for a in obj.accounts.all()]
# def index_queryset(self, using=None):
# """Used when the entire index for model is updated."""
# return Customer.objects.all()
def get_model(self):
return Customer
and this is the query
sqs = SearchQuerySet().filter(
full_name_auto__exact=query_text).order_by('-full_name_auto').models(Customer)

This seems to be an haystack default feature

Related

how can store the number 100 only when 1 to 99 numbers are must have inside the db

suppose i am adding matchround_5, round 1,2,3,4 must have inside the db ,check each round are present in the database , How can i solve this issue?
Modelserializer
class MatchScoreSerializer(serializers.ModelSerializer):
def create(self, validated_data):
gameevent = validated_data.get('gameevent')
match_round =validated_data.get('match_round')
match = Matchscore.objects.filter(gameevent=gameevent,match_round=match_round).first()
if match :
validated_data = Matchscore.objects.filter(gameevent=gameevent,match_round=match_round).update(**validated_data)
match.refresh_from_db()
return validated_data
else:
return Matchscore.objects.create(**validated_data)
def validate(self, validated_data):
gameevent = validated_data.get('gameevent')
match_round =validated_data.get('match_round')
if not match_round :
raise serializers.ValidationError("Enter value more than 0")
if match_round == 1:
return validated_data
round = range(1,match_round)
match = Matchscore.objects.filter(gameevent=gameevent,match_round__in=round).values_list('match_round',flat=True)
match = set(match)
if match :
return validated_data
if len(match)== match_round-1:
return validated_data
else:
raise serializers.ValidationError("Enter a valid match_round")
Here my model
class Matchscore(TimeStampedModel):
gameevent = models.ForeignKey(GameEvent, null=True, related_name='game_event',on_delete=models.DO_NOTHING)
match_round = models.IntegerField(null=True,blank=True)
team_a = models.ForeignKey(Team,null=True,related_name='team_one',on_delete=models.DO_NOTHING)
team_a_score = models.PositiveIntegerField(null=True,blank=True)
team_b = models.ForeignKey(Team,null=True,related_name='team_two',on_delete=models.DO_NOTHING)
team_b_score = models.PositiveIntegerField(null=True,blank=True)
team_won = models.ForeignKey(Team,null=True,related_name='team', on_delete=models.DO_NOTHING)
Checking if match to return the validated data is not sufficient. You should check the length. You thus return the validated data if len(match) == match_round - 1.
You can however let the database return the number of distinct values, and thus avoid counting yourself:
matches = Matchscore.objects.filter(
gameevent=gameevent,
match_round__range=(1, match_round)
).values('match_round').distinct().count()
if matches == match_round-1:
return validated_data
else:
raise serializers.ValidationError('Enter a valid match_round')

How can you deal with a reserved word (from) in a serializer in DRF

Below is a serializer with a reserved word (from) used in a field:
class EdgeSerializer(serializers.Serializer):
field_name_map = {
'_from': 'from'
}
class Meta:
read_only_fields = ('_from', 'to', 'weight')
_from = serializers.IntegerField(required=True)
to = serializers.IntegerField(required=True)
weight = serializers.FloatField(required=True)
The problem is when I read serializer.data the field name in the "output" is _from, not from. I've tried using source=, I've tried reversing the field_name_map (key, value) => (value, key).
I can't use from as the name of the field, python blows up trying to parse the file
So, I did this which works, but which leaves a bad taste in my mouth and seems the "wrong" way to do it:
class FromIntegerField(serializers.IntegerField):
def bind(self, field_name, parent):
super().bind(field_name, parent)
self.field_name = 'from'
class EdgeSerializer(serializers.Serializer):
_from = FromIntegerField(required=True)
to = serializers.IntegerField(required=True)
weight = serializers.FloatField(required=True)
class Meta:
read_only_fields = ('_from', 'to', 'weight')
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
#self.fields (a `BindingDict`) contains a field keyed by '_from'
# to the field where I changed the field_name to 'from'
While this works, the smell is a little bit too much for me and I'd like to know the right way to do this. I could generalize this approach to allow me to pass an output_name='from' but that still seems wrong. I would also like to be able to take a dict that has a key of from rather than _from as well but that is a secondary concern. I think I can do it by changing self.fields to be keyed off of 'from' instead of '_from' or setting the source to 'from' in the FromIntegerField class
In my opinion it is quite ugly but likely works, you can override the .get_fields(…) method
class EdgeSerializer(serializers.Serializer):
_from = FromIntegerField(required=True)
# …
def get_fields(self):
result = super().get_fields()
_form = result.pop('_from', None)
result['from'] = _from
return result
here we thus map the original key-value pairs to a slightly different dictionary where we add this to the from key.

How to implement Elasticsearch advanced search with DRF

I want to implement a search in Elastic Search with Django Rest Framework. I have a form for searching as follows.
I used a serializer to implement this form.
search.py:
class AdvancedSearch(mixins.ListModelMixin, viewsets.GenericViewSet):
serializer_class = AdvancedSearchSerializer
def query_builder(self, *args, **kwargs):
## building related query
return query
#get_db()
def get_queryset(self, db=None, *args, **kwargs):
serializer = self.get_serializer(data=self.request.data)
serializer.is_valid(raise_exception=True)
query = self.query_builder(search_input=serializer.validated_data)
response = db.search(query) # query the elastic with elasticsearch-dsl and return the results
if not response:
raise NoteFound()
return response
def list(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
self.serializer_class = AdvancedSearchSerializer
return super(AdvancedSearch, self).list(request, *args, **kwargs)
serializer.py:
class AdvancedSearchSerializer(serializers.Serializer):
metadata_choices = [('', ''), ...]
name = serializers.CharField(required=False, label='Name')
type = serializers.CharField(required=False, label='Type')
metadata = serializers.CharField(required=False, label='Metadata')
metadata_fields = serializers.MultipleChoiceField(allow_blank=True, choices=metadata_choices)
submit_date = serializers.DateTimeField(required=False)
def to_representation(self, instance):
output = {}
output['es_id'] = instance.meta.id
for attribute_name in instance:
attribute = getattr(instance, attribute_name)
if isinstance(attribute, (str, int, bool, float, type(None))):
# Primitive types can be passed through unmodified.
output[attribute_name] = attribute
elif isinstance(attribute, list):
# Recursively deal with items in lists.
output[attribute_name] = [
self.to_representation(item) for item in attribute
]
elif isinstance(attribute, (dict, AttrDict)):
temp = attribute.to_dict()
for key, value in temp.items():
print(key,value)
# Recursively deal with items in dictionaries.
output[attribute_name] = {
str(key): value
for key, value in temp.items()
}
else:
# Force anything else to its string representation.
output[attribute_name] = attribute
output['highlight'] = instance.meta.highlight.to_dict()
return [output]
With this code, I get the expected result, but I was wondering if this is a right approach.
And also in to_representation I have access to each result, but how can I add a total value like the number of results.
Thanks in advance.

Django rest methodfield if condition working issue?

i want to pass completely and partially paid users in my serializer,but its not shows
,
payment_status = serializers.SerializerMethodField()
def get_payment_status(self, obj):
if int(obj.total_due) > 0:
paid_status ={'payment_status':'Partially paid'}
else:
paid_status={'payment_status':'Completely paid'}
return paid_status
Try to return String, not dict
payment_status = serializers.SerializerMethodField()
def get_payment_status(self, obj):
if int(obj.total_due) > 0:
return 'Partially paid'
return 'Completely paid'

Parse JSON like syntax to ruby object

Simple parser which turned out to be much harder than i thought. I need a string parser to convert nested fields to ruby object. In my case api response will only return desired fields.
Given
Parser.parse "album{name, photo{name, picture, tags}}, post{id}"
Desired output or similar
{album: [:name, photo: [:name, :picture, :tags]], post: [:id]}
Any thoughts?
Wrote my own solution
module Parser
extend self
def parse str
parse_list(str).map do |i|
extract_item_fields i
end
end
def extract_item_fields item
field_name, fields_str = item.scan(/(.+?){(.+)}/).flatten
if field_name.nil?
item
else
fields = parse_list fields_str
result = fields.map { |field| extract_item_fields(field) }
{ field_name => result }
end
end
def parse_list list
return list if list.nil?
list.concat(',').scan(/([^,{}]+({.+?})?),/).map(&:first).map(&:strip)
end
end
str = 'album{name, photo{name, picture, tags}}, post{id}'
puts Parser.parse(str).inspect
# => [{"album"=>["name", {"photo"=>["name", "picture", "tags"]}]}, {"post"=>["id"]}]

Resources