Calendrier de l'Avent du groupe mixi C'est le deuxième jour.
"Ticket Camp" exploité par Mixy Group est développé avec Python et Django côté serveur.
J'utilise actuellement Django version 1.7.11, qui est une note de ce que j'ai fait lors de la mise à jour vers Django 1.8.
Je suis sûr que certaines parties sont uniques aux camps de billets, mais j'espère que cela aidera ceux qui envisagent de mettre à jour Django.
En premier lieu, la politique de mise à niveau de la bibliothèque de framework de ticket camp dépend quelque peu de mon intuition, et elle est difficile à clarifier, mais généralement les trois règles suivantes sont utilisées. Je peux expliquer.
Le troisième "à moins qu'il n'y ait une raison spécifique" est ambiguë, et la raison est claire dans des cas tels que "Je veux utiliser la fonction X, mais dans ce cas, je dois mettre à jour la bibliothèque Y". Cependant, il y a des cas où il n'y a pas de raison plus profonde que "j'ai essayé de le soulever en passant" comme "Il y avait un cas pour modifier l'API de téléchargement d'image, donc je mettrai à jour Pillow aussi".
Quoi qu'il en soit, je tiens à souligner que nous ne développons pas avec une politique telle que "interdire la mise à niveau de version".
Le deuxième "suivre les mises à jour majeures autant que possible" signifie qu'en tant que personne qui a utilisé Django avant la version 1.0, il est préférable de toujours suivre la dernière version pour maintenir la santé de l'application, et lors de la mise à jour Il est basé sur la règle empirique selon laquelle c'est facile après tout quand cela devient.
De ce point de vue, je voulais mettre à jour depuis Django 1.8 Beta Stage, mais avec quelques échecs de mise à jour Il y avait un point que je n'avais pas touché depuis longtemps. En attendant, Django 1.9 RC est sorti, donc c'est mauvais. J'ai finalement commencé à travailler sérieusement sur la mise à jour de la version.
Puis, lorsque j'ai vérifié le site Django alors que j'allais appuyer sur le bouton de publication de cet article, [Django 1.9 était déjà publié](https://www.djangoproject.com/weblog/2015/dec/01/] django-19-publié /) ・ ・ ・
Au ticket camp, la file d'attente de travaux utilise le standard Celery en Python et le traitement qui nécessite des E / S réseau externes telles que la notification push via AWS SNS , Le traitement de la liste des tickets / de la correspondance des demandes, etc., qui prend un certain temps, sont traités par le processus de travail de Celery.
Lorsque je suis passé à Django 1.8, une erreur s'est produite dans le fichier céleri == 3.1.7
que j'utilisais jusqu'à présent, j'ai donc mis à jour vers la dernière version de céleri == 3.1.9
.
pip install --upgrade celery==3.1.9
Celery est très stable et a beaucoup d'utilisateurs, donc je ne ressens pas beaucoup de risques en ce qui concerne les mises à jour mineures.
Le lanceur de tests unitaires utilise le lanceur de tests django_nose
au lieu de celui standard de Django.
Comme cela a également été corrigé sur une version légèrement plus ancienne, une erreur s'est produite, j'ai donc mis à jour vers la dernière version django_nose == 1.4.2
.
pip install --upgrade django_nose==1.4.2
À partir de Django 1.7, la méthode de configuration de la base de données de test est passée du préfixe TEST_
à l'utilisation d'un dict
indépendant appelé TEST
](https://docs.djangoproject.com/en/1.8/ref/settings) / # test), donc corrigez-le à ce moment.
Avant correction.
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'USER': 'root',
'NAME': 'ticketcamp_dev',
'TEST_NAME': 'test_ticketcamp_dev',
},
}
Modifié.
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'USER': 'root',
'NAME': 'ticketcamp_dev',
'TEST': {
'NAME': 'test_ticketcamp_dev',
},
},
}
loader.get_template_from_string
a disparuIl n'y avait qu'un seul endroit dans le camp de tickets qui utilisait la méthode django.template.loader.get_template_from_string
.
Au minimum, le code ressemble à ceci:
from django.template import loader, Context
tmpl = loader.get_template_from_string(content)
output = tmpl.render(Context(ctxt))
Code comme ça
AttributeError: 'module' object has no attribute 'get_template_from_string'
J'ai commencé à avoir l'erreur.
Apparemment, django.template.loader.get_template_from_string
a été supprimé dans Django 1.8.
Ce type de suppression soudaine de méthode est rare dans Django et ne se produit jamais dans les API publiques. Normalement, un DeprecatedWarning
est affiché et sera aboli dans Django 1.x, vous le remarquerez donc pendant le développement normal.
Cela signifie que cette méthode a été traitée comme une méthode privée et non comme une méthode publique.
Heureusement, dans ce cas, remplacer loader.get_template_from_string
par Template
était une solution simple.
from django.template import Template, Context
tmpl = Template(content)
output = tmpl.render(Context(ctxt))
ForeignKey (unique = True)
est sorti.Ticket camp utilise django.contrib.auth
pour l'enregistrement et l'authentification des utilisateurs, mais c'est un vestige du développement depuis l'époque de Django 1.4, Pattern utilisant l'objet Profile pour donner des informations supplémentaires aux utilisateurs reste toujours.
Le code ressemble à ceci:
# -*- coding: utf-8 -*-
#Ce code a un piège alors ne le copiez pas!
from django.conf import settings
from django.db import models
class Profile(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, unique=True)
#réduction
Après la mise à jour vers Django 1.8 et l'exécution de nœuds de calcul Celery, j'ai reçu l'avertissement suivant:
myapp.Profile.user: (fields.W342) Setting unique=True on a ForeignKey has the same effect as using a OneToOneField.
HINT: ForeignKey(unique=True) is usually better served by a OneToOneField.
Je le savais pour la première fois à ce stade, mais le code ci-dessus est en premier lieu
# -*- coding: utf-8 -*-
from django.conf import settings
from django.db import models
class Profile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL)
#réduction
Il semble que j'aurais dû utiliser ʻOneToOneField () au lieu de
ForeignKey (unique = True) `comme dans. De plus, parce que j'ai fait une erreur dans la première étape, il y avait des endroits où des avertissements similaires ont été émis.
Il me semblait que je devrais le changer en ʻOneToOneField () `comme dans l'indication dans l'avertissement, donc j'ai pu tout réparer à cette occasion.
default
, ʻauto_now, ʻauto_now_add
of DateTimeField
est maintenant exclusifDe là, c'est la production de mises à jour difficiles.
La définition du modèle de ticket camp a le modèle suivant, et la date et l'heure de création du modèle ainsi que la date et l'heure de mise à jour sont automatiquement mises à jour en tant que created_at
, ʻupdated_at`.
from django.db import models
class Ticket(models.Model):
price = models.IntegerField()
count = models.IntegerField()
created_at = models.DateTimeField(default=timezone.now, auto_now_add=True)
updated_at = models.DateTimeField(default=timezone.now, auto_now=True)
Lorsque j'ai essayé d'exécuter du code contenant une telle définition de modèle sur Django 1.8, le travailleur Celery a arrêté de démarrer en raison de l'erreur suivante:
myapp.Ticket.created_at: (fields.E160) The options auto_now, auto_now_add, and default are mutually exclusive. Only one of these options may be present.
myapp.Ticket.updated_at: (fields.E160) The options auto_now, auto_now_add, and default are mutually exclusive. Only one of these options may be present.
La cause est que, comme indiqué dans le message d'erreur, ʻauto_now, ʻauto_now_add
et default
sont des options mutuellement exclusives et ne peuvent pas être spécifiées en même temps.
Pour résoudre ce problème, j'ai pensé aux solutions suivantes.
DateTimeField
afin que l'heure actuelle soit entrée par défaut et que la date et l'heure de création et la date et l'heure de mise à jour soient mises à jour lorsque le modèle est enregistré., et la définition de schéma sur MySQL est forcée d'être ʻupdated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
.
――Autorisez la valeur initiale de ʻupdated_at à
None`.La première option est que je ne veux pas écrire le code moi-même autant que possible, et que Django a fait une telle modification est une bonne correspondance pour ʻauto_now, ʻauto_now_add
, default
en même temps. J'ai abandonné parce que j'avais deviné qu'il serait difficile de faire une telle implémentation.
La deuxième option devait avoir moins de changements de code et moins d'impact sur l'application, mais je l'ai poussée jusqu'à "ne pas définir de schémas qui ne peuvent pas être représentés par le modèle Django". Je l'ai mis en attente du principe de conception.
Nous testons actuellement la mise à jour avec un troisième correctif.
Tout d'abord, dans l'exemple du modèle ci-dessus, created_at
peut supprimer en toute sécurité l'option ʻauto_now_add = True`.
Lorsque vous créez une instance du modèle, l'option default
option timezone.now
est évaluée et la valeur de created_at
devient l'heure actuelle, et cette valeur est enregistrée dans la base de données lorsque vous appelezsave ()
. Parce que ça le sera. (En y réfléchissant, je pense que ʻauto_now_add = True` était inutile en premier lieu.)
Le problème est ʻupdated_at`
updated_at = models.DateTimeField(default=timezone.now)
Ou
updated_at = models.DateTimeField(auto_now=True)
Tu dois choisir.
Dans le premier cas, ʻupdated_at est non
None lorsque l'instance est créée, mais
save () ne met pas à jour la colonne ʻupdated_at
de la base de données.
$ python manage.py shell
>>> from myapp.models import Ticket
>>> ticket = Ticket(price=1000, count=1)
>>> ticket.updated_at is not None
True
>>> ticket.save()
>>> ticket.price = 1500
>>> ticket.save() #Je l'ai changé, mais la base de données a été mise à jour_à n'est pas mis à jour
J'ai envisagé des moyens de mettre à jour ʻupdated_aten utilisant [les signaux
post_save`](https://docs.djangoproject.com/en/1.8/ref/signals/#post-save) , Je pensais que cela poserait un problème car il était difficile de trouver la cause, alors j'ai décidé d'y renoncer.
Ce dernier, l'inconvénient de sélectionner DateTimeField (auto_now = True)
, est que ʻupdated_at est
Nonelorsque l'instance est créée, et l'heure actuelle est le seul moment où
save () est appelé. Cela signifie que le comportement sera reflété dans la propriété updated_at
.
$ python manage.py shell
>>> from myapp.models import Ticket
>>> ticket = Ticket(price=1000, count=1)
>>> ticket.updated_at is not None
False # updated_à est toujours Aucun
>>> ticket.save()
>>> ticket.updated_at is not None
True # save()Devenez non-None pour la première fois après avoir appelé
En d'autres termes, il y a des cas où cela ne fonctionnera pas s'il y a du code qui fait référence à l'instance ʻupdated_at avant
save () `.
Cependant, chaque méthode a des avantages et des inconvénients, et au final, la dernière méthode semblait suivre l'usage attendu par le créateur du framework, j'ai donc adopté la dernière méthode et adopté la méthode suivante. J'ai décidé de le changer avec un sentiment.
from django.db import models
class Ticket(models.Model):
price = models.IntegerField()
count = models.IntegerField()
created_at = models.DateTimeField(default=timezone.now)
updated_at = models.DateTimeField(auto_now=True)
Puisque l'erreur évidente a disparu, lorsque j'ai commencé à vérifier l'opération, il semble qu'elle fonctionne normalement. Après cela, j'ai pensé que si je faisais référence à ʻupdated_at avant
save () ʻet déplaçais la partie où l'erreur s'est produite, je pensais que la mise à jour était terminée, mais il y avait encore des pièges ...
En fait, je voulais atteindre le point où la mise à jour était terminée au moment de la sortie de ce calendrier de l'Avent, mais il y a encore des problèmes non résolus et inexpliqués.
Lorsque vous exécutez le test unitaire,
$ python manage.py test myapp
#Abréviation
django.db.utils.IntegrityError: (1215, 'Cannot add foreign key constraint')
J'ai eu l'erreur.
Il a fallu beaucoup de temps pour rechercher la cause, mais il semble que la cause soit que le schéma ne soit pas reflété correctement lors de la création de la base de données de test unitaire car les migrations
n'existent pas sous chaque répertoire de l'application Django.
Ticket camp a été développé avant l'introduction de Migrations dans Django 1.7, et même lors de la mise à jour vers Django 1.7, "Migrations" Je n'ai pas fait manage.py make migrations
parce que je n'avais pas prévu de l'utiliser, mais il semble que j'ai finalement besoin d'utiliser Migrations.
Revenez au programme d'exécution de test standard de Django, créez manuellement une base de données de test, puis
$ python manage.py test myapp --keepdb
Lorsque j'ai exécuté le test avec l'option --keepdb
, j'ai pu exécuter le test.
Cependant, comme je m'y attendais à l'avance, la définition du modèle de ʻupdated_at a changé, donc j'essayais d'INSÉRER
NULL dans ʻupdated_at
et je n'ai pas pu charger les appareils.
Concernant ce problème
--Fix YAML pour tous les appareils.
non-NULL dans le signal
pre_save` uniquement pendant le test.Nous envisageons une méthode de correction telle que.
Avec Django 1.8, il y a beaucoup d'avertissements pour les fonctions qui seront supprimées dans la 1.9, donc je les écrase un par un.
Avertissement pour django.core.cache.get_cache
.
RemovedInDjango19Warning: 'get_cache' is deprecated in favor of 'caches'
Avant correction.
from django.core.cache improt get_cache
get_cache('default').get('key')
Modifié. Cela a été remplacé mécaniquement.
from django.core.cache improt caches
caches['default'].get('key')
Avertissement pour django.utils.functional.memoize
.
RemovedInDjango19Warning: memoize wrapper is deprecated and will be removed in Django 1.9. Use django.utils.lru_cache instead.
Avertissement pour django.utils.datastructures.SortedDict
. Ce n'est pas parce que le code que j'ai écrit moi-même, mais parce que la version de django-redis que j'utilise est assez ancienne, alors je l'ai mise à jour. Cela semble nécessaire.
RemovedInDjango19Warning: SortedDict is deprecated and will be $
emoved in Django 1.9.
Un avertissement qui se produit lors du pickle
ing d'un modèle Django.
RuntimeWarning: Pickled model instance's Django version is not specified.
Il semble que nous soyons encore au milieu de la mise à jour, mais selon la politique de publication de Django, la 1.7 actuellement utilisée mettra fin à la maintenance lorsque la 2.0 sortira, il est donc absolument nécessaire de passer à la prochaine version 1.8 de LTS. Il y a.
Nous étudions également s'il est possible de migrer de Python 2.7 vers Python 3.5, et je ressens le besoin de suivre la dernière version de Django pour la migration vers Python 3.5.
J'espère régler la question d'ici la fin de l'année et accueillir confortablement la nouvelle année.
Ensuite, akkuma écrira sur le mode Action pour Android.
Recommended Posts