A]问题摘要:
我在模型之间有1到多个层次关系
国家/地区(1) - >城市(许多)
城市(1) - >状态(很多)
所以,只能有一个独特的国家,一个国家只能拥有一个独特的城市,一个城市可以拥有许多地位
我打算使用“get_or_insert”方法来确保我在数据库中维护唯一记录。
B]代码摘录:
1]模型结构 -
class UserReportedCountry(db.Model):
name = db.StringProperty(required=True)
class UserReportedCity(db.Model):
country = db.ReferenceProperty(UserReportedCountry, collection_name='cities')
name = db.StringProperty(required=True)
class UserReportedStatus(db.Model):
city = db.ReferenceProperty(UserReportedCity, collection_name='statuses')
status = db.BooleanProperty()
date_time = db.DateTimeProperty(auto_now_add=True)
2]用于存储从HTML表单检索的数据的代码:
def store_user_data(self):
country_name = self.request.get('selCountry')
user_reported_country = UserReportedCountry.get_or_insert(name=country_name)
user_reported_city = UserReportedCity.get_or_insert( name = self.request.get('city'), country = user_reported_country )
user_reported_status = UserReportedStatus( status = self.request.get('status'), city = user_reported_city)
user_reported_status.put()
问题:
1]从谷歌搜索中,看起来“get_or_insert”需要一个密钥,在我的情况下,在“UserReportedCountry”模型中,我希望国家的名称是主键 在“UserReportedCity”模型中,我希望国家名称+城市名称的组合成为关键。我该怎么做呢?
2]有没有办法在不指定密钥的情况下使用“get_or_insert”,我在stackoverflow上发布了以下帖子(http://stackoverflow.com/questions/4308002/google-app-engine-datastore-get-或插入键名称混淆),并尝试了这个想法,但它没有用。
感谢您阅读,
[EDIT#1]
基于@Josh Smeaton给出的回应的变化摘要
1]现在代码检查用户是否报告了db中是否存在国家/地区。如果用户报告的国家/地区不存在,则代码会创建UserReportedCountry,UserReportedCity并为其附加新状态
2]如果国家/地区存在,则代码会检查用户是否为指定国家/地区报告了城市。
如果找不到城市,则创建城市记录并将其与找到的国家/地区相关联,并附上状态记录。
如果找到了城市,则将状态记录附加到该城市。
请求:
我将非常感谢,如果有人可以请进行代码审查,并告诉我是否犯了任何错误。
谢谢,
代码摘录:
#this method will be used to parse the data the user provided in the html form and store it in the database models
#while maintaing the relationship between UserReportedCountry, UserReportedCity and UserReportedStatus
#BUG, there needs to be error checking to make sure the country , city and status data is invalid or not
#if the data is invalid, then error message needs to be reported and then redirection back to the main page
def store_user_data(self):
#method call to find out the completly filled out UserReportedCity model
user_reported_city = self.find_or_create_user_reported_country_and_city(
self.request.get('selCountry'), self.request.get('city'))
#status is always unique for a user entry, so create a brand new UserReportedStatus everytime.
user_reported_status = UserReportedStatus(status = self.get_user_reported_status(), city = user_reported_city)
user_reported_status.put()
#Here the code needs to find out if there is an existing country/city for the user selection
#1] If the user reported country doesnt exist, create a new country record, create a new city record and return the city record
#2] If the user reported country exists, check if the user reported city is associated with the country.
#if the city exists, then return it. If the city doesnt exists, then create a new city and return it
#example: if the user chooses USA, there needs to be a check if USA is already present or not,
#so that we dont create an additonal USA record
def find_or_create_user_reported_country_and_city(self, country_name, city_name):
country_query_result = db.GqlQuery("SELECT * FROM UserReportedCountry WHERE name = :country_name_value"
,country_name_value = country_name).get()
if (country_query_result == None):
#since the country doesnt exists, create and save the country
user_reported_country = self.create_and_save_user_country_record(country_name)
#Since the country doesnt exist, there cannot be a city record for the given country, so blindly create the record
return self.create_and_save_user_city_record(city_name, user_reported_country)
else:
#Since we found a country, now we need to find whether the user selected city exists for the given country
return self.find_or_create_city_for_country(country_query_result, city_name)
#Check wheter the user selectred city exists in the country
#1] if the city exists return the record back
#2] if the city doesnt exist creaty the city record and return it
def find_or_create_city_for_country(self, country_record, city_name):
city_query_result = db.GqlQuery("SELECT * FROM UserReportedCity WHERE name = :city_name_value AND country =:country_value"
,city_name_value = city_name, country_value = country_record ).get()
if (city_query_result == None):
#Since the city doesnt exist for the given country,
#create the city record, associated it with the country and return the record back
return self.create_and_save_user_city_record(city_name, country_record)
else:
#since the city was found, return the record back
return city_query_result
#method to create a UserReportedCountry record for a given country name
def create_and_save_user_country_record(self, country_name):
user_reported_country = UserReportedCountry(name= country_name)
user_reported_country.put()
return user_reported_country
#method to create a UserReportedCity record for a given city name and a given country record
def create_and_save_user_city_record (self, city_name, country_record):
user_reported_city = UserReportedCity(name = city_name, country = country_record)
user_reported_city.put()
return user_reported_city
[EDIT#2]
在html表单中,使用“post”完成保存数据的调用。你认为这仍然是个问题吗?
<div id="userDataForm">
<form method="post" action="/UserReporting">
<p> Select Country: </p>
<select name="selCountry" id="country">
<!-- By default, we will select users country -->
<script type="text/javascript" language="JavaScript">
document.write("<option value=\"" + geoip_country_name() + "\" selected>"
</script>
:
:
:
<p> Select City: </p>
<div>
<input type="text" name="city" id="city">
<!-- By default, we will select users city -->
<script type="text/javascript" language="JavaScript">
document.getElementById("city").value = geoip_city()
</script>
</div>
<input type="submit" name="report_down" value="Report Down">
<input type="submit" name="report_up" value="Report Up">
</form>
<div>
最初我尝试使用Djangoforms,但我被阻止因为我不知道如何使用javascript在djangoform中选择一个值
答案 0 :(得分:3)
按顺序解决您的问题:
1]从谷歌搜索中,它出现了 “get_or_insert”需要一个键,在我的 “UserReportedCountry”中的大小写 模特,我想要国家的名字 成为主键并在中 “UserReportedCity”模型,我想要的 国名+城市的组合 名字是关键。我该怎么办? 这样做?
只需指定国家/地区的名称,以及国家和城市的串联(例如“USA / San Francisco”作为您传递给get_or_insert
的关键名称。另外,get_or_insert
只是语法糖如下:
def get_or_insert(cls, key_name, **kwargs):
def _tx():
obj = cls.get_by_key_name(key_name)
if obj is None:
return cls(key_name, **kwargs)
else:
return obj
return db.run_in_transaction(_tx)
2]有没有办法使用 “get_or_insert”没有指定 关键,我来了以下 在stackoverflow上发布 (http://stackoverflow.com/questions/4308002/google-app-engine-datastore-get-or-insert-key-name-confusion), 并尝试了这个想法,但它没有用。
这样做真的没有意义。关键是App Engine中模型的唯一唯一字段,您无法在App Engine中执行跨实体组查询,因此除非您指定一个,否则无法执行事务性get-or-insert操作。但是,根据您的要求,使用国家名称和城市名称作为关键名称应该可以正常工作。
答案 1 :(得分:1)
我不知道GAE是否使用内部Meta类,但是在django中,我会使用unique
字段参数作为国家/地区定义的国家/地区名称,unique_together
Meta城市定义中的`('country','name')元组。这将在您忘记get_or_insert正确咒语的任何情况下强制执行完整性。
否则,请对名称(获取操作)进行查找,如果尚不存在,请执行插入操作。基本上,模仿你自己的代码中的get_or_insert。