Запрос к хранилищу данных: объект NoneType не имеет атрибута

Когда я запускаю этот блок if:

first_query = db.GqlQuery("SELECT * FROM Contract ORDER BY date DESC").get()
    if first_query == None:
        numBook = 42
        numInitialPage = 42
        numFinalPage = 42
        first_record = Contract(book_number = 1, initial_page = 0, final_page = 0)
        first_record.put()
        contract = db.GqlQuery("SELECT * FROM Contract ORDER BY date DESC").get()
        numBook = contract.book_number
        numInitialPage = contract.final_page +1
        numFinalPage = numInitialPage
    else:
        contract = first_query
        numBook = first_query
        numInitialPage = 51
        numFinalPage = 51

Процедура переходит в блок if, но затем я получаю следующее сообщение об ошибке:

    File "C:\Users\CG\Documents\udacity\contract\main.py", line 88, in get
    numBook = contract.book_number
AttributeError: 'NoneType' object has no attribute 'book_number'

Поскольку я использовал .put() для вставки записи и .get() для доступа к ней, почему значение контракта равно None?

Заранее благодарю за любую помощь!

Вот весь код:

# -*- coding: utf-8 -*-
# -*- coding: utf-8 -*-
#!/usr/bin/env python
#
# Copyright 2007 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

import os

import webapp2

import jinja2

jinja_environment = jinja2.Environment(autoescape=True,
    loader=jinja2.FileSystemLoader(os.path.join(os.path.dirname(__file__), 'templates')))

import re

from google.appengine.ext import db

USER_RE = re.compile(r"^[a-zA-Z0-9_ -]{3,20}$")
def valid_person(person):
    return USER_RE.match(person)

PASS_RE = re.compile(r"^.{3,20}$")
def valid_SSN(SSN):
    return PASS_RE.match(SSN)

EMAIL_RE = re.compile(r"^[\S]+@[\S]+\.[\S]+$")
def valid_email(email):
    return EMAIL_RE.match(email)

import time

import datetime

def dateToday():
    today = datetime.datetime.today()
    todayDay = str(today.day)
    todayMonth = str(today.month)
    monthExt = {'1':' January ', '2':'February', '3':' March ', '4':'April', '5':'May', '6':'June', '7':' July ', '8':'August', '9':'September', '10':'October', '11':'November ', '12':'December'}
    todayYear = str(today.year)
    return(todayDay + ' of  ' + monthExt[todayMonth] + ' of ' + todayYear)

class Person(db.Model):
    firstName = db.StringProperty(required = True)
    nacionality = db.StringProperty(required = True)
    marital_status = db.StringProperty(required = True)
    profession = db.StringProperty(required = True)
    SSN = db.IntegerProperty(required = True)
    driver_license = db.IntegerProperty(required = True)
#    address = db.PostalAddress(required = False)

class Contract(db.Model):
  book_number = db.IntegerProperty(required = True)
  initial_page = db.IntegerProperty(required = True)
  final_page = db.IntegerProperty(required = True)
##  contrac_type = db.StringProperty(required = False, choices=set(["Purchase Agreement", "Rental House", "Rental Car"]))
##  contract_place = db.StringProperty(required = False)
##  contract_date = db.DateProperty (required = True, auto_now = True, auto_now_add = True)

class ContractingParty(db.Model):
  person = db.ReferenceProperty(Person, required=True, collection_name="party_to_contracts")
  condition = db.StringProperty(required = False, choices=set(["buyer", "seller", "renter", "owner", "witness"]))

class MainHandler(webapp2.RequestHandler):
    def get(self):
        first_query = db.GqlQuery("SELECT * FROM Contract ORDER BY date DESC").get()
        if first_query == None:
            numBook = 8
            numInitialPage = 8
            numFinalPage = 8
            first_record = Contract(book_number = 1, initial_page = 0, final_page = 0)
            first_record.put()
            contract = db.GqlQuery("SELECT * FROM Contract ORDER BY date DESC").get()
            numBook = contract.book_number
            numInitialPage = contract.final_page +1
            numFinalPage = numInitialPage
        else:
            contract = first_query
            numBook = first_query
            numInitialPage = 7
            numFinalPage = 7

##        numBook = contract.book_number
##        numInitialPage = contract.final_page +1
##        numFinalPage = numInitialPage
        template_values = {"person": "",
                                       "nacionality": "",
                                       "SSN": "",
                                       "driverLicense": "",
                                       "email":"",
                                       "person_error": "",
                                       "SSN_error": "",
                                       "driverLicense_error": "",
                                       "address": "",
                                       "email_error": "",
                                       "numBook": numBook,
                                       "numInitialPage": numInitialPage,
                                       "numFinalPage": numFinalPage,
                                       }
        template = jinja_environment.get_template('index.html')
        self.response.out.write(template.render(template_values))

    def post(self):
        person_name = self.request.get("person")
        user_nacionality = self.request.get('nacionality')
        user_profession = self.request.get('profession')
        user_maritalStatus = self.request.get('maritalStatus')
        user_SSN = self.request.get('SSN')
        user_email = self.request.get('email')
        user_driverLicense = self.request.get('driverLicense')
        person_error = ""
        SSN_error = ""
        driverLicense_error = ""
        geted_email_error = ""
        address = self.request.get('address')
        contractType = self.request.get("contractType")
        owner = self.request.get("owner")
        witness = self.request.get("witness")
        numBook = self.request.get("numBook")
        numInitialPage = self.request.get("numInitialPage")
        numFinalPage = self.request.get("numFinalPage")

        if (person_name and valid_person(person_name)) and (user_SSN and valid_SSN(user_SSN)) and ((not user_email) or (user_email and valid_email(user_email))):
            contract_record = Contract(book_number = numBook, initial_page = numInitialPage, final_page = numFinalPage)
            contract_record.put()
            contract_id = contract_record.key().id()
            person_record = Person(name = person_name,
                               nacionality = user_nacionality,
                               profession = user_profession,
                               marital_status = user_maritalStatus,
                               SSN = int(user_SSN),
                               driverLicense = int(user_driverLicense))
            person_record.put()
# HERE THE PROBLEM - Contracting party should be a table with ID refering to contract table
 #       contracting_party_record = ContractingParty(person = 1,  )
##            person = db.ReferenceProperty(People, required=True, collection_name="party_to_contracts")
##            condition = db.StringProperty(required = False, choices=set(["buyer", "seller", "renter", "owner", "witness"]))
##            self.redirect('/your_contract?person=%s&nacionality=%s&profession=%s&maritalStatus=%s&SSN=%s&driverLicense=%s&email=%s&witness=%s&owner=%s&contractType=%s&address=%s&numBook=%s&numInitialPage=%s&numFinalPage=%s' % (person_name, user_nacionality, user_profession, user_maritalStatus, user_SSN, user_driverLicense, user_email,
##witness, owner, contractType, address, numBook, numInitialPage, numFinalPage))
            self.redirect('/your_contract?person=%s' % contract_id)

        else:
            if not person_name or not valid_person(person_name):
                person_error = "Oh no!!! this person name isn't valid!"
            if not user_SSN or not valid_SSN(user_SSN):
                SSN_error = "Oh no!!! SSN isn't valid!"
            if user_email and not valid_email(user_email):
                geted_email_error = "Oh no!!! e-mail isn't valid!"
            template_values = {"person": person_name,
                                "nacionality": user_nacionality,
                                "maritalStatus": user_maritalStatus,
                                "profession": user_profession,
                                "SSN": user_SSN,
                                "driverLicense": user_driverLicense,
                                "email": user_email,
                                "person_error": person_error,
                                "SSN_error": SSN_error,
                                "driverLicense_error": user_driverLicense,
                                "address": address,
                                "email_error": geted_email_error}
            template = jinja_environment.get_template('index.html')
            self.response.out.write(template.render(template_values))

class your_contractHandler(webapp2.RequestHandler):
    def get(self):
        contract_id = self.request.get('contract_id')
        contract = db.GqlQuery("SELECT * FROM Contract WHERE __key__ = KEY('Model', contract_id").get()
##        SELECT * FROM Model where __key__ = KEY('Model', <numeric_id>)
        geted_numBook = contract.book_number
        geted_numInitialPage = contract.initial_page
        geted_numFinalPage = contract.final_page
        geted_dateToday = dateToday()
        geted_contractType = contract.contract_type

        person = db.GqlQuery("SELECT * FROM Person ORDER BY date DESC").get()
        geted_person_name = person.name
        geted_user_nacionality = person.nacionality
        geted_user_profession = person.profession
        geted_user_maritalStatus = person.marital_status
        geted_user_SSN = person.SSN
        geted_user_driver_license = person.driver_license


        your_contract = jinja_environment.get_template('your_contract.html')

        your_contract_values = {"person":geted_person_name,
                                "nacionality":geted_user_nacionality,
                                "maritalStatus": geted_user_marital_status,
                                "profession": geted_user_profession,
                                "SSN":geted_user_SSN,
                                "driverLicense":geted_user_driver_license,
                                "address":geted_address,
                                "email":geted_user_email,
                                "contractType":geted_contract_type,
                                "dateContract":geted_dateToday,
                                "numBook":geted_numBook,
                                "numInitialPage":geted_numInitialPage,
                                "numFinalPage":geted_numInitialPage,
                                }
        template = jinja_environment.get_template('index.html')
        self.response.out.write(your_contract.render(your_contract_values))


# ContractingParty.all().ancestor(thecontract).run()
# contract_id = contract.key().id()
# contract_parties = Contract.get_by_id(contract_id)
#http://stackoverflow.com/questions/11294526/how-to-model-a-contract-database-with-several-buyers-or-sellers-using-gae-data
#http://stackoverflow.com/questions/11311461/how-to-query-gae-datastore-to-render-a-template-newbie-level
app = webapp2.WSGIApplication([('/', MainHandler), ('/your_contract', your_contractHandler)],
                              debug=True)

person craftApprentice    schedule 09.07.2012    source источник
comment
Спасибо, @NedBatchelder, только что сделал!   -  person craftApprentice    schedule 09.07.2012
comment
В документах GAE сказано, что GqlQuery.get() возвращает None, если нет результаты найдены.   -  person Joel Cornett    schedule 09.07.2012
comment
Вопрос: как может не быть результатов, если я просто поставил в Контрактах новую запись: first_record = Contract(book_number = 1, initial_page = 0, final_page = 0) first_record.put()?   -  person craftApprentice    schedule 09.07.2012


Ответы (1)


Поскольку в вашей модели контракта нет поля date, ничего не возвращается.

Поскольку хранилище данных не имеет схемы, GQL не может знать, может ли какое-либо из сущностей в вашей модели иметь конкретное поле. Таким образом, в отличие от SQL, он не выдает ошибку при обращении к несуществующему полю: он просто выполняет запрос и, если ничего не найдено, ничего не возвращает.

Я не уверен, почему вы хотите запросить его в любом случае. И даже если бы вы это сделали, вы действительно должны получить его по ключу, возвращенному вызовом put(), а не выполнять запрос: модель окончательной согласованности означает, что данные могут не полностью сохраняться следующим оператором, поэтому запрос не увидит его, тогда как прямое получение по ключу всегда гарантированно это сделает.

person Daniel Roseman    schedule 09.07.2012
comment
Спасибо за ответ и за предложение. Я буду использовать key_id. - person craftApprentice; 09.07.2012