⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tutorial.txt

📁 Python的一个ORM,现在很火
💻 TXT
📖 第 1 页 / 共 2 页
字号:
Let's create another company to check something. This time we'llflush the store just after adding it.{{{#!python>>> sweets = store.add(Company(u"Sweets Inc."))>>> store.flush()>>> sweets.id2}}}Nice, we've already got the id of the new company. So, what wouldhappen if we changed '''just the id''' for Ben's company?{{{#!python>>> ben.company_id = 2>>> ben.company.nameu'Sweets Inc.'>>> ben.company is sweetsTrue}}}Hah! '''That''' wasn't expected, was it? ;-)Let's commit everything.{{{#!python>>> store.commit()>>>}}}==== Many-to-one reference sets ====So, while our model says that employees work for a single company(we only design normal people here), companies may of course havemultiple employees. We represent that in Storm using reference sets.We won't define the company again. Instead, we'll add a new attributeto the class.{{{#!python>>> Company.employees = ReferenceSet(Company.id, Employee.company_id)>>> }}}Without any further work, we can already see which employees areworking for a given company.{{{#!python>>> sweets.employees.count()1>>> for employee in sweets.employees:...     print "%r, %r" % (employee.id, employee.name)...     print employee is ben...1, u'Ben Bill'True}}}Let's create another employee, and add him to the company, ratherthan setting the company in the employee (it sounds better, at least).{{{#!python>>> mike = store.add(Employee(u"Mike Mayer"))>>> sweets.employees.add(mike)>>>}}}That, of course, means that Mike's working for a company, and so itshould be reflected elsewhere.{{{#!python>>> mike.company_id2>>> mike.company is sweetsTrue}}}==== Many-to-many reference sets and composed keys ====We want to represent accountants in our model as well.  Companies haveaccountants, but accountants may also attend several companies, so we'llrepresent that using a many-to-many relationship.Let's create a simple class to use with accountants, and the relationshipclass.{{{#!python>>> class Accountant(Person):...     __storm_table__ = "accountant"...     def __init__(self, name):...         self.name = name>>> class CompanyAccountant(object):...     __storm_table__ = "company_accountant"...     __storm_primary__ = "company_id", "accountant_id"...     company_id = Int()...     accountant_id = Int()}}}Hey, we've just declared a class with a composed key!Now, let's use it to declare the many-to-many relationship in thecompany.  Once more, we'll just stick the new attribute in theexistent object.  It may easily be defined at class definitiontime.  Later we'll see another way to do that as well.{{{#!python>>> Company.accountants = ReferenceSet(Company.id,...                                    CompanyAccountant.company_id,...                                    CompanyAccountant.accountant_id,...                                    Accountant.id)}}}Done!  The order in which attributes were defined is important,but the logic should be pretty obvious.We're missing some tables, at this point.{{{#!python>>> store.execute("CREATE TABLE accountant "...               "(id INTEGER PRIMARY KEY, name VARCHAR)", noresult=True)...>>> store.execute("CREATE TABLE company_accountant "...               "(company_id INTEGER, accountant_id INTEGER,"...               " PRIMARY KEY (company_id, accountant_id))", noresult=True)}}}Let's give life to a couple of accountants, and register themin both companies.{{{#!python>>> karl = Accountant(u"Karl Kent")>>> frank = Accountant(u"Frank Fourt")>>> sweets.accountants.add(karl)>>> sweets.accountants.add(frank)>>> circus.accountants.add(frank)>>>}}}That's it! Really!  Notice that we didn't even have to add them tothe store, since it happens implicitly by linking to the other objectwhich is already in the store, and that we didn't have to declare therelationship object, since that's known to the reference set.We can now check them.{{{>>> sweets.accountants.count()2>>> circus.accountants.count()1}}}Even though we didn't use the Company``Accountant object explicitly,we can check it if we're really curious.{{{#!python>>> store.get(CompanyAccountant, (sweets.id, frank.id))<CompanyAccountant object at 0x...>}}}Notice that we pass a tuple for the `get()` method, due to thecomposed key.If we wanted to know for which companies accountants are working,we could easily define a reversed relationship:{{{#!python>>> Accountant.companies = ReferenceSet(Accountant.id,...                                     CompanyAccountant.accountant_id,...                                     CompanyAccountant.company_id,...                                     Company.id)>>> [company.name for company in frank.companies][u'Circus Inc.', u'Sweets Inc.']>>> [company.name for company in karl.companies][u'Sweets Inc.']}}}==== Joins ====Since we've got some nice data to play with, let's try to make afew interesting queries.Let's start by checking which companies have at least one employeenamed Ben.  We have at least two ways to do it.First, with an implicit join.{{{#!python>>> result = store.find(Company,...                     Employee.company_id == Company.id,...                     Employee.name.like(u"Ben %"))...>>> [company.name for company in result][u'Sweets Inc.']}}}Then, we can also do an explicit join.  This is interesting for mappingcomplex SQL joins to Storm queries.{{{#!python>>> origin = [Company, Join(Employee, Employee.company_id == Company.id)]>>> result = store.using(*origin).find(Company, Employee.name.like(u"Ben %"))>>> [company.name for company in result][u'Sweets Inc.']}}}If we already had the company, and wanted to know which of his employeeswere named Ben, that'd have been easier.{{{#!python>>> result = sweets.employees.find(Employee.name.like(u"Ben %"))>>> [employee.name for employee in result][u'Ben Bill']}}}==== The Storm base class ====So far we've been defining our references and reference sets usingclasses and their properties.  This has some advantages, like beingeasier to debug, but also has some disadvantages, such as requiringclasses to be present in the local scope, what potentially leads tocircular import issues.To prevent that kind of situation, Storm supports defining thesereferences using the stringified version of the class and propertynames.  The only inconvenience of doing so is that all involvedclasses must inherit from the `Storm` base class.Let's define some new classes to show that.  To expose the point,we'll refer to a class before it's actually defined.{{{#!python>>> class Country(Storm):...     __storm_table__ = "country"...     id = Int(primary=True)...     name = Unicode()...     currency_id = Int()...     currency = Reference(currency_id, "Currency.id")>>> class Currency(Storm):...     __storm_table__ = "currency"...     id = Int(primary=True)...     symbol = Unicode()>>> store.execute("CREATE TABLE country "...               "(id INTEGER PRIMARY KEY, name VARCHAR, currency_id INTEGER)",...               noresult=True)>>> store.execute("CREATE TABLE currency "...               "(id INTEGER PRIMARY KEY, symbol VARCHAR)", noresult=True)}}}Now, let's see if it works.{{{#!python>>> real = store.add(Currency())>>> real.id = 1>>> real.symbol = u"BRL">>> brazil = store.add(Country())>>> brazil.name = u"Brazil">>> brazil.currency_id = 1>>> brazil.currency.symbolu'BRL'}}}Questions!? ;-)==== Loading hook ====Storm allows classes to define a few different hooks are calledto act when certain things happen.  One of the interesting hooksavailable is the `__storm_loaded__` one.Let's play with it.  We'll define a temporary subclass of Personfor that.{{{#!python>>> class PersonWithHook(Person):...     def __init__(self, name):...         print "Creating %s" % name...         self.name = name......     def __storm_loaded__(self):...         print "Loaded %s" % self.name>>> earl = store.add(PersonWithHook(u"Earl Easton"))Creating Earl Easton>>> earl = store.find(PersonWithHook, name=u"Earl Easton").one()>>> del earl>>> collected = gc.collect()>>> earl = store.find(PersonWithHook, name=u"Earl Easton").one()Loaded Earl Easton}}}Note that in the first find, nothing was called, since the objectwas still in memory and cached.  When we deleted the object andensured that it was collected, the object had to be retrievedfrom the database again, and thus the hook was called (and notthe constructor!).==== Auto-reloading values ====Storm offers some special values that may be assigned to attributesunder its control.  One of these values is `AutoReload`.  When used,it will make the object automatically reload the value from thedatabase when touched.  Even primary keys may benefit from its use,as shown below.{{{>>> from storm.locals import AutoReload>>> ruy = store.add(Person())>>> ruy.name = u"Ruy">>> print ruy.idNone>>> ruy.id = AutoReload>>> print ruy.id4}}}This may be set as the default value for any attribute, making theobject be automatically flushed if necessary.==== Expression values ====Besides auto-reloading, it's also possible to assign a value thatwill run a SQL expression to update a value.  For instance:{{{#!pythonfrom storm.locals import SQL>>> ruy.name = SQL("(SELECT name || ' Ritcher' FROM person WHERE id=4)")>>> ruy.nameu'Ruy Ritcher'}}}That's a silly example, of course, but there are many useful waysto use that feature.==== Much more! ====There's a lot more about Storm to be shown.  This tutorial is just away to get initiated on some of the concepts.  While your questionsare not answered somewhere else, feel free to ask them in the mailinglist.## vim:ts=4:sw=4:et:ft=moin

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -