I am trying to make a responsive tournament bracket with python/django and using $.post requests to update a tournament dict - which I pass to a 'bracket' template as a dictionary, render, then update by $.posting the passed in variable to a nother view, which updates, saves to server, then redirects to 'bracket' view.
I am just starting to make some progress, but having issues with reformatting of the bracket object.
Little more detail
The bracket is initialized in python (in my views.py) in a bracket view, but I am calling in the view a Tournament class that I got from here.
the Tournament class takes a list of players and then generates a dictionary corresponding to the games with the method t.generate_bracket().
I kind of restructure this and then pass it into a bracket view for displaying - I display the restructured array in my template but also pass in the un-restructured one
I have little radio buttons that are bound to a $.post 'update_bracket' view. In the JS $.post, I send the array to the view, where I will call a t.play_game() method to update the bracket. Then - instead of a JSON or HTTP response and subsequent re-population of the bracket client side (which I am not good enough at frontend to do), I save the updated bracket to a JSONField on an employee model (extends the logged in user) and HTTPResponseRedirect to the initial 'bracket' view, where I have a check to see if the Employee has a bracket saved to them, then use that value saved to the JSONField as the new bracket dict to be displayed - instead of generating from scratch with t.generate_bracket()
Here are my bracket view, my update bracket view, the bracket.html with json $.post() to update_bracket and some of the Tournament and other classes I am utilizing
Code
Initial bracket view
#login_required#(login_url='/accounts/login/')
def bracket(request):
'''
:param request:
:return:
'''
emp = Employee.objects.get(user = request.user)
emp_bracket = emp.guess
players = [p.id for p in Pet.objects.all()]
t = Tournament(players)
if not emp_bracket:
t.generate_bracket('single', 0)
else:
t.games = emp_bracket
tournament_games = t.games
nested_tournament_games = {}
nested_tournament_games['rounds']={}
for g_id,g in tournament_games.items():
#....I do restructuring of the tournament_games dict
context = {'arr':tournament_games, 'nested':nested_tournament_games['rounds']}#{'latest_question_list': latest_question_list}
return render(request, 'madness/bracket.html', context)
.post in bracket template
$('input[type=radio][name=bStatus]').change(function() {
alert(this.value);
$.post('{% url "update_bracket" %}',
{ bracketData: JSON.stringify("{{arr}}") },
function(data, status, xhr) {
console.log(JSON.stringify(data));
var nested = JSON.stringify(data);
}).done(function() { })
.fail(function(jqxhr, settings, ex) { alert('failed, ' + ex); });
});
update_bracket view
#csrf_exempt
def update_bracket(request):
bracketData = request.POST['bracketData']
print(json.loads(bracketData))
#I plan on using the play_game() method here, but first I have to just get the basics down
emp = Employee.objects.get(user = request.user)
emp.guess = bracketData
emp.save()
# return HttpResponse(json.loads(bracketData))
return HttpResponseRedirect(reverse('bracket'))
Tournament class I am using
class Tournament:
def __init__(self, players):
self.players = players
self.player_count = len(players)
self.games = {}
...
def generate_bracket(self, bracket_class, randomize):
if bracket_class != "single":
print("Illegal bracket class")
quit()
self.n_size = int(math.ceil(math.log(self.player_count, 2)))
self.underflow = int(math.pow(2, self.n_size) - self.player_count)
if randomize:
random.shuffle(self.players)
for i in range(self.underflow):
self.players.append(None)
self.num_of_rounds = int(math.log(len(self.players), 2))
self.games = generate_bracket_rec(self.players, self.num_of_rounds)
...
def generate_bracket_rec(players, num_of_rounds):
games_map = {}
next_players = []
assert len(players) > 0
if len(players) == 1:
return games_map
gm=1
for i in range(int(len(players) / 2)):
player1_id = i
player2_id = len(players) - 1 - i
if players[player2_id] is None:
next_players.append(players[player1_id])
else:
round=str(1+num_of_rounds-int(math.log(len(players), 2)))
game_id = "round_"+round + "_game_" + str(gm)#str(i + 1)
g = Game((players[player1_id], players[player2_id]), game_id)
g.round, g.game = round, gm
games_map[g.id] = g#{'players':g.players, 'winner':g.winner, 'loser':g.loser, 'done':g.done}
# next_players.append((g, "winner")) #the winner of that game
# next_players.append('winner of %s and %s' % (g.players))
next_players.append('winner of Round %s Game %s' % (g.round, g.game))
gm += 1
d = {}
d.update(games_map)
d.update(generate_bracket_rec(next_players, num_of_rounds).items())
return d
Errors in formatting
I have tried different ways of dealing with the JSON tournament object, as it stands now the error I have is happening in js in $.post - Uncaught SyntaxError: Invalid or unexpected token, so code is not even reaching the update_bracket view.
DevTools shows
$.post('/update_bracket',
{ bracketData: JSON.stringify("{'round_1_game_1': round_1_game_1: 2 vs 3
Done: False, 'round_2_game_1': round_2_game_1: 1 vs winner of Round 1 Game 1
Done: False}") },
Does anyone know how I need to be dealing with this tournament object in the lifecycle
python (generated as dict)-->template (passed in as context var) -->python (from .post of that passed-in-template-var)-->save to django JSONField-->retrieved from JSONField (restart of cycle)
EDIT - JSON Decode error
After following advice of what to do with the passing-to-template, I get a new error in update_bracket. I am able to send the data there, but then when I try to loads() it I get JSONDecode error. Do you know how I can deal with this?
request.POST['bracketData']
'{"round_1_game_1": {"players": [2, 3], "winner": null, "loser": null, "done": false}, "round_2_game_1": {"players": [1, "winner of Round 1 Game 1"], "winner": null, "loser": null, "done": false}}'
json.loads(request.POST['bracketData'])
Traceback (most recent call last):
File "C:\Program Files\JetBrains\PyCharm Community Edition 2019.2.1\helpers\pydev\_pydevd_bundle\pydevd_exec2.py", line 3, in Exec
exec(exp, global_vars, local_vars)
File "<input>", line 1, in <module>
File "C:\Users\aiden\AppData\Local\Programs\Python\Python37-32\lib\json\__init__.py", line 348, in loads
return _default_decoder.decode(s)
File "C:\Users\aiden\AppData\Local\Programs\Python\Python37-32\lib\json\decoder.py", line 337, in decode
obj, end = self.raw_decode(s, idx=_w(s, 0).end())
File "C:\Users\aiden\AppData\Local\Programs\Python\Python37-32\lib\json\decoder.py", line 353, in raw_decode
obj, end = self.scan_once(s, idx)
json.decoder.JSONDecodeError: Expecting property name enclosed in double quotes: line 1 column 2 (char 1)
When you do {{ arr }} in your template, you're just telling python to print the arr object as string. Since arr is a dictionary (it's tournament_games), you're printing something like {'key': 'value'} which isn't a JSON string (JSON strings need double-quotes ").
And then you wrap it in "" making it a javascript string and your javascript calls JSON.stringify() on it. But that doesn't work, because stringify() expects a javascript object, not a string.
Since all you want is post a JSON string, create that string in python and print that in your template. In your context:
'arr': json.dumps(tournament_games)
and in your template:
bracketData: "{{ arr }}"
Related
In views.py VENDOR_MAPPER is list of dictionary each dictionary has id, name, placeholder and autocommit key. I also tried sending json instead of Response object.
resp_object = {}
resp_object['supported_vendors'] = VENDOR_MAPPER
resp_object['vendor_name'] = ""
resp_object['create_vo_entry'] = False
resp_object['generate_signature_flag'] = False
resp_object['branch_flag'] = False
resp_object['trunk_flag'] = False
resp_object['branch_name'] = ""
resp_object['advisory'] = ""
data = {'data': resp_object}
return Response(data)
On home.html I am accessing the vendors_supported which is list and iterate through it, however instead of object i am getting string as type of variable.
var supported_vendors = "{{data.supported_vendors|safe}}";
console.log(supported_vendors);
console.log("Supported_vendors ", supported_vendors);
console.log("Supported_vendors_type:", typeof(supported_vendors));
data.supported_vendors|safe (django template tagging) is used to remove the unwanted characters in the response i have also tried without safe, but still the type was string
also tried converted as well as parse the response but type is shown as string
var supported_vendors = "{{data.supported_vendors}}";
console.log(JSON.parse(supported_vendors));
console.log(JSON.stringify(supported_vendors));
Output generated, i have printed the response type and values i get, also converting using JSON.parse and JSON.stringify did not work and output every time was string
[1]: https://i.stack.imgur.com/DuSMb.png
I want to convert the property into javascript object and perform some computations
You can try this instead ,
return HttpResponse(json.dumps(data),
content_type="application/json")
I got the answer:
var supported_vendors = "{{data.supported_vendors}}";
Converted the above line to
var supported_vendors = {{data.supported_vendors}};
removed quotes from the variable
I want to extract the line 'Unique protein chains: 1' from this entry, using a graphQL query.
I know this is the query I want to use:
{
entry(entry_id: "5O6C") {
rcsb_entry_info {
polymer_entity_count_protein
}
}
}
and I can see the output if I use the graphQL interface here:
{
"data": {
"entry": {
"rcsb_entry_info": {
"polymer_entity_count_protein": 1
}
}
}
}
Has the information I want : "polymer_entity_count_protein": 1
I want to run this query through python so it can be fed into other pipelines (and also process multiple IDs).
I found graphene to be one library that will do graphQL queries, and this is the hello world example, which I can get to work on my machine:
import graphene
class Query(graphene.ObjectType):
hello = graphene.String(name=graphene.String(default_value="world"))
def resolve_hello(self, info, name):
return name
schema = graphene.Schema(query=Query)
result = schema.execute('{ hello }')
print(result.data['hello']) # "Hello World"
I don't understand how to combine the two. Can someone show me how I edit my python code with the query of interest, so what's printed at the end is:
'506C 1'
I have seen some other examples/queries about graphene/graphQL: e.g. here; except I can't understand how to make my specific example work.
Based on answer below, I ran:
import graphene
class Query(graphene.ObjectType):
# ResponseType needs to be the type of your response
# the following line defines the return value of your query (ResponseType)
# and the inputType (graphene.String())
entry = graphene.String(entry_id=graphene.String(default_value=''))
def resolve_entry(self, info, **kwargs):
id = kwargs.get('entry_id')
# as you already have a working query you should enter the logic here
schema = graphene.Schema(query=Query)
# not totally sure if the query needs to look like this, it also depends heavily on your response type
query = '{ entry(entry_id="506C"){rcsb_entry_info}'
result = schema.execute(query)
print("506C" + str(result.data.entry.rcsb_entry_info.polymer_entity_count_protein))
However, I get:
Traceback (most recent call last):
File "graphene_query_for_rcsb.py", line 18, in <module>
print("506C" + str(result.data.entry.rcsb_entry_info.polymer_entity_count_protein))
AttributeError: 'NoneType' object has no attribute 'entry'
Did you write the logic of the already working query you have in your question? Is it not using python/ graphene?
I'm not sure if I understood the question correctly but here's a general idea:
import graphene
class Query(graphene.ObjectType):
# ResponseType needs to be the type of your response
# the following line defines the return value of your query (ResponseType)
# and the inputType (graphene.String())
entry = graphene.Field(ResponseType, entry_id=graphene.String()
def resolve_entry(self, info, **kwargs):
id = kwargs.get('entry_id')
# as you already have a working query you should enter the logic here
schema = graphene.Schema(query=Query)
# not totally sure if the query needs to look like this, it also depends heavily on your response type
query = '{ entry(entry_id="506C"){rcsb_entry_info}}'
result = schema.execute(query)
print("506C" + str(result.data.entry.rcsb_entry_info.polymer_entity_count_protein)
Here an example for a response type:
if you have the query
# here TeamType is my ResponseType
get_team = graphene.Field(TeamType, id=graphene.Int())
def resolve_get_team(self, info, **kwargs):
id = kwargs.get('id')
if id is not None:
return Team.objects.get(pk=id)
else:
raise Exception();
the responseType is defined as:
class TeamType(DjangoObjectType):
class Meta:
model = Team
but you can also define a response type that is not based on a model:
class DeleteResponse(graphene.ObjectType):
numberOfDeletedObject = graphene.Int(required=True)
numberOfDeletedTeams = graphene.Int(required=False)
And your response type should look something like this:
class myResponse(graphene.ObjectType):
rcsb_entry_info = graphne.Field(Polymer)
class Polymer(graphene.ObjectType):
polymer_entity_count_protein = graphene.Int()
again this is not testet or anything and I don't really know what your response really is.
I'm trying to serialize the form objects and return to the AJAX call so that I can display them in the template, but I'm not able to serialize them unlike serializing the model objects don't we have an option for form objects
if request.method == 'POST':
temp_data_form = TemplateDataForm(request.POST)
if request.POST.get('temp_id'):
# getting id of the current template
existing_template = Template.objects.filter(id=request.POST.get('temp_id'))[0]
if request.POST.get('item'):
item_query = existing_template.tempdata_set.filter(item=request.POST.get('item'))
if item_query:
item_query = item_query[0] and True
# we only edit the existing object of the template always as we create the object by default on GET request
if existing_template and existing_template.title != request.POST.get('title') and request.POST.get('title')!= None:
existing_template.title = request.POST.get('title')
existing_template.save()
if temp_data_form.is_valid() and item_query != True:
# Template items alias data
td_obj = temp_data_form.save(commit=False)
td_obj.template = existing_template
td_obj.save()
values_form = []
for item in existing_template.tempdata_set.all():
values_form.append(TemplateDataForm(instance=item))
return JsonResponse(values_form, safe=False)
I'm getting the below error.
raise TypeError(f'Object of type {o.__class__.__name__} '
TypeError: Object of type TemplateDataForm is not JSON serializable
Assuming your TemplateDataForm is a Django form, it should have a "cleaned_data" attribute. You need to serialize that data and not the form itself. So for a single form, that would look like the below. Also, cleaned_data is a dictionary, so you can drop the "safe=False" argument.
return JsonResponse(values_form.cleaned_data, safe=False)
However, based on your code, it looks like you are trying to loop through a child object set or multiple forms. So, for that, you would probably want to pre-build the json dictionary response in the loop.
json_response_dict = {}
for item in existing_template.tempdata_set.all():
values_form.append(TemplateDataForm(instance=item))
# Add to your response dictionary here. Assuming you are using
# django forms and each one is a valid form. Your key will
# need to be unique for each loop, so replace 'key' with a
# loop counter such as 'form' + counter or maybe a form instance
# cleaned_data pk. If looping through child set objects, then
# reference the appropriate attribute such as values_form.title.
json_response_dict['key'] = values_form.cleaned_data
return JsonResponse(json_response_dict, safe=False)
Then in javascript, for your response, you would need to access each key.
$.ajax({
method: 'POST',
url: yourURL,
data: yourData
}).always(function (response) {
/* Test viewing the title for a single object in dictionary. Otherwise, loop
* through the response in each dictionary subset to get the keys/values.
*/
alert(response.title);
});
I have the following MongonEngine models:
from app import db
from datetime import datetime
from mongoengine import signals
class PathEmbedded(db.EmbeddedDocument):
"""
To be embedded.
"""
_id = db.ObjectIdField(required=False)
distance = db.IntField(required=False, min_value=0, default=0)
meta = {
"allow_inheritance": True,
}
def __unicode__(self):
return "Path '%s': %d m" % (self.id, self.distance)
class Path2(PathEmbedded, db.Document):
"""
Same as above, but standalone version to be stored in its own collection.
"""
_id = db.ObjectIdField()
orig = db.ObjectIdField(required=True)
dest = db.ObjectIdField(required=True)
updateStamp = db.DateTimeField(required=True)
ok_to_use = db.BooleanField(required=True, default=False)
meta = {
'indexes': [
{
'fields': ['ok_to_use', 'orig', 'dest'],
'cls': False, # does this affect performance?!
},
],
}
#classmethod
def pre_save(cls, sender, document, **kwargs):
document.updateStamp = datetime.utcnow()
def to_embedded(self):
"""
Converts the standalone Path instance into an embeddadle PathEmbedded instance.
"""
import json
temp = json.loads(self.to_json())
#remove the {"_cls": "Location"} key.
#If we don't do this, the output will be a 'Location' instance, not a 'LocationEmbedded' instace
temp.pop('_cls')
return PathEmbedded().from_json(json.dumps(temp))
def get_from_gmaps(self):
"""
Get distance from Google maps using the directions API and append to the 'paths' list.
Return False on error or True on success.
"""
try:
self.distance = 10,
self.save()
except Exception, e:
print str(e)
return False
else:
return True
# connect event hooks:
signals.pre_save.connect(Path2.pre_save, sender=Path2)
So, at some point I'm updating a path instance by calling get_from_gmaps():
from app.models.Path2 import Path2 as P
from bson import ObjectId
p=P(orig=ObjectId(), dest=ObjectId())
p.save()
p.get_from_gmaps()
which raises:
>>> p.get_from_gmaps()
ValidationError (Path2:54d34b97362499300a6ec3be) (10 could not be converted to int: ['distance'])
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "[...]app/models/Path2/get_from_gmaps.py", line 18, in get_from_gmaps
self.save()
File "[...]venv/local/lib/python2.7/site-packages/mongoengine/document.py", line 224, in save
self.validate(clean=clean)
File "[...]venv/local/lib/python2.7/site-packages/mongoengine/base/document.py", line 323, in validate
raise ValidationError(message, errors=errors)
ValidationError: ValidationError (Path2:54d34b97362499300a6ec3be) (10 could not be converted to int: ['distance'])
Originally I was storing an integer parsed from some json and converted to int, and thought somthing was wrong there, but i replaced it with an int value for debugging and now get this. I really don't know where to start o.O
EDIT: expanded code to provide complete [non]working example.
There's an extra comma after the 10:
self.distance = 10,
^
You are setting distance to a tuple containing an int, instead of an int.
HINT: The reason why your are seeing such an unhelpful message is that MongoEngine is using %s format string improperly. In fact, the result of "%s" % something depends on the type of something, as tuples are special cased. Compare:
>>> '%s' % 10
'10'
>>> '%s' % (10,)
'10'
>>> '%s' % (10, 11)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: not all arguments converted during string formatting
>>> '%s' % ((10,),) # This is the correct way of formatting strings
'(10,)' # when the type of the argument is unknown.
This is a MongoEngine's problem of course, but if you want to avoid the same kind of mistake in your code, remember to always use tuples at the right of the % operator, or even better use the .format() method.
Are you sure the self model you send is the right one?
This ValidationError is thrown when you have declare a ReferenceField in a document, and you try to save this document before saving the referenced document (Mongoengine represents a reference field in MongoDB as an dictionnay containing the class and the ObjectId of the reference).
I'm fairly new to programming. I'm trying to write two class methods that will take a string, '{{name}} is in {{course}}' , and replace {{name}} and {{course}} with their respective Key values in a dictionary. So:
t = Template()
vars = {
'name': 'Jane',
'course': 'CS 1410'
}
out = t.process('{{name}} is in {{course}}', vars)
print 'out is: [' + out + ']'
Would print:
Jane is in CS 1410
My code goes as:
class Template:
def processVariable(self, template, data):
print template
assert(template.startswith('{{'))
start = template.find("{{")
end = template.find("}}")
out = template[start+2:end]
assert(out != None)
assert(out in data)
return data[out]
def process(self, template, data):
output = ""
check = True
while check == True:
start = template.find("{{")
end = template.find("}}")
output += template[:start]
output += self.processVariable(template[start:end+2], data)
template = template.replace(template[:end+2], "")
for i in template:
if i == "}}":
check = True
output += template
return output
t = Template()
vars = {
'name': 'Jane',
'course': 'CS 1410'
}
out = t.process('{{name}} is in {{course}}', vars)
print 'out is: [' + out + ']'
When I run the code, I get the following output:
{{name}}
{{course}}
Traceback (most recent call last):
File "C:some/filepath/name.py", line 46, in <module>
out = t.process('{{name}} is in {{course}}', vars)
File "C:some/filepath/name.py", line 28, in process
output += self.processVariable(template[start:end+2], data)
File "C:some/filepath/name.py", line 8, in processVariable
assert(template.startswith('{{'))
AssertionError
I just don't understand why im getting that assertion error if template is '{{course}}'
Edit:
The purpose making the code this way, was to bring in any dictionary and string, so that I can create a simple social network. Otherwise much simpler methods would be proficient.
You weren't actually getting the assertion error when template was {{course}}, which you can see for yourself if you change the process method to include some simple print statements, e.g.:
def process(self, template, data):
# ...
output += template[:start]
print "Processing, template is currently:"
print template
output += self.processVariable(template[start:end+2], data)
# ...
return output
The actual problem was that check never became false. You can replace your if test with something like this, and then your function runs fine:
if not '}}' in template:
check = False
Marius beat me to the answer to your question, but I just wanted to point out an easier way to do (almost) the same thing. Ofcourse, if you're just trying to learn than the hard way is usually better.
vars = {
'name': 'Jane',
'course': 'CS 1410'
}
out = '{name} is in {course}'.format(**vars)
print out