Guy, I need your help. Since I'm newbie and I'm making my first app in Django I came to an issue while testing my app. There is problem with testing views, and since tested manually everything works fine problem occurs while testing automatition.
I think the issue may be related to POST / GET requests because I made things in way that, most things are based on GET, even those which change things in DB. POST request is reserved only to forms. When I start tests, every action that is made seems lacking-effect like those GET requests don't work.
Ok here comes the code:
Views:
#login_required
def new(request):
if request.method == "POST":
player = Player.objects.get(name=request.user)
hosted = Game(host=player.nick)
form = CreateGame(instance=hosted, data=request.POST)
if form.is_valid():
form.save()
return redirect("home", name="new_room")
#login_required
def delete_room(request, id):
game = Game.objects.get(id=id)
player = Player.objects.get(name=request.user)
if player.nick == game.host and game.how_many_players_ready == 0:
if not game.is_played:
game.delete()
return redirect("home", name="game_deleted")
else:
return redirect('detail', id=game.id)
else:
return redirect('detail', id=game.id)
Tests:
class TestViews(TestCase):
def setUp(self):
self.client = Client()
self.user = User.objects.create_user(username='testuser', password='12345')
self.user2 = User.objects.create_user(username='testuser2', password='12345')
usr = self.user
self.client.login(username='testuser', password='12345')
self.player = Player.objects.create(name=usr, parent = usr.username, nick = 'nie')
def test_create_many_rooms(self):
#this one works -> POST
self.new_room=reverse('new_room')
self.client.post(self.new_room, {'name' :'mariaczi', 'host':'mario'})
self.client.post(self.new_room, {'name': 'mariaczi2','host':'mario'})
self.client.post(self.new_room, {'name': 'mariaczi3', 'host': 'mario'})
suma = Game.objects.all().count()
self.assertEquals(suma,3)
def test_host_delete_empty_room(self):
#this one not
game = Game.objects.create(name='empty', host='testuser', is_played=False, max_players=4)
self.delete_room = reverse('delete_gam', args=[game.id])
self.client.get(self.delete_room, follow=True)
suma = Game.objects.all().count()
self.assertEquals(suma,0)
OUTCOME: ======================================================================
FAIL: test_host_delete_empty_room (game.tests.test_views.TestViews)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/dottore/PycharmProjects/Nowa_gra/Nova_gra/game/tests/test_views.py", line 53, in test_host_delete_empty_room
self.assertEquals(suma,0)
AssertionError: 1 != 0
Models:
class Game(models.Model):
name = models.CharField(max_length=150)
host = models.CharField(max_length=10)
is_played = models.BooleanField(default = False)
max_players = models.IntegerField(default=4)
who_is_ready = models.ManyToManyField(Player, related_name="guys_ready", blank=True)
who_is_playing = models.ManyToManyField(Player, related_name="guys_playing", blank=True)
turn = models.IntegerField(default=1)
turn_of_player = models.ForeignKey(Player, on_delete=models.CASCADE, related_name='czyja_tura', blank=True, null=True)
#property
def how_many_players_ready(self):
return self.who_is_ready.count()
#property
def how_many_players_playing(self):
return self.who_is_playing.count()
#property
def players_ready(self):
return list(self.who_is_ready.all())
#property
def players_playing(self):
return list(self.who_is_playing.all())
#property
def players_playing_str(self):
res = [i.nick for i in self.who_is_playing.all()]
return res
#property
def first_player(self):
return self.players_playing[0]
#property
def second_player(self):
return self.players_playing[1]
#property
def third_player(self):
return self.players_playing[2]
#property
def forth_player(self):
return self.players_playing[3]
#property
def next_player(self):
x = self.players_playing.index(self.turn_of_player)
nast= x+1
if nast > (self.how_many_players_playing - 1):
self.turn +=1
self.save()
return self.players_playing[0]
else:
return self.players_playing[x+1]
def __str__(self):
return self.name
Where is the TRICK? Shall I always handle things with database changes other way then generating GET?
There is no trick here... I think the Game object is not getting delete, your delete_room has many if-else's. Common debugging technique is to put a print statement in each if else condition to see which path it's taking.
My suspicion is on first part of this if condition,
if player.nick == game.host this will result in "nie" == "testuser"
which are not equal. But find it yourself using print statements.
Related
I am trying to create a FlaskForm that changes depending on the customer passed to it and having issues when the HTML is getting rendered. I haven't done much work with classes unfortunately so I'm not sure what the issue is. I get an error in Python that says:
AttributeError: 'GlobalsForm' object has no attribute '_fields'
I modified the __init__ so that you can set who the customer is plus a created a class function that checks to see who the customer is and customizes the form fields depending on who the customer is. I have a feeling it doesn't like me modifying the class I am inheriting and am probably missing something to make it work. Need to do something with "super"?
Here is what I have so far:
routes.py
#app.route('/global_vars', methods=['GET', 'POST'])
def global_vars():
data = session.get('dev_data', None)
form = GlobalsForm(customer=data['customer'])
form.set_fields()
return render_template('global_vars.html', title='Config Provisioning - Globals', form=form)
forms.py
class GlobalsForm(FlaskForm):
def __init__(self, customer):
self.customer = customer
def set_fields(self):
if self.customer == 'Cust1':
site_choices = [('Site1', 'Site1'), ('Site2', 'Site2'), ('Site3', 'Site3')]
site = SelectField('Site: ', choices = site_choices)
floor_room = StringField("Floor/Room (Ex. FL1RM56 or 1J46): ", validators=[InputRequired()])
rack = StringField("Rack (Data Centers only): ")
l2_domain_choices = [('USR', 'USR - User'), ('DC', 'DC - Data Center'), ('OOBM', 'OOBM - Out of Band Management')]
l2_domain = SelectField('Layer 2 Domain: ', choices=l2_domain_choices)
function_choices = [('ACSW', 'ACSW - Access Switch)'), ('AGSW', 'AGSW - Aggregation Switch'), ('CRSW', 'CRSW - Core Switch')]
function = SelectField('Device function: ', choices=function_choices)
else:
hostname = Stringfield("Hostname: ", validators=[InputRequired()])
I figured it out.. Had to expand on the super() line...
class GlobalsForm(FlaskForm):
def __init__(self, customer=None, *args, **kwargs):
self.customer = customer
super(GlobalsForm, self).__init__(*args, **kwargs)
Of course, I hate resorting to using the time of busy StackExchange members to solve my issues, but I have asked in the forums from which I retrieved this code to explain how the mechanism works, but there has been absolutely no response.
My question should probably be quite simple (not for myself, as I am what you would call a web development amateur). I have this code (not my own) for the backend a basic blog. But there is one thing that I am not quite understanding. In one of the HTML files, there is a line that has {{user.name}}, which gets the username of the person currently logged in and posts it in the corner of the page. The {{}} is just Jinja2 syntax that prints a python expression to the template (or so I'm told).
How can I get the username of the user logged in within the Python file? What I am currently trying to do in my own web application, is obtain the username of the user logged in and Query the Google Datastore for the information regarding the user and put in on a profile page, like so:
class Profile(BlogHandler):
def render_profile(self):
signatory = user.name
signedevents = db.GqlQuery("SELECT event FROM Signatories WHERE username IN (signatory)")
self.render("profile.html", signedevents=signedevents)
def get(self):
if self.user:
self.render_profile()
else:
self.redirect('/')
But whenever I try this, I always get an error. Is there something else that should go in place of user.name?
Blog code (I am sure the answer is somewhere in the Handler class but I simply cannot figure out what the issue is):
import os
import re
import random
import hashlib
import hmac
from string import letters
import webapp2
import jinja2
from google.appengine.ext import db
template_dir = os.path.join(os.path.dirname(__file__), 'templates')
jinja_env = jinja2.Environment(loader = jinja2.FileSystemLoader(template_dir),
autoescape = True)
secret = 'fart'
def render_str(template, **params):
t = jinja_env.get_template(template)
return t.render(params)
def make_secure_val(val):
return '%s|%s' % (val, hmac.new(secret, val).hexdigest())
def check_secure_val(secure_val):
val = secure_val.split('|')[0]
if secure_val == make_secure_val(val):
return val
class BlogHandler(webapp2.RequestHandler):
def write(self, *a, **kw):
self.response.out.write(*a, **kw)
def render_str(self, template, **params):
params['user'] = self.user
return render_str(template, **params)
def render(self, template, **kw):
self.write(self.render_str(template, **kw))
def set_secure_cookie(self, name, val):
cookie_val = make_secure_val(val)
self.response.headers.add_header(
'Set-Cookie',
'%s=%s; Path=/' % (name, cookie_val))
def read_secure_cookie(self, name):
cookie_val = self.request.cookies.get(name)
return cookie_val and check_secure_val(cookie_val)
def login(self, user):
self.set_secure_cookie('user_id', str(user.key().id()))
def logout(self):
self.response.headers.add_header('Set-Cookie', 'user_id=; Path=/')
def initialize(self, *a, **kw):
webapp2.RequestHandler.initialize(self, *a, **kw)
uid = self.read_secure_cookie('user_id')
self.user = uid and User.by_id(int(uid))
def render_post(response, post):
response.out.write('<b>' + post.subject + '</b><br>')
response.out.write(post.content)
class MainPage(BlogHandler):
def get(self):
self.write('Hello, Udacity!')
##### user stuff
def make_salt(length = 5):
return ''.join(random.choice(letters) for x in xrange(length))
def make_pw_hash(name, pw, salt = None):
if not salt:
salt = make_salt()
h = hashlib.sha256(name + pw + salt).hexdigest()
return '%s,%s' % (salt, h)
def valid_pw(name, password, h):
salt = h.split(',')[0]
return h == make_pw_hash(name, password, salt)
def users_key(group = 'default'):
return db.Key.from_path('users', group)
class User(db.Model):
name = db.StringProperty(required = True)
pw_hash = db.StringProperty(required = True)
email = db.StringProperty()
#classmethod
def by_id(cls, uid):
return User.get_by_id(uid, parent = users_key())
#classmethod
def by_name(cls, name):
u = User.all().filter('name =', name).get()
return u
#classmethod
def register(cls, name, pw, email = None):
pw_hash = make_pw_hash(name, pw)
return User(parent = users_key(),
name = name,
pw_hash = pw_hash,
email = email)
#classmethod
def login(cls, name, pw):
u = cls.by_name(name)
if u and valid_pw(name, pw, u.pw_hash):
return u
Everything past here is probably not important, but if the answer cannot be found by only using the code above, please continue.
##### blog stuff
def blog_key(name = 'default'):
return db.Key.from_path('blogs', name)
class Post(db.Model):
subject = db.StringProperty(required = True)
content = db.TextProperty(required = True)
created = db.DateTimeProperty(auto_now_add = True)
last_modified = db.DateTimeProperty(auto_now = True)
def render(self):
self._render_text = self.content.replace('\n', '<br>')
return render_str("post.html", p = self)
class BlogFront(BlogHandler):
def get(self):
posts = greetings = Post.all().order('-created')
self.render('front.html', posts = posts)
class PostPage(BlogHandler):
def get(self, post_id):
key = db.Key.from_path('Post', int(post_id), parent=blog_key())
post = db.get(key)
if not post:
self.error(404)
return
self.render("permalink.html", post = post)
class NewPost(BlogHandler):
def get(self):
if self.user:
self.render("newpost.html")
else:
self.redirect("/login")
def post(self):
if not self.user:
self.redirect('/blog')
subject = self.request.get('subject')
content = self.request.get('content')
if subject and content:
p = Post(parent = blog_key(), subject = subject, content = content)
p.put()
self.redirect('/blog/%s' % str(p.key().id()))
else:
error = "subject and content, please!"
self.render("newpost.html", subject=subject, content=content, error=error)
###### Unit 2 HW's
class Rot13(BlogHandler):
def get(self):
self.render('rot13-form.html')
def post(self):
rot13 = ''
text = self.request.get('text')
if text:
rot13 = text.encode('rot13')
self.render('rot13-form.html', text = rot13)
USER_RE = re.compile(r"^[a-zA-Z0-9_-]{3,20}$")
def valid_username(username):
return username and USER_RE.match(username)
PASS_RE = re.compile(r"^.{3,20}$")
def valid_password(password):
return password and PASS_RE.match(password)
EMAIL_RE = re.compile(r'^[\S]+#[\S]+\.[\S]+$')
def valid_email(email):
return not email or EMAIL_RE.match(email)
class Signup(BlogHandler):
def get(self):
self.render("signup-form.html")
def post(self):
have_error = False
self.username = self.request.get('username')
self.password = self.request.get('password')
self.verify = self.request.get('verify')
self.email = self.request.get('email')
params = dict(username = self.username,
email = self.email)
if not valid_username(self.username):
params['error_username'] = "That's not a valid username."
have_error = True
if not valid_password(self.password):
params['error_password'] = "That wasn't a valid password."
have_error = True
elif self.password != self.verify:
params['error_verify'] = "Your passwords didn't match."
have_error = True
if not valid_email(self.email):
params['error_email'] = "That's not a valid email."
have_error = True
if have_error:
self.render('signup-form.html', **params)
else:
self.done()
def done(self, *a, **kw):
raise NotImplementedError
class Unit2Signup(Signup):
def done(self):
self.redirect('/unit2/welcome?username=' + self.username)
class Register(Signup):
def done(self):
#make sure the user doesn't already exist
u = User.by_name(self.username)
if u:
msg = 'That user already exists.'
self.render('signup-form.html', error_username = msg)
else:
u = User.register(self.username, self.password, self.email)
u.put()
self.login(u)
self.redirect('/blog')
class Login(BlogHandler):
def get(self):
self.render('login-form.html')
def post(self):
username = self.request.get('username')
password = self.request.get('password')
u = User.login(username, password)
if u:
self.login(u)
self.redirect('/blog')
else:
msg = 'Invalid login'
self.render('login-form.html', error = msg)
class Logout(BlogHandler):
def get(self):
self.logout()
self.redirect('/blog')
class Unit3Welcome(BlogHandler):
def get(self):
if self.user:
self.render('welcome.html', username = self.user.name)
else:
self.redirect('/signup')
class Welcome(BlogHandler):
def get(self):
username = self.request.get('username')
if valid_username(username):
self.render('welcome.html', username = username)
else:
self.redirect('/unit2/signup')
app = webapp2.WSGIApplication([('/', MainPage),
('/unit2/rot13', Rot13),
('/unit2/signup', Unit2Signup),
('/unit2/welcome', Welcome),
('/blog/?', BlogFront),
('/blog/([0-9]+)', PostPage),
('/blog/newpost', NewPost),
('/signup', Register),
('/login', Login),
('/logout', Logout),
('/unit3/welcome', Unit3Welcome),
],
debug=True)
If there is something you need me to clarify, please let me know. Thank you in advance for your help.
OK, you're inheriting BlogHandler.
To get the username info, by following the Unit3Welcome() example, I think you need to change signatory = user.name to signatory = self.user.name
To fill the {{user.name}} field in a jinja2 template it needs to get in the template values dict it receives a user variable (also of dict type) containing a name key (presumably with the respective username). For example: {'user': {'name': 'johndoe'}}.
I'm not familiar neither with how the renderer you use works nor with SQL and how signedevents is filled, so you may need to adapt.
To easily inspect (in debug print style) what actually makes it to the template you can temporarily insert a paragraph like this somewhere in your html: <p>user: ({{ user }})</p> and you should get the dump of the user variable right in your browser :)
Hi I remember this thing with App Engine, maybe it has to do something with the old 'db' datastore. Google now recommends to use 'ndb'.
Since you are also setting cookie you can actually use it to render your user's name in the Welcome page.
This is how I got around it, hope this helps.
class Register(SignUp):
def done(self):
#make sure the user doesn't already exist
u = User.by_name(self.request.get("username"))
if u:
msg = 'That user already exists.'
self.render('signup-form.html', username_exists = msg)
else:
username = self.request.get("username")
password = self.request.get("password")
email = self.request.get("email")
u = User.register(username, password , email)
u.put()
self.login(u)
self.redirect('/blog/welcome')
class Welcome(BlogHandler):
def get(self):
cookie = self.request.cookies.get("user_id")
val = check_secure_val(cookie)
u = User.by_id(int(val))
if u:
print u
self.render('welcome.html', username = u.name)
else:
self.redirect('/blog/signup')
I have issues with the two following models. The first model (QueryJob) is referenced by the second model(PropertyQuery) by a many to many field( queryID = models.ForeignKey(QueryJob,blank=True,null=True)) which necessitates that QueryJob precedes PropertyQuery.
How PropertyQuery objects are created by calling QueryJob.createqueries() which requires that PropertyQuery preceeds QueryJob.
Code is below. Is there a better way to approach this problem?
class QueryJob(models.Model):
queryUID = models.AutoField(primary_key=True)
client = models.ManyToManyField(Client,blank=True)
Json = JSONField()
street_column =models.TextField()
state_column =models.TextField(blank=True)
suburb_column =models.TextField(blank=True)
postcode_column =models.TextField(blank=True)
def createqueries(self):
#json_data = json.loads(self.Json)
print self.Json
for each in self.Json:
try:
Street = each[self.street_column]
State = each[self.state_column]
Suburb = each[self.suburb_column]
Postcode = each[self.postcode_column]
q = PropertyQuery(street_address = Street, state=State ,suburb = Suburb,postcode=Postcode,queryID=self.queryUID )
q.save()
except:
pass
def save(self, *args, **kwargs):
self.createqueries()
super(QueryJob, self).save(*args, **kwargs)
Second model
class PropertyQuery(models.Model):
queryID = models.ForeignKey(QueryJob,blank=True,null=True)
linkedproperty = models.ForeignKey(Property,blank=True,null=True)
street_address = models.CharField(max_length=255, db_index=True,null=True)
suburb = models.CharField(max_length=120, db_index=True,blank=True,null=True)
state = models.CharField(max_length=3, db_index=True,blank=True,null=True)
postcode = models.IntegerField(max_length=4, db_index=True, blank=True,null=True)
matcheduncertainty = models.PositiveSmallIntegerField(blank=True,null=True)
def search_for_a_match(self):
if self.postcode:
print self.postcode
print Property.objects.filter(postcode=self.postcode)
try:
property_list = Property.objects.filter(postcode=self.postcode)
print property_list
except:
print "no properties in that postcode"
return
elif self.suburb:
try:
property_list = Property.objects.filter(suburb=self.suburb)
print property_list
except:
print "no properties in that suburb"
elif self.state:
try:
property_list = Property.objects.filter(state=self.state)
print property_list
except:
print "no properties in that state"
return
else:
print "no properties found"
return
for possible in property_list:
if possible.street_address == self.street_address:
self.linkedproperty = possible
self.matcheduncertainty = 100
return
else:
print "we will need to try something else"
Switch the order of these statements, so that your QueryJob is created first, then your PropertyQuery models are created:
def save(self, *args, **kwargs):
super(QueryJob, self).save(*args, **kwargs)
self.createqueries()
In your createqueries() method, you can refer to self when you need to create a link. Do not create a link to the primary key directly as this won't work - you don't realize its not working because you have a blank except clause that is catching the exceptions raised:
def createqueries(self):
#json_data = json.loads(self.Json)
print self.Json
for each in self.Json:
Street = each.get(self.street_column)
State = each.get(self.state_column)
Suburb = each.get(self.suburb_column)
Postcode = each.get(self.postcode_column)
q = PropertyQuery(street_address = Street,
state=State,
suburb = Suburb,
postcode=Postcode,
queryID=self)
q.save()
I have an admin page in django 1.4.3 [final]. We use CF cards in a lot of hardware, each card connects to a VPN. I have a function which determines whether the card is online or not depending on its last feedback written in database.
models.py:
class Card(models.Model):
...
last_feedback = models.DateTimeField(_('Last feedback'), null=True, blank=True)
...
def online_status(self):
nowtime = calendar.timegm(timezone.now().utctimetuple())
seen = calendar.timegm(self.last_feedback.utctimetuple())
diff = nowtime-seen
if (self.state == 1) and (diff < 300):
return '<div style="width:100%%; height:100%%; background-color:green; color:white;">online & production</div>'
elif (diff < 300):
return '<div style="width:100%%; height:100%%; background-color:orange;">online</div>'
else:
return "offline"
online_status.allow_tags = True
admin.py:
class OnlineFilter(admin.SimpleListFilter):
title = _("Online")
parameter_name = "online"
def lookups(self, request, model_admin):
return (("yes", "Yes"),
("no", "No"),
)
def queryset(self, request, queryset):
out = self.filter(request, queryset)
f = open("/tmp/list", "w")
f.write(str(out))
f.close()
return out
def filter(self, request, queryset):
if not self.value():
return queryset
else:
out = []
if self.value() == 'yes':
for i in queryset:
try:
if i.online_status() != "offline":
out.append(i)
except:
pass
elif self.value() == 'no':
for i in queryset:
try:
if i.online_status() == "offline":
out.append(i)
except:
pass
return out
class CardAdmin(admin.ModelAdmin):
list_filter = [ ... , OnlineFilter ]
and everytime I try to set the online filter, the file /tmp/list gets full with the right set of cards and then filled with the default list - as if the filter gets called twice. And the URL in my browser says ?e=1 instead of ?online=yes. If the filter is not set, it is called only once - giving only one set of cards in the file.
BTW: the OnlineFilter.filter method is out of the queryset method just so that I know what goes out of my code, in final release I would have put it in only one method ...
is this a bug? or a feature? Am I doing something wrong? If so, what?
I wouldn't be surprised if django calls the queryset function twice - I seem to remember noticing that once before. Not sure why though. Regarding why the filter is not working, django expects a QuerySet to be returned, not a list. You might be able to construct a query to determine online status, but given the complexity I suspect it will prove to be beyond the powers to the django ORM and you'd need to revert to raw SQL. The alternative would be to create a list of primary keys, the simply filter the queryset by those, so:
def filter(self, request, queryset):
if not self.value():
return queryset
else:
pks = []
if self.value() == 'yes':
for i in queryset:
try:
if i.online_status() != "offline":
pks.append(i.pk)
except:
pass
elif self.value() == 'no':
for i in queryset:
try:
if i.online_status() == "offline":
pks.append(i.pk)
except:
pass
out = queryset.filter(pk__in=pks)
return out
I have got following django code for Formwizard in python. First there are two forms:
class AuthenticationForm(forms.Form):
FirstName = forms.CharField(max_length=500)
LastName = forms.CharField(max_length=500)
class SurveyForm(forms.Form):
def __init__(self, *args, **kwargs):
super(SurveyForm, self).__init__(*args, **kwargs)
for question in choiceValue:
self.fields[question] = forms.ChoiceField(choices=CHOICES,widget=RadioSelect())
class ContactWizard(FormWizard):
choiceValue = []
def get_template(self,step):
if step == 0:
return 'wizard0.html'
if step == 1:
return 'wizard1.html'
def process_step(self, request, form, step):
if (step == 0):
fullName=""
if request.method== 'POST':
if form.is_valid():
FirstName = form.cleaned_data['FirstName']
LastName = form.cleaned_data['LastName']
FirstNameU=FirstName.capitalize()
LastNameU=LastName.capitalize()
fullName=FirstNameU+" "+LastNameU
personURIfn=GraphR.triples((None,FOAF_NS['givenName'],Literal(FirstNameU)))
personURIln=GraphR.triples((None,FOAF_NS['familyName'],Literal(LastNameU)))
for purifn in personURIfn:
purifnStr='%s' %purifn[0]
for puriln in personURIln:
purilnStr='%s' %puriln[0]
if purifnStr == purilnStr:
personURI=purifnStr
friendKnows=GraphR.triples((URIRef(purifnStr),FOAF_NS['knows'],None))
for fk in friendKnows: #and scn1 not in epuriList1:
fkStr='%s' %fk[2]
choiceValue.append(fkStr)
return render_to_response('wizard1.html', RequestContext(request))
def done(self, request, form_list):
print 'run'
I am not getting why it is giving error mentioned in the Title. Moreover Google is also not providing any specific help. Could anyone of you please guess the cause of it. I suspect something wrong happening in Done method but not sure.
Thanks.
Think about what happens in process_step if if's not step 0, or if it's a GET rather than a POST, or if the form is not valid. What is returned in those cases?