Cours Python pour apprendre la programmation web avancé avec Divmod Nevow


Télécharger Cours Python pour apprendre la programmation web avancé avec Divmod Nevow

★★★★★★★★★★3.5 étoiles sur 5 basé sur 1 votes.
Votez ce document:

Télécharger aussi :


Cours Python pour apprendre la programmation web avancé avec Divmod Nevow

Axiome Divmod

Axiom est une base de données d’objets dont le but principal est de fournir une couche orientée objet avec ce que nous considérons être les aspects clés de l’utilisation de l’OA, à savoir le polymorphisme et la distribution des messages, sans nuire à la puissance d’un SGBDR. Il est conçu pour «ressentir la Pythonique», sans encourager le comportement ORM typique tel que la programmation de la pomme de terre. Axiom fournit une interface complète à la base de données, ce qui vous suggère fortement de ne pas écrire votre propre code SQL. La métaprogrammation est difficile et dangereuse (comme le montrent de nombreuses attaques par injection SQL). L'écriture de votre propre SQL est toutefois toujours possible et Axiom dispose de plusieurs méthodes qui renvoient des fragments du schéma généré si vous souhaitez les utiliser dans vos propres requêtes. Actuellement, Axiom ne prend en charge que SQLite et ne dispose d'aucune fonctionnalité permettant de gérer les accès simultanés. Nous prévoyons d’en ajouter quelques-unes plus tard et, peut-être, de prendre en charge d’autres bases de données à l’avenir. Jetez un coup d’œil à Concurrence et évolutivité pour plus d’informations - nous la mettrons à jour à mesure que la communauté progressera sur ces questions.

Indice

Concurrence et évolutivité

Plusieurs questions semblent continuer à venir concernant ces questions; c'est une tentative de résumer la discussion autour d'eux.

Pourquoi l'API est-elle synchrone?

En règle générale, l’accès à la base de données via le backend SQLite est suffisamment rapide pour que les opérations de la base de données ne se bloquent pas assez longtemps pour être une source de préoccupation.

Êtes-vous sûr?

Sorte de. L'utilisation actuelle semble indiquer que cela fonctionne très bien, mais vous devez effectuer vos propres tests pour déterminer si ce modèle est adapté à vos habitudes d'utilisation.

Est-ce que c'est thread-safe, cependant?

Non. L'accès à un magasin à partir de différents threads va casser. Accéder à différents magasins, même avec la même base de données SQLite, est acceptable.

Mais comment atteindre l'évolutivité alors?

Utilisez plusieurs bases de données. Par exemple, Divmod Mantissa a des magasins par utilisateur et par application.

Et si cela ne suffisait pas?

Si vous avez besoin d'une concurrence plus fine, alors exécuter des transactions dans des threads séparés est un moyen d'y parvenir.

Le blog de Glyph a plus à ce sujet; voir également le numéro 537 qui couvre la mise en œuvre de ce modèle par DivmodAxiom.

Tutoriel Axiom

Série occasionnelle de JP Calderone sur l’utilisation d’Axiom et de Mantissa. Via le blog de JP.

  • Comment créer un serveur Mantissa
  • Configuration des ports HTTP et HTTPS et du contenu statique
  • Configuration de ressources statiques sur un serveur Mantissa
  • Redirection des journaux de requêtes HTTP
  • Ajout de plugins Axiomatic
  • Requêtes Axiom
  • Powerups Axiom

Pourquoi utiliser Axiom?

Parce que c’est génial, bien sûr! Plus spécifiquement, il s’agit d’une base de données relationnelle objet qui ...

Réellement relationnel

Axiom impose un mappage extrêmement simple entre les tables et les classes: 1 à 1. Vos tables ont un comportement.

Ils peuvent se référer les uns aux autres. Si vous connaissez le modèle relationnel, mais que vous étudiez OO et souhaitez utiliser certaines de ses fonctionnalités, Axiom n’explosera pas votre cerveau avec un million de nouveaux concepts. Après avoir appris le fonctionnement de quelques expressions Python simples, vous pourrez commencer à fonctionner.

Axiom respecte également le modèle relationnel et vous permet d'effectuer des requêtes sur des groupes d'éléments à la fois, sans les charger au préalable. La prise en charge des mises à jour et des suppressions sans chargement d’éléments sera également mise en œuvre avant la publication de la version 1.0. Vous n'avez pas besoin d'écrire vos propres boucles "for" ou votre propre code SQL pour charger une requête jointe. Pas de pomme de terre

La programmation.

Réellement orienté objet

Les tables ont un comportement. Vous pouvez avoir une référence à un élément arbitraire. Les éléments peuvent exister en dehors de la base de données. Vous pouvez mélanger du code à partir de classes d’utilitaires pour donner à vos éléments des méthodes supplémentaires, sans affecter leur schéma. Les types de base de données simples, tels que les chaînes et les entiers, peuvent être mappés en valeurs Python complexes et riches, telles que les adresses électroniques ou une classe décimale à virgule fixe.

Extensible

Le mécanisme "Powerups" d’Axiom vous permet d’améliorer une base de données, ou toute ligne de la base de données, avec des fonctionnalités supplémentaires.

actif

Axiom n’est pas une base de données statique. C'est dynamique, ça contient des comportements.

Vous pouvez, par exemple, installer un planificateur qui exécutera des tâches à des heures spécifiques lorsque la base de données est ouverte.

Twisted-friendly

L’ordonnanceur susmentionné est mis en oeuvre en utilisant le réacteur Twisted Axiom a été explicitement conçu pour être utilisé avec des événements et s’intègre parfaitement dans un environnement basé sur Twisted.

Preuve de l'avenir

Les applications Axiom peuvent continuer à fonctionner pendant la mise à niveau d’un schéma à un autre (avec un jeu de données partiel disponible). Les mises à niveau sont gérées automatiquement et le code de mise à niveau peut être séparé du code de votre application. Vous pouvez même écrire des mises à niveau impliquant des relations complexes entre plusieurs lignes.

Simple

Axiom vous donne le pouvoir d'une base de données SQL sans avoir à générer du code à partir du code.

Travailler avec les bases de données Axiom est facile. Le moteur SQLite sous-jacent est déjà assez simple à utiliser, mais Axiom n’ajoute pas de niveaux de complexité qui vous gênent. Comparez le chargement d'une ligne et sa manipulation avec une classe Python: from axiom.store import Store

s = Store ('store.axiom')

x = s.getItemByID (0)

depuis pysqlite2 import dbapi2

depuis mymodule importer MyClass

con = dbapi2.connect ('store.sqlite')

cur = con.cursor ()

cur.execute ('select * from my_table où oid = 0')

row = con.fetchall () [0]

x = MyClass (rangée)

Dans ce cas, l'exemple Axiom est en réalité beaucoup plus court!

Sûr

Axiom maintient vos objets en mémoire à jour avec ce qui se passe dans la base de données, même lorsque des transactions doivent être annulées. Pas besoin de gérer vos propres connexions. Plus besoin d'oublier de valider une transaction, ni de revenir en arrière dans un gestionnaire d'erreurs.

Axiom n’expose aucun code SQL au développeur d’application. Axiom fait également très attention à la génération SQL en interne: il n’utilise pas la concaténation de chaînes sauf dans les cas absolument nécessaires, mais utilise plutôt? interpolation. Cela signifie que votre site sera totalement sécurisé contre les attaques par injection SQL.

Axiom veille également à ce que vos objets en mémoire correspondent à ceux de la base de données. En cas d'échec d'une transaction, Axiom enregistre l'erreur et ramène tous les objets Python impliqués dans la transaction à l'état dans lequel ils se trouvent après leur annulation.

Cela apporte la sécurité des transactions de base de données dans votre code Python.

Mises sous tension

Un powerup est un type de plugin Axiom. Zéro ou plusieurs bonus (éléments Axiom) peuvent être enregistrés dans un autre élément axiome (tant qu'il se trouve dans le même magasin) et peuvent être récupérés en fonction de leur interface, soit par adaptation normale du sujet (auquel cas la mise sous tension la plus prioritaire). est retourné), ou en tant que groupe (par ordre de priorité) en utilisant

axiom.item.Item.powerupsFor.

Voir également

  • classe axiom.item.Empowered

Référence

item.Item (store = store.Store, ** kw)

Une classe décrivant un objet dans un magasin Axiom. Votre sous-classe de axiom.item.Item doit définir les attributs suivants:

  • typeName: chaîne identifiant de manière unique ce schéma de classe dans le magasin.
  • schemaVersion: entier indiquant la version du schéma. Voir Upgraders.

Vous voudrez également définir d'autres attributs, qui doivent être des attributs spéciaux de la classe Axiom. Une sélection de types standard est déjà définie dans le module axiom.attributes.

Un exemple simple:

d'axiom import item, attributs

classe ShopProduct (item.Item):

typeName = 'ShopProduct'

schemaVersion = 1

nom = attributs.text (allowNone = False)

prix = attributs.intégré (allowNone = False)

stock = attributs.intégré (valeur par défaut = 0)

def __repr __ (auto):

return '<ShopProduct name ='% s 'price ='% d 'stock ='% d '>'% (self.name, self.

→ prix, auto.stock)



Limites

  • Les éléments Axiom ne prennent en charge qu'un seul niveau d'héritage. Par exemple, vous ne pouvez pas écrire une sous-classe de la classe ShopProduct ci-dessus. Ceci est voulu par la conception, et vous êtes plutôt encouragé à explorer la composition et l’adaptation des objets.

store.Store ([dbdir = None [, debug = False [, parent = None [, idInParent = None]]]])

Une base de données dans laquelle les éléments Axiom peuvent être stockés. Un magasin Axiom peut être instancié avec un paramètre dbdir. Dans ce cas, il sera conservé dans le système de fichiers par le chemin indiqué. Sinon, s'il est instancié sans paramètre dbdir, le magasin n'existera en mémoire que pendant la durée de vie du processus python.

d'axiom import store

s = store.Store ('/ tmp / example.axiom')

s = store.Store () # Un magasin en mémoire

Si debug = True, le magasin imprimera toutes les commandes SQL au fur et à mesure de leur envoi à la base de données SQLite sous-jacente.

Ajouter des articles à la boutique

p = ShopProduct (magasin = s, nom = u'Tea Bags ', prix = 2)

C'est tout ce qu'on peut en dire. L'élément retourné peut être traité comme n'importe quel autre objet Python. Les modifications apportées sont automatiquement conservées dans le magasin.

>>> nom de famille

sacs à thé

>>> p.stock

0

>>> p.stock + = 20

>>> p.stock

20

Si vous souhaitez éviter les doublons, vous pouvez utiliser la méthode findOrCreate (voir ci-dessous).

Récupérer des articles du magasin

  • getItemByID (storeID [, default = _noItem]):

Renvoie l’élément avec le «storeID» donné. Si aucun élément ne correspond, KeyError ou ‘défaut’ s’il est spécifié. Chaque article de la boutique a un attribut unique «storeID».

  • findFirst '' '(userItemClass [, ** attrs]):

Renvoie le premier élément de la classe 'userItemClass' ou None. La requête peut être davantage affinée en spécifiant "attrs", par exemple

>>> s.findFirst (ShopProduct, name = u'Tea Bags ')

<ShopProduct name = 'Sachets de thé' prix = '2' stock = '20 '>

  • findOrCreate (userItemClass [, ** attrs]):

Renvoie le premier élément de la classe ‘userItemClass’ ou le crée s’il n’existe pas déjà. par exemple.

>>> s.findOrCreate (ShopProduct, nom = u'Pot Noodle ')

TypeError: attribut `= integer () <ShopProduct.price>` _ ne doit pas être None, mais nous devons donner tous les attributs nécessaires à la création du nouvel élément.

>>> s.findOrCreate (ShopProduct, nom = u'Pot Noodle ', prix = 3)

<ShopProduct name = 'Pot de nouilles' price = '3' stock = '0'>

  • requête (tableClass [, comparaison = Aucune [, limite = Aucune [, offset = Aucune [,

sort = None [, justCount = False [, sumAttribute = None]]]]]]):

Générateur de retours d'éléments correspondant à la classe 'tableClass' et à la comparaison. Limité à la longueur «limite» au-delà de «offset». Trié par attribut "trier". Exemples:

>>> 'Tous les produits'

>>> [x.name for x in s.query (ShopProduct)]

[u'Tea Bags ', u'Pot Noodle']

>>> 'Produits en stock'

>>> [x.name for x in s.query (ShopProduct, ShopProduct.stock> 0)]

[u'Tea Bags ']

>>> 'Produits en stock ET qui coûtent moins de 5'

>>> d'axiom.attributes import AND, OR

>>> [x.name for x in s.query (ShopProduct, ET (ShopProduct.stock> 0, ShopProduct).

→ prix <5))]

[u'Tea Bags ']

Vous avez eu l'idée. Essayez d’activer le débogage du magasin et vous aurez une idée de ce qui se passe dans les coulisses.

>>> s.debug = True

>>> [x.name for x in s.query (ShopProduct, sort = ShopProduct.stock.ascending)]

** SELECT item_ShopProduct_v1 .oid, item_ShopProduct_v1. * FROM item_ShopProduct_

→ v1 ORDER BY item_ShopProduct_v1.`ASC -

********** COMMIT **********

lastrow: aucun

résultat: [(4, u'Pot Noodle ', 3, 0), (3, u'Tea Bags', 2, 20) <stock]> `_

[u'Pot Noodle ', u'Tea Bags']

Axiom est également capable de construire des requêtes plus complexes impliquant des jointures de table en arrière-plan. Pour des exemples plus complets, voir axiom-examples.

Sous-magasin

Un magasin qui existe également en tant qu'élément d'un magasin parent.

  • classe axiom.substore.SubStore

Mises sous tension

Un powerup est un type de plugin Axiom. Zéro ou plusieurs bonus (éléments Axiom) peuvent être enregistrés dans un autre élément axiome (tant qu'il se trouve dans le même magasin) et peuvent être récupérés en fonction de leur interface, soit par adaptation normale du sujet (auquel cas la mise sous tension la plus prioritaire). est retourné), ou en tant que groupe (par ordre de priorité) en utilisant

axiom.item.Item.powerupsFor.

  • classe axiom.item.Empowered

Upgraders

?

Exemples: Shop

depuis l'interface d'importation de zope.interface, implémente

depuis axiom.attributes import AND, OR

d'axiom item item, attributs, séquence

à partir de l'heure d'importation d'epsilon.extime

classe Person (item.Item):

'' 'Une personne ici n'est pas spécifique à la partie achats de l'application.

Il a peut-être été défini ailleurs, par exemple lors de l'inscription à un système de demandes de renseignements.

Nous ne pouvons pas sous-classer Person mais nous pouvons brancher les attributs spécifiques de notre boutique et

˓ → méthodes utilisant le modèle de démarrage Axiom.

'' '

typeName = 'Personne'

schemaVersion = 1

nom = attributs.text (allowNone = False)

dob = attributs.timestamp (allowNone = False)

def __repr __ (auto):

return '<Nom de la personne ='% s 'dob ='% s '>'% (self.name, self.dob.

→ asISO8601TimeAndDate ())

Classe IShopCustomer (Interface):

passer

classe ShopCustomer (item.Item):

'' 'Un ShopCustomer est un bonus pour personne.' ''

implémente (IShopCustomer)

typeName = 'ShopCustomer'

schemaVersion = 1

installedOn = attributs.reference ()

def installOn (auto, autre):

assert self.installedOn est None, 'impossible d'installer ShopCustomer sur plus de

→ une personne '

self.installedOn = autre

other.powerUp (self, IShopCustomer)

'' 'Méthodes spécifiques au client' ''

def getProductsOrdered (auto):

# Exemple de requête de jointure interne

retourne self.store.query (

ShopProduct,

ET(

ShopOrder.customer == self.installedOn,

ShopProductOrdered.order == ShopOrder.storeID,

ShopProductOrdered.product == ShopProduct.storeID

)

)

def getOrders (auto):

retourne self.store.query (

ShopOrder,

ShopOrder.customer == self.installedOn

)

classe ShopProduct (item.Item):

typeName = 'ShopProduct'

schemaVersion = 1

nom = attributs.text (allowNone = False)

prix = attributs.intégré (allowNone = False)



stock = attributs.intégré (valeur par défaut = 0)

def __repr __ (auto):

return '<ShopProduct name ='% s 'price ='% d 'stock ='% d '>'% (self.name, self.

→ prix, auto.stock)

classe ShopProductOrdered (item.Item):

'' 'Lie un produit et une quantité de produit à une commande.' ''

typeName = 'ShopProductOrdered'

schemaVersion = 1

order = attributs.reference (allowNone = False)

product = attributs.reference (allowNone = False)

quantité = attributs.intégré (par défaut = 1)

classe ShopOrder (item.Item):

typeName = 'ShopOrder'

schemaVersion = 1

client = attributs.reference (allowNone = False)

purchaseDate = attributs.timestamp (allowNone = False)

def __init __ (auto, ** kw):

IShopCustomer (kw ['client'])

super (ShopOrder, self) .__ init __ (** kw)

def addProduct (self, produit, quantité = 1):

po = self.store.findOrCreate (

ShopProductOrdered,

ordre = soi,

produit = produit)

quantité.po. = quantité

def getProducts (auto):

return self.store.query (ShopProductOrdered, ShopProductOrdered.order == self)

def getTotalPrice (auto):

#XXX: Axiom émettra plusieurs requêtes ici, mais cela pourrait se faire en un seul SQL

˓ → requête. Existe-t-il un moyen d'émettre une telle requête?

total = 0

pour p dans self.getProducts ():

total + = prix.produit * * quantité

retour total

def __repr __ (auto):

return '<client ShopOrder ='% s 'PurchaseDate ='% s 'items ='% s '>'% (self.

→ customer.name, self.purchaseDate.asISO8601TimeAndDate (), self.items)

def populateStore (s):

customerDetails = [

(u'Joe Bloggs ',' 1977-05-08 '),

(Jane Doe, 1959-05-22),

]

pour le nom, dob dans customerDetails:

p = Personne (magasin = s, nom = nom, dob = Time.fromISO8601TimeAndDate (dob))

# C'est ici que nous mettons la personne sous tension avec des bits supplémentaires ShopCustomer

ShopCustomer (store = s) .installOn (p)

produits = [

ShopProduct (magasin = s, nom = u'Tea Bags ', prix = 2),

ShopProduct (magasin = s, nom = u'Cornflakes ', prix = 3),

ShopProduct (magasin = s, nom = u'Lemonade ', prix = 4),

ShopProduct (magasin = s, nom = u'Peanuts ', prix = 5),

]

quantités = [1,2,4]

pour c à la requête (ShopCustomer):

o = ShopOrder (magasin = s, client = c.installedOn, purchaseDate = Time ())

o.addProduct (random.choice (produits), random.choice (quantités))

o.addProduct (random.choice (produits), random.choice (quantités))

si __name__ == '__main__':

importer au hasard

d'axiom import store

s = store.Store (debug = False)

populateStore (s)

'' 'Nous voulons seulement une personne qui est aussi un ShopCustomer.

Nous recherchons donc ShopCustomer mais prenons une référence à la personne au sein de

˓ → (installedOn)

Si vous voulez que la référence de personne se comporte comme un client, adaptez-la à l'interface IShopCustomer '' '

p = s.findFirst (ShopCustomer) .installedOn

print [x.name for x dans IShopCustomer (p) .getProductsOrdered ()]

print '% s a commandé les produits suivants depuis son enregistrement:'% p.name

print 'Une ventilation des commandes de% s'% p.name

print ['Items:% s, Total:% d'% (['% s X% d'% (y.product.name, y.quantité)) pour y dans x.

Get → getProducts ()], x.getTotalPrice ()) pour x dans IShopCustomer (p) .getOrders ()]

Mini HOWTO sur la transition

Remarques

Quelques points avec des choses à faire pour passer du code de pré-dépendance aux nouvelles API.

  • axiom.item.InstallableMixin a été supprimé, car il est inutile, de même que l'attribut installedOn qui était dans les sous-classes de celles-ci. powerup.installedOn () est maintenant orthographié axiom.dependency.

installedOn (mise sous tension).

  • powerup.installOn (cible) est maintenant orthographié axiom.dependency.installOn (mise sous tension, cible). Voir aussi axiom.dependency.uninstallFrom (mise sous tension, cible).
  • Au lieu de mettre explicitement la cible sous tension dans installOn, définissez l'attribut de classe powerupInterfaces sur une séquence d'interfaces ou de n-uplets (d'interface, de priorité).
  • Si vous implémentez INavigableElement, vous avez besoin de quelque chose comme:

privateApplication = dependOn (PrivateApplication)

  • Déclarez d’autres dépendances de vos bonus, le cas échéant.
  • Débarrassez-vous de vos classes Benefactor / BenefactorFactory et passez plutôt une

séquence installablePups lors de la construction de votre offre. Par exemple:

installablePowerups = [

(u'Operator admin ', u'Operator administration', OperatorAdmin),

(u'Reports ', u'Fonction de reporting de données', Rapports),

]

  • TODO: écrire des correcteurs

Exemple

xmantissa.webapp a été migré dans le cadre de cette modification. Cela sert de bon exemple et sera (incomplètement) présenté ci-dessous à titre de démonstration. Les exemples ci-dessous illustrent l'essentiel du code et se concentrent uniquement sur les modifications. Veuillez vous référer aux différentes versions de fichiers pour une représentation complète.

Avant (référence):

Classe PrivateApplication (Item, PrefixURLMixin):

...

implémente (ISiteRootPlugin, IWebTranslator)

...

installedOn = référence ()

...

def installOn (auto, autre):

super (PrivateApplication, self) .installOn (autre)

other.powerUp (self, IWebTranslator)

def findOrCreate (* a, ** k):

renvoie other.store.findOrCreate (* a, ** k)

findOrCreate (StaticRedirect,

sessioned = True,

sessionless = False,

prefixURL = u '',

targetURL = u '/' + self.prefixURL) .installOn (other, -1)

findOrCreate (CustomizedPublicPage) .installOn (autre)

findOrCreate (AuthenticationApplication)

findOrCreate (PreferenceAggregator) .installOn (autre)

findOrCreate (DefaultPreferenceCollection) .installOn (autre)

findOrCreate (SearchAggregator) .installOn (autre)

...



7