Differentiate lists according to translations - python

I have a multilingual field which i used hvad package.
I have a script like below, which i use for the tastypie dehydration.
array = []
for t in bundle.obj.facilities.filter(foo_type = i.foo_type):
for field in get_translatable_fields(t.foo_type.__class__):
for translation in t.foo_type.translations.all():
value = getattr(translation, field)
array.append(value)
print array
But i get all the language translations in the same list. Do you have any idea to have different lists belong to different languages.
I just want to have different arrays that differentiate during for translation in .... iteration

You can store them in a dictionary, indexed by the translation, using a collections.defaultdict:
import collections
dict_all = collections.defaultdict(list)
for t in bundle.obj.facilities.filter(foo_type = i.foo_type):
for field in get_translatable_fields(t.foo_type.__class__):
for translation in t.foo_type.translations.all():
value = getattr(translation, field)
dict_all[translation.language_code].append(value)
If you'd like to turn it back into a regular dictionary afterwards (instead of a defaultdict):
dict_all = dict(dict_all.items())

Related

How can I generate a unique key from 2 strings?

Let's say I have "username1" and "username2"
How can I combine these two usernames together to generate a unique value?
The value should be the same no matter how they are combined if username2 is entered first or vice versa the two names should always combine to become the same unique value. The string length will not work as other usernames can have the same length.
Is there a simple way to do this or a technique for this?
Sets are unordered, and Python has a hashable immutable set type, assuming your requirement for a unique key is that it can be used as a dict key:
def key(a, b):
return frozenset([a, b])
d = {}
d[key("foo", "bar")] = "baz"
print(d[key("bar", "foo")])
You can also create a sorted tuple:
def key(a, b):
return tuple(sorted([a, b]))
d = {}
d[key("foo", "bar")] = "baz"
print(d[key("bar", "foo")])
There are many ways to generate a unique value. One common (to sysops) method is the one used to get a UNIX UUID (Universally Unique IDentifier) from the routines supplied with most major languages. In case of parsing problems, use a separator that does not appear in your input strings.
If you replace my constant strings "username1" and "username2" with your variables, I believe that your problem is solved.
import uuid
unique_sep = '|' # I posit vertical bar as not appearing in any user name
import uuid
unique_ID = uuid.uuid5(uuid.NAMESPACE_X500, "username1" + unique_sep + "username2")
print(unique_ID)
Output:
b2106742-94f5-596d-a461-c977b5982d85
To preserve uniqueness from entry order, simply sort them in any convenient fashion, such as:
names_in = [username1, username2]
unique_ID = uuid.uuid5(uuid.NAMESPACE_X500, min(names_in) + unique_sep + max(names_in))

Django using icontains filter with multiple values from dictionary

Hi i'm trying to run a model search query through a dictionary data which i got like so:
{
"city":5,
"direction":"ne",
..other data that can be dynamic...
"address__icontains" = ["word1", "word2", "word3"],
}
My search query:
Models.objects.filter(**query_dict)
since the other data are dynamic that why i use filter with dictionary.And i'm using __icontains to search up field address(string value) that contains those 3 words in that string, so the problem right now is since __icontains doesn't accept array like so in the query set:
Models.objects.filter(other keys and values from dictionary, address__icontains= ["word1", "word2", "word3"])
How would i make this work with the dictionary filter search ?
my data in dict has 3 types string, int and list(1 for range search the other for icontains search) i would like to combine dictionary search with icontains AND search
I also tried changing the dictionary to
"address__icontains" = "word1 word2 word3"
but it also doesn't work
Example data:
what im doing is find a Property that has an address field that has dynamic data like city, street, ward and district
For example:
Đường ĐT 9(street), Xã Mỹ Hạnh Nam(ward), Đức Hòa(district), Long
An(city)
and it also has other data for example like direction="ne" and specials one that search between range so has key like "size__range": [0,1000] in the dict
for example if "address__icontains" = ["Long An", "Đức Hòa", "Xã Mỹ Hạnh Nam"] then it should return the above Property item with that address, direction="ne" and size has value between 0 and 1000
Thank for reading
This should do the trick:
from operator import or_
from django.db.models import Q
from functools import reduce
instance = Model.objects.all()
def queryset_filter(instance, kwargs):
for key, value in kwargs.items():
if isinstance(value, list):
instance.filter(reduce(or_, (Q(key=x) for x in value))
else:
instance.filter(key=value)
return instance
You do a bit of extra iterating this way, but if your code requires more complex filtering (like using querysets from forms), then you will need to iterate in this manner anyways.

How to create a nested python dictionary with keys as strings?

Summary of issue: I'm trying to create a nested Python dictionary, with keys defined by pre-defined variables and strings. And I'm populating the dictionary from regular expressions outputs. This mostly works. But I'm getting an error because the nested dictionary - not the main one - doesn't like having the key set to a string, it wants an integer. This is confusing me. So I'd like to ask you guys how I can get a nested python dictionary with string keys.
Below I'll walk you through the steps of what I've done. What is working, and what isn't. Starting from the top:
# Regular expressions module
import re
# Read text data from a file
file = open("dt.cc", "r")
dtcc = file.read()
# Create a list of stations from regular expression matches
stations = sorted(set(re.findall(r"\n(\w+)\s", dtcc)))
The result is good, and is as something like this:
stations = ['AAAA','BBBB','CCCC','DDDD']
# Initialize a new dictionary
rows = {}
# Loop over each station in the station list, and start populating
for station in stations:
rows[station] = re.findall("%s\s(.+)" %station, dtcc)
The result is good, and is something like this:
rows['AAAA'] = ['AAAA 0.1132 0.32 P',...]
However, when I try to create a sub-dictionary with a string key:
for station in stations:
rows[station] = re.findall("%s\s(.+)" %station, dtcc)
rows[station]["dt"] = re.findall("%s\s(\S+)" %station, dtcc)
I get the following error.
"TypeError: list indices must be integers, not str"
It doesn't seem to like that I'm specifying the second dictionary key as "dt". If I give it a number instead, it works just fine. But then my dictionary key name is a number, which isn't very descriptive.
Any thoughts on how to get this working?
The issue is that by doing
rows[station] = re.findall(...)
You are creating a dictionary with the station names as keys and the return value of re.findall method as values, which happen to be lists. So by calling them again by
rows[station]["dt"] = re.findall(...)
on the LHS row[station] is a list that is indexed by integers, which is what the TypeError is complaining about. You could do rows[station][0] for example, you would get the first match from the regex. You said you want a nested dictionary. You could do
rows[station] = dict()
rows[station]["dt"] = re.findall(...)
To make it a bit nicer, a data structure that you could use instead is a defaultdict from the collections module.
The defaultdict is a dictionary that accepts a default type as a type for its values. You enter the type constructor as its argument. For example dictlist = defaultdict(list) defines a dictionary that has as values lists! Then immediately doing dictlist[key].append(item1) is legal as the list is automatically created when setting the key.
In your case you could do
from collections import defaultdict
rows = defaultdict(dict)
for station in stations:
rows[station]["bulk"] = re.findall("%s\s(.+)" %station, dtcc)
rows[station]["dt"] = re.findall("%s\s(\S+)" %station, dtcc)
Where you have to assign the first regex result to a new key, "bulk" here but you can call it whatever you like. Hope this helps.

Django: Add a list to a QuerySet

I am new to django so apologies if this is not possible or easy.
I have a view that takes a subset of a model
data = Terms.objects.filter(language = language_id)
The subset is one language. The set has a number of concepts for a language. Some languages might use the same word for multiple concepts, and I want to colour these the same in an SVG image. So I do this next:
for d in data:
if d.term is None:
d.colour = "#D3D3D3"
else:
d.colour = termColours[d.term]
Where termColours is a dictionary with keys as the unique terms and values as the hexadecimal colour I want.
I thought this would add a new colour attribute to my queryset. However, when I convert the queryset to json (in order to pass it to JS) the colour object is not there.
terms_json = serializers.serialize('json', data)
How can I add a new colour element to my queryset?
Convert your Queryset to Dict and then modify values.
Ex:
data = Terms.objects.filter(language = language_id).values()
for d in data:
if d.term is None:
d.colour = "#D3D3D3"
else:
d.colour = termColours[d.term]
If I understand correctly - you need Django ORM annotation. And it might look like that:
from django.db.models import Case, When, Value
data = Terms.objects.filter(language = language_id)
.annotate(color = Case(
When(term__isnull = True, then = "#D3D3D3"),
When(term__isnull = False, then = termColours[Value(term)]),))
Only problem here - I don't exactly know this moment - termColours[Value(term)], you need to test different combinations of that expressions to get the value of field term.

Pythonic way to parse list of dictionaries for a specific attribute?

I want to cross reference a dictionary and django queryset to determine which elements have unique dictionary['name'] and djangoModel.name values, respectively. The way I'm doing this now is to:
Create a list of the dictionary['name'] values
Create a list of djangoModel.name values
Generate the list of unique values by checking for inclusion in those lists
This looks as follows:
alldbTests = dbp.test_set.exclude(end_date__isnull=False) #django queryset
vctestNames = [vctest['name'] for vctest in vcdict['tests']] #from dictionary
dbtestNames = [dbtest.name for dbtest in alldbTests] #from django model
# Compare tests in protocol in fortytwo's db with protocol from vc
obsoleteTests = [dbtest for dbtest in alldbTests if dbtest.name not in vctestNames]
newTests = [vctest for vctest in vcdict if vctest['name'] not in dbtestNames]
It feels unpythonic to have to generate the intermediate list of names (lines 2 and 3 above), just to be able to check for inclusion immediately after. Am I missing anything? I suppose I could put two list comprehensions in one line like this:
obsoleteTests = [dbtest for dbtest in alldbTests if dbtest.name not in [vctest['name'] for vctest in vcdict['tests']]]
But that seems harder to follow.
Edit:
Think of the initial state like this:
# vcdict is a list of django models where the following are all true
alldBTests[0].name == 'test1'
alldBTests[1].name == 'test2'
alldBTests[2].name == 'test4'
dict1 = {'name':'test1', 'status':'pass'}
dict2 = {'name':'test2', 'status':'pass'}
dict3 = {'name':'test5', 'status':'fail'}
vcdict = [dict1, dict2, dict3]
I can't convert to sets and take the difference unless I strip things down to just the name string, but then I lose access to the rest of the model/dictionary, right? Sets only would work here if I had the same type of object in both cases.
vctestNames = dict((vctest['name'], vctest) for vctest in vcdict['tests'])
dbtestNames = dict((dbtest.name, dbtest) for dbtest in alldbTests)
obsoleteTests = [vctestNames[key]
for key in set(vctestNames.keys()) - set(dbtestNames.keys())]
newTests = [dbtestNames[key]
for key in set(dbtestNames.keys()) - set(vctestNames.keys())]
You're working with basic set operations here. You could convert your objects to sets and just find the intersection (think Venn Diagrams):
obsoleteTests = list(set([a.name for a in alldbTests]) - set(vctestNames))
Sets are really useful when comparing two lists of objects (pseudopython):
set(a) - set(b) = [c for c in a and not in b]
set(a) + set(b) = [c for c in a or in b]
set(a).intersection(set(b)) = [c for c in a and in b]
The intersection- and difference-operations of sets should help you solve your problem more elegant.
But as you're originally dealing with dicts these examples and discussion may provide some inspirations: http://code.activestate.com/recipes/59875-finding-the-intersection-of-two-dicts

Categories

Resources