google app engine stringlist property on Database - python

I want to create a database in google app engine with the following properties
class Questions(db.Model):
title = db.StringProperty()
author = db.StringProperty()
text = db.TextProperty()
date = db.DateProperty(auto_now_add = True)
votes = db.IntegerProperty()
answers = db.StringListProperty()
tags = db.StringProperty()
The problem is that when I go to the dashboard and try to create an entity from there, answers property isn't there.
Is there any better way to have a list of strings, so I can manipulate them seperately?
Update:
When I try to update the entity and add something on the string list:
The link is localhost:9082/questions-4889528208719872
class QuestionPageHandler(BaseHandler):
def get(self, *a, **kw):
sURL = self.request.url.split("-")
question = Questions.get_by_id(long(sURL[-1]))
self.render_content("questionpage.html",question=question)
def post(self, *a, **kw):
answer = self.request.get("answer")
sURL = self.request.url.split("-")
question = Questions.get_by_id(long(sURL[-1]))
question.answers.append(answer)
question.put() **<---- I forgot to add this EDIT**
And then on the html I use this:
{% for answer in question.answers %}
<div class="well span7">
<p>{{answer}}</p>
</div>
{% endfor %}
But I have an empty page.

The solution:
def post(self, *a, **kw):
answer = self.request.get("answer")
sURL = self.request.url.split("-")
question = Questions.get_by_id(long(sURL[-1]))
question.answers.append(answer)
**question.put()** <-- add this

Link to NDB
Maybe try NDB which has list type properties
look at ->
ndb.StringProperty(repeated=True)
or
ndb.StructuredProperty(xxx,repeated=True)

Related

How to put arguments in a jchart.Chart class

I am trying to make a chart in Django using the jchart module and to be able to chose which rows i want to retrieve from the db using the variable hosp from my views.py to HomeTotalStudies() (below)
views.py
from charts.chartsclass import HomeTotalStudies
def home(request):
hosp = request.user.userprofile.hospital
chart = HomeTotalStudies()
return render .....
here is the /charts/chartsclass.py
from jchart import Chart
from jchart.config import (DataSet, Axes, rgba, ScaleLabel, Tick, Tooltips,
Legend, LegendLabel, Title, Hover, InteractionModes,
ElementLine, ElementPoint, ElementRectangle)
class HomeTotalStudies(Chart):
chart_type = 'pie'
responsive = False
def get_labels(self,**kwargs):
return ["CT","MG","RF","DX"]
def get_datasets(self,**kwargs):
modality = ['CT','MG','RF','DX']
count = []
if hosp=='somestring' #this is the variable i want to get from the views.py
studies = GeneralStudyModel.objects.all()
else:
studies = GeneralStudyModel.objects.filter(equipmentattributes__institution_name__exact=hosp)
for mod in modality:
cc = studies.objects.filter(modality_type__exact=mod).count()
count.append(cc)
data = [count[i] for i in range(len(count))]
colors = [
rgba(255,99,132,1),
rgba(54,162,235,1),
rgba(255,159,64,1),
rgba(255,206,86,1)
]
return [DataSet(label="My DataSet",
data=data,
borderWidth=1,
backgroundColor=colors,
borderColor=colors)]
So, my question is, how can I pass this variable hosp from the view to the chart class so that i can make the query to the db table GeneralStudyModel and i retrieve only the rows needed?
Any one has any suggestion / idea / solution?
Thanks
Yep.
You have two possibilites:
the hard way: you make an AJAX call that returns an array, and you populate this in JavaScript. This implies to make a JSON view that returns a JSON array
the easy way: you need to use class-based-view's to make modern application and in your class you override the method get_context_data()
like this:
class GeneralStudyResultsView(generic.TemplateView):
template_name='general_study_results.html'
def get_context_data(self, **kwargs):
# Call the base implementation first to get a context
context = super(GeneralStudyResultsView, self).get_context_data(**kwargs)
# Create a variable you fill
context['my_big_sql'] = GeneralStudyModel.objects.all()
return context
And from there, in your template file (this is your template file, not a JavaScript file) general_study_results.html add something like:
<script>
var myData =
{% for row in my_big_sql %}
{{ row.column }}{% if not forloop.last %},{% endif %}
{% endfor %};
</script>
And then you have all your data in your HTML file ready to be show thanks to charts.js
Just add a suitable initialiser to the chart class as follows:
class HomeTotalStudies(Chart):
def __init__(self, hosp, *args, **kwargs):
self.hosp = hosp
super().__init__(*args, **kwargs)
def get_datasets(self,**kwargs):
modality = ['CT','MG','RF','DX']
count = []
if self.hosp=='somestring' #this is the variable i want to get from the views.py
studies = GeneralStudyModel.objects.all()
else:
studies = GeneralStudyModel.objects.filter(equipmentattributes__institution_name__exact=self.hosp)
...
then in your view:
from charts.chartsclass import HomeTotalStudies
def home(request):
hosp = request.user.userprofile.hospital
chart = HomeTotalStudies(hosp='whatever')
return render .....

Python Django return unique save dates and filter model objects

I have two models
Room and RoomLog
each single Room object can have multiple RoomLog objects.
the purpose of it is that Room object has got an attribute: value and method save(). I create a new related RoomLog object every time a user saves changed attribute of any specific Room object and saves it.
RoomLog object has got value attribute and date attribute.
date is related to Room save method so it gives Room changed value save DATE.
My question is:
Q1: How to return all unique days from all RoomLog objects so I know when any save took place ?
Q2: Let's say we know how to return unique days. So, the question is: how to select any day from these unique days and display all Room objects values by chosen date ? I would like to return last saved value from chosen date for each Room object.
The way I tackle both questions at the moment (I am looking for more Pythonic, faster, better performing solutions) is:
I created Form in which I iterate through RoomLog objects:
class MyForm(forms.Form):
roomdates = []
roomextracted = []
for r in RoomLog.objects.all():
if r not in roomdates:
roomdates.append(r.update_date)
for i in roomdates:
if i not in roomextracted:
roomextracted.append(i)
ROOMDATA = [(r, r) for r in roomextracted]
my_choice_field = forms.ChoiceField(choices=ROOMDATA)
then I have a view to pass selected date to another view in which I filter Room.objects.all() by selected date:
def choices(request):
form = RoomLogChoices()
form.fields['choice'].choices = list()
testlist = []
for rl in RoomLog.objects.all():
if rl.update_date not in testlist:
testlist.append(rl.update_date)
for d in testlist:
form.fields['choice'].choices.append(
(
d,d
)
)
return render(request, 'prostats/choices.html', {'form':form})
next I have choicesform.html in which I select date from dropdown menu:
{% extends "base.html" %}
{% block content %}
<form action="" method="post" >
{% csrf_token %}
<ul>
{% for choice in form.my_choice_field.field.choices %}
<li>
<input type="radio" name="my_choice_field" value="{{choice.0}}"
{% if equal form.my_choice_field.data choice.0 %}
checked="checked"
{% endifequal %}/>
<label for="">{{choice.1}}</label>
</li>
{% endfor %}
</ul>
<input type="submit" value="Submit" />
</form>
{% endblock %}
and this is the view in which I handle POST data
class AllRoomsView(ListView):
template_name = 'prostats/roomsdetail.html'
queryset = Room.objects.all()
def get_context_data(self, **kwargs):
context = super(AllRoomsView, self).get_context_data(**kwargs)
context['rooms'] = Room.objects.all()
context['rlog'] = RoomLog.objects.all()
roomsdates = []
for r in context['rlog']:
if r not in roomsdates:
roomsdates.append(r.update_date)
roomextracted = []
for i in roomsdates:
if i not in roomextracted:
roomextracted.append(i)
context['roomextracted'] = roomextracted
choicedate = self.request.GET.get('choice')
if choicedate != None:
choosend = choicedate
else:
choosend = '2016-02-01'
#filtered rlogs
rlfilteredempty = []
for r in context['rooms']:
i = RoomLog.objects.filter(room=r.id, update_date__lte = choosend).order_by('-update_date')[:1]
if i:
rlfilteredempty.append(i[0])
else:
rlfilteredempty.append(r)
context['rlfiltered'] = rlfilteredempty
context['choicedate'] = self.request.GET.get('choice')
#context['roomfiltersettime'] = RoomLog.objects.filter(update_date__lte = choosend)
context['roomfiltersettime'] = RoomLog.objects.filter(update_date__lte = choosend)
rslice = []
for r in context['rooms']:
i = RoomLog.objects.filter(room=r.id, update_date__lte = choosend).order_by('-update_date')[:1]
if i:
for rsobject in i:
rs = (r.flat.flat_number,r.flat.block.block_name,r.room_name)
rl = rsobject.id
rv = rsobject.room_value
rslice.append((rs,rl,rv))
else:
rs = (r.flat.flat_number,r.flat.block.block_name,r.room_name)
r = r.id
rslice.append((rs,r))
context['rslice'] = rslice
So, all of it what I have done I feel is not very good and maybe somebody can point me with some good ideas on how to tackle this problem better ?
EDIT: update of the post with my Room and RoomLog models:
class Room(models.Model):
room_name = models.CharField(max_length= 10)
room_value = models.PositiveSmallIntegerField(default=0)
flat = models.ForeignKey(Flat)
created_date = models.DateField(auto_now_add= True)
created_time = models.TimeField(auto_now_add= True)
substage_name = models.CharField(max_length=50,default="")
def __init__(self, *args, **kwargs):
super(Room, self).__init__(*args, **kwargs)
self.value_original = self.room_value
def save(self, **kwargs):
with transaction.atomic():
response = super(Room, self).save(**kwargs)
if self.value_original != self.room_value:
room_log = RoomLog()
room_log.room = self
room_log.room_value = self.value_original
room_log.save()
return response
class RoomLog(models.Model):
room = models.ForeignKey(Room)
room_value = models.PositiveSmallIntegerField(default=0)
update_date = models.DateField(auto_now_add= True)
update_time = models.TimeField(auto_now_add= True)
To return all unique days, use distinct() on your created_date field. That will, of course, only work if created_date is actually a date and not a datetime value!
RoomLog.objects.all().distinct('created_date')
If your created value is a datetime, you need to make it a date first, using Django's func() and F() functions. That uses the DATE() SQL functions that may not work on all databases, but it does on Postgres and probably many others.
RoomLog.objects.all()\
.annotate(created_date=Func(F('created'), function='DATE'))\
.order_by('-created_date')\
.distinct('created_date')
Only a partial answer. The second question depends on the layout of your models that you didn't post.

Routes filtering by Language and/or category

I'm building a StumbleUpon like application which the content has to be filtered by language and category. I have two simple routes for each, language and category, but I would like to know if it's possible to have both in one simple router declaration. To not get confused I'm using Peewee as the ORM.
Here are the routes I've already defined:
#app.route("/<language>")
def languages(language):
links = []
for contenido in models.Post.select().where(models.Post.language**language):
links.append(contenido.content)
iframe = random.choice(links)
return render_template('language.html', iframe=iframe, language=language)
#app.route("/<category>")
def categories(category):
links = []
for contenido in models.Post.select().where(models.Post.category**category):
links.append(contenido.content)
iframe = random.choice(links)
return render_template('category.html', iframe=iframe, category=category)
models.py
class Post(Model):
timestamp = DateTimeField(default=datetime.datetime.now)
user = ForeignKeyField(
rel_model=User,
related_name='posts'
)
language = TextField()
category = TextField()
content = TextField()
class Meta:
database = DATABASE
What I'm trying to do is to have a relation on language and/or categories in the navigation feature. Is it possible to create something like this? I'm actually really lost trying to accomplish something like this. At the time I have something that could look a little what I'm trying to do, here is the snippet:
#app.route("/<language>/<category>")
def mixin(language, category):
language_links = []
category_links = []
for contenido in models.Post.select().where(models.Post.language**language):
language_links.append(contenido.content)
for contenido in models.Post.select().where(models.Post.category**category):
category_links.append(contenido.content)
if category_links == []:
iframe = random.choice(language_links)
else:
iframe = random.choice(category_links)
return render_template('language.html', iframe=iframe, language=language, category=category)
You can do this to retrieve posts with the given language and category:
#app.route("/<language>/<category>")
def mixin(language, category):
links = []
query = models.Post.select().where(
(models.Post.language ** language) &
(models.Post.category ** category))
for contenido in query:
links.append(contenido.content)
iframe = random.choice(links)
return render_template('language.html', iframe=iframe, language=language, category=category)
To get posts with the given language or category, you would write:
query = models.Post.select().where(
(models.Post.language ** language) | # note the "pipe" instead of "&"
(models.Post.category ** category))
Also the "**" operators may be inefficient. Is there a reason you are not using "==" instead? If you need to be able to do case-insensitive matching you can do:
(fn.LOWER(models.Post.language) == language.lower())

Django: How do I display this variable information in models to my template

I want to display answer subject and question in my template. How would I call these variables from my Answer class in my template?
Here is how my class looks
Model.py:
class Answer(models.Model):
subject = models.ForeignKey(Subject, help_text = u'The user who supplied this answer')
question = models.ForeignKey(Question, help_text = u"The question that this is an answer to")
runid = models.CharField(u'RunID', help_text = u"The RunID (ie. year)", max_length=32)
answer = models.TextField()
def __unicode__(self):
return "Answer(%s: %s, %s)" % (self.question.number, self.subject.surname, self.subject.givenname)
def choice_str(self, secondary = False):
choice_string = ""
choices = self.question.get_choices()
for choice in choices:
for split_answer in self.split_answer():
if str(split_answer) == choice.value:
choice_string += str(choice.text) + " "
Template:
{{ subject }}
{{ question }}
{{ answer }}?????
I am fairly new to Django and I am only a few weeks in to learning.
Values to the template are passed onto by views (through something known as a context) when they render some html, and not by the model classes as you seem to be indicating.
This also makes sense because model classes are just a schema or a representation of your database, whereas views are functions that retrieve values from the database (or not) and create dynamic content to be rendered.
Here's the link to the official tutorial on how to do it properly.
Pass the values in your views.py something like this:
from django.shortcuts import render_to_response
def display_variables(request):
subject = # get your subject and assign it a variable
question = # get your question and assign it a variable
answer = # get your answerand assign it a variable
return render_to_response('your_web_page.html',{'subject':subject,'question ':question ,'answer ':answer },context_instance=RequestContext(request))

Google app engine python problem

I'm having a problem with the datastore trying to replicate a left join to find items from model a that don't have a matching relation in model b:
class Page(db.Model):
url = db.StringProperty(required=True)
class Item(db.Model):
page = db.ReferenceProperty(Page, required=True)
name = db.StringProperty(required=True)
I want to find any pages that don't have any associated items.
You cannot query for items using a "property is null" filter. However, you can add a boolean property to Page that signals if it has items or not:
class Page(db.Model):
url = db.StringProperty(required=True)
has_items = db.BooleanProperty(default=False)
Then override the "put" method of Item to flip the flag. But you might want to encapsulate this logic in the Page model (maybe Page.add_item(self, *args, **kwargs)):
class Item(db.Model):
page = db.ReferenceProperty(Page, required=True)
name = db.StringProperty(required=True)
def put(self):
if not self.page.has_items:
self.page.has_items = True
self.page.put()
return db.put(self)
Hence, the query for pages with no items would be:
pages_with_no_items = Page.all().filter("has_items =", False)
The datastore doesn't support joins, so you can't do this with a single query. You need to do a query for items in A, then for each, do another query to determine if it has any matching items in B.
Did you try it like :
Page.all().filter("item_set = ", None)
Should work.

Categories

Resources