Модель движка приложения, вопрос get_or_insert относительно первичного ключа и составных ключей - PullRequest
1 голос
/ 26 марта 2011

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] В поиске Google, по-видимому, для "get_or_insert" требуется ключ. В моем случае в модели "UserReportedCountry" я хочу, чтобы название страны было первичным ключом, а вмодель «UserReportedCity», я хочу, чтобы комбинация названия страны + названия города была ключевой.Как мне это сделать?

2] Есть ли способ использовать "get_or_insert" без указания ключа, я наткнулся на следующую публикацию на stackoverflow (/2439623/google-app-engine-oshibka-hranilischa-dannyh-getorinsert-keyname), и попробовал идею, но она не работала.

Спасибо за чтение,

[EDIT # 1]

Сводка изменений, основанная на ответе, полученном @Josh Smeaton

1] Теперь код проверяет, присутствует ли указанная пользователем страна в базе данных или нет. Если указанная пользователем страна отсутствует, то код создает UserReportedCountry, UserReportedCity и присоединяет к нему новый статус

2] Если страна присутствует, то код проверяет, присутствует ли указанный пользователем город для данной страны.

Если город не найден, то создайте запись города и свяжите ее снайденная страна и прикрепите запись статуса.

Если город найден, то прикрепите к нему запись статуса.

Запрос:

Я будувысоко ценю, если сомeone может сделать обзор кода и сообщить мне, если я делаю какие-либо ошибки.

Спасибо,

Отрывки кода:

#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

Ответы [ 2 ]

3 голосов
/ 28 марта 2011

Чтобы ответить на ваши вопросы по порядку:

1] В поиске Google появляется «get_or_insert» требуется ключ. В моем случае в модели «UserReportedCountry» мне нужно имястрана должна быть первичным ключом, и в модели «UserReportedCity» я хочу, чтобы комбинация названия страны + города была ключевой.Как мне это сделать?

Просто укажите название страны и объединение страны и города (например, "США / Сан-Франциско" в качестве имен ключей, которые вы передаете 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» без указания ключа, я наткнулся на следующую записьon stackoverflow (/2439623/google-app-engine-oshibka-hranilischa-dannyh-getorinsert-keyname), и попробовал идею, но она не сработала.

Это на самом деле не имеет смысла. Ключ - это единственное уникальное поле для модели в App Engine, иВы не можете выполнять запросы между группами сущностей в App Engine, поэтому, если вы не укажете один из них, невозможно выполнить транзакционную операцию получения или вставки. Однако, учитывая ваши требования, использование названия страны и города в качестве имени ключа должноработать просто отлично.

1 голос
/ 26 марта 2011

Я не знаю, использует ли GAE внутренний мета-класс, но в django я бы использовал параметр поля unique для названия страны для определения страны и unique_together кортежа мета для `( «страна», «имя») в определении города. Это обеспечит целостность в любом случае, если вы забудете правильное заклинание get_or_insert.

В противном случае выполните поиск по имени (операция get) и, если его еще нет, выполните вставку. По сути, имитируйте get_or_insert в вашем собственном коде.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...