2011-01-19 6 views
5

私たちのDjangoサイトを動かすMySQLデータベースは、いくつかの完全性の問題を引き起こしました。例えば存在しない行を参照する外部キー。私はこの混乱にどのように取り込まれたかについては触れませんが、今私はそれを修正する方法を見ています。Djangoでデータベースの整合性をチェックするツールはありますか?

基本的に私はDjangoサイトのすべてのモデルをスキャンし、すべての外部キーとその他の制約が正しいかどうかをチェックするスクリプトを探しています。うまくいけば、問題の数は十分小さく、手で修正することができます。

私はこれを自分でコーディングすることができましたが、私はここに誰かが良いアイデアを持っていることを期待しています。

私はdjango-check-constraintsを見つけましたが、これは法案にはあまり適していません。今は、これらの問題を防ぐために何か必要はありませんが、他の手順を実行する前に手作業で固定することができます。

他の制約:

  • ジャンゴ1.1.1とアップグレードは、Python 2.5のものに現在のMyISAMテーブル
  • のMySQL 5.0.51(Debianのレニー)を、破るために決定されていますアップグレード可能かもしれませんが、私はむしろ今のところほしくないでしょう

(後でIに変換します。適切なトランザクションサポートのためのnnoDB、およびおそらく将来の同様の問題を防ぐためのデータベースレベルの外部キー制約が含まれます。しかし、それはこの質問の話題ではありません。)

+0

PostGreSQLを使用するだけではなく、MySQLは必須ですか? –

+0

必須ではありません。後でPostgreSQLを検討する予定ですが、DBMSを変更するのは現時点ではあまりにも危険です。 – Thomas

答えて

7

私は自分自身で何かを取り上げました。以下の管理スクリプトはmyapp/management/commands/checkdb.pyに保存してください。中間ディレクトリに__init__.pyファイルがあることを確認してください。

使用法:フルチェックの場合は./manage.py checkdb、 または-e app.Modelを使用して、Modelのモデルをappに含めないようにします。

from django.core.management.base import BaseCommand, CommandError 
from django.core.management.base import NoArgsCommand 
from django.core.exceptions import ObjectDoesNotExist 
from django.db import models 
from optparse import make_option 
from lib.progress import with_progress_meter 

def model_name(model): 
    return '%s.%s' % (model._meta.app_label, model._meta.object_name) 

class Command(BaseCommand): 
    args = '[-e|--exclude app_name.ModelName]' 
    help = 'Checks constraints in the database and reports violations on stdout' 

    option_list = NoArgsCommand.option_list + (
     make_option('-e', '--exclude', action='append', type='string', dest='exclude'), 
    ) 

    def handle(self, *args, **options): 
     # TODO once we're on Django 1.2, write to self.stdout and self.stderr instead of plain print 

     exclude = options.get('exclude', None) or [] 

     failed_instance_count = 0 
     failed_model_count = 0 
     for app in models.get_apps(): 
      for model in models.get_models(app): 
       if model_name(model) in exclude: 
        print 'Skipping model %s' % model_name(model) 
        continue 
       fail_count = self.check_model(app, model) 
       if fail_count > 0: 
        failed_model_count += 1 
        failed_instance_count += fail_count 
     print 'Detected %d errors in %d models' % (failed_instance_count, failed_model_count) 

    def check_model(self, app, model): 
     meta = model._meta 
     if meta.proxy: 
      print 'WARNING: proxy models not currently supported; ignored' 
      return 

     # Define all the checks we can do; they return True if they are ok, 
     # False if not (and print a message to stdout) 
     def check_foreign_key(model, field): 
      foreign_model = field.related.parent_model 
      def check_instance(instance): 
       try: 
        # name: name of the attribute containing the model instance (e.g. 'user') 
        # attname: name of the attribute containing the id (e.g. 'user_id') 
        getattr(instance, field.name) 
        return True 
       except ObjectDoesNotExist: 
        print '%s with pk %s refers via field %s to nonexistent %s with pk %s' % \ 
         (model_name(model), str(instance.pk), field.name, model_name(foreign_model), getattr(instance, field.attname)) 
      return check_instance 

     # Make a list of checks to run on each model instance 
     checks = [] 
     for field in meta.local_fields + meta.local_many_to_many + meta.virtual_fields: 
      if isinstance(field, models.ForeignKey): 
       checks.append(check_foreign_key(model, field)) 

     # Run all checks 
     fail_count = 0 
     if checks: 
      for instance in with_progress_meter(model.objects.all(), model.objects.count(), 'Checking model %s ...' % model_name(model)): 
       for check in checks: 
        if not check(instance): 
         fail_count += 1 
     return fail_count 

私は自分のコードに一切の改善を歓迎するので、私は、このコミュニティのwikiを作ってるんです!

+1

これは素晴らしいですね。 Djangoのコア開発者に連絡し、Django自体でこれを考慮するかどうかを尋ねるべきです。私はそれが巨大な欠けている機能だと思う。 – slacy

+0

どこでlib.progress with_progress_meterが見つかりますか? CHEERS –

+0

私のハードドライブ。それでは、こちらもhttp://pastebin.com/Bdd75Rkk – Thomas

0

トーマスの答えは素晴らしいですが、今はちょっと古いです。 Django 1.8+をサポートするためにas a gistを更新しました。

関連する問題