1. ホーム
  2. python

[解決済み] OperationalError, no such column. ジャンゴ

2022-02-18 05:58:11

質問

私はdjangoの初心者ですが、djangoproject.comのチュートリアルを何のエラーもなく終えることができました。私は今、以下のサイトで見つけた Django REST フレームワークのチュートリアルを進めています。 http://www.django-rest-framework.org/ ほぼ終了し、認証を追加したところです。今、私は取得しています。

OperationalError at /snippets/
no such column: snippets_snippet.owner_id
Request Method: GET
Request URL:    http://localhost:8000/snippets/
Django Version: 1.7
Exception Type: OperationalError
Exception Value:    
no such column: snippets_snippet.owner_id
Exception Location: /Users/taylorallred/Desktop/env/lib/python2.7/site-packages/django/db/backends/sqlite3/base.py in execute, line 485
Python Executable:  /Users/taylorallred/Desktop/env/bin/python
Python Version: 2.7.5
Python Path:    
['/Users/taylorallred/Desktop/tutorial',
 '/Users/taylorallred/Desktop/env/lib/python27.zip',
 '/Users/taylorallred/Desktop/env/lib/python2.7',
 '/Users/taylorallred/Desktop/env/lib/python2.7/plat-darwin',
 '/Users/taylorallred/Desktop/env/lib/python2.7/plat-mac',
 '/Users/taylorallred/Desktop/env/lib/python2.7/plat-mac/lib-scriptpackages',
 '/Users/taylorallred/Desktop/env/Extras/lib/python',
 '/Users/taylorallred/Desktop/env/lib/python2.7/lib-tk',
 '/Users/taylorallred/Desktop/env/lib/python2.7/lib-old',
 '/Users/taylorallred/Desktop/env/lib/python2.7/lib-dynload',
 '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7',
 '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-darwin',
 '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-tk',
 '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-mac',
 '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-mac/lib-scriptpackages',
 '/Users/taylorallred/Desktop/env/lib/python2.7/site-packages']
Server time:    Sat, 11 Oct 2014 07:02:34 +0000

StackOverflowだけでなく、ウェブ上のいくつかの場所で解決策を探しましたが、一般的に問題は私のデータベースにあり、それを削除してから作り直す必要があるようです。私はこれを数回行いました。チュートリアルでは、データベースを削除してその時点で作り直すようにとさえ言われています。 以下は私の models.py :

from django.db import models
from pygments.lexers import get_all_lexers
from pygments.styles import get_all_styles
from pygments.lexers import get_lexer_by_name
from pygments.formatters.html import HtmlFormatter
from pygments import highlight


LEXERS = [item for item in get_all_lexers() if item[1]]
LANGUAGE_CHOICES = sorted([(item[1][0], item[0]) for item in LEXERS])
STYLE_CHOICES = sorted((item, item) for item in get_all_styles())



class Snippet(models.Model):
    owner = models.ForeignKey('auth.User', related_name='snippets')
    highlighted = models.TextField()
    created = models.DateTimeField(auto_now_add=True)
    title = models.CharField(max_length=100, blank=True, default='')
    code = models.TextField()
    linenos = models.BooleanField(default=False)
    language = models.CharField(choices=LANGUAGE_CHOICES,
                                            default='python',
                                            max_length=100)
    style = models.CharField(choices=STYLE_CHOICES,
                                     default='friendly',
                                     max_length=100)
    class Meta:
        ordering = ('created',)
def save(self, *args, **kwargs):
    """
    Use the 'pygments' library to create a highlighted HTML
    representation of the code snippet.
    """
    lexer = get_lexer_by_name(self.language)
    linenos = self.linenos and 'table' or False
    options = self.title and {'title': self.title} or {}
    formatter = HtmlFormatter(style=self.style, linenos=linenos,
                                      full=true, **options)
    self.highlighted = highlight(self.code, lexer, formatter)
    super(Snippet, self).save(*args, **kwargs)

私の serializers.py :

from django.forms import widgets
from rest_framework import serializers
from snippets.models import Snippet, LANGUAGE_CHOICES, STYLE_CHOICES
from django.contrib.auth.models import User



class SnippetSerializer(serializers.ModelSerializer):
    owner = serializers.Field(source='owner.username')
    class Meta:
        model = Snippet
        fields = ('id', 'title', 'code', 'linenos', 'language', 'style', 'owner')


class UserSerializer(serializers.ModelSerializer):
    snippets = serializers.PrimaryKeyRelatedField(many=True)


    class Meta:
        model = User
        fields = ('id', 'username', 'snippets')

私の views.py :

from snippets.models import Snippet
from snippets.serializers import SnippetSerializer
from rest_framework import generics
from django.contrib.auth.models import User
from snippets.serializers import UserSerializer
from rest_framework import permissions

class SnippetList(generics.ListCreateAPIView):
    """
    List all snippets, or create a new snippet.
    """
    queryset = Snippet.objects.all()
    serializer_class = SnippetSerializer
    def pre_save(self, obj):
        obj.owner = self.request.user
    permission_classes = (permissions.IsAuthenticatedOrReadOnly,)

class SnippetDetail(generics.RetrieveUpdateDestroyAPIView):
    """
    Retrieve, update or delete a nippet instance.
    """
    queryset = Snippet.objects.all()
    serializer_class = SnippetSerializer
    def pre_save(self, obj):
        obj.owner = self.request.user
    permission_classes = (permissions.IsAuthenticatedOrReadOnly,)

class UserList(generics.ListAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer

class UserDetail(generics.RetrieveAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer

そして最後に私の urls.py

from django.conf.urls import include
from django.conf.urls import patterns, url
from rest_framework.urlpatterns import format_suffix_patterns
from snippets import views


urlpatterns = patterns('',
    url(r'^snippets/$', views.SnippetList.as_view()),
    url(r'^snippets/(?P<pk>[0-9]+)/$', views.SnippetDetail.as_view()),
    url(r'^users/$', views.UserList.as_view()),
    url(r'^users/(?P<pk>[0-9]+)/$', views.UserDetail.as_view()),
)

urlpatterns = format_suffix_patterns(urlpatterns)

urlpatterns += patterns('',
    url(r'^api-auth/', include('rest_framework.urls',
                                       namespace='rest_framework')),
)

余計な情報を書き込んだら申し訳ないです。皆さん、よろしくお願いします。

編集 DBスキーマ。

CREATE TABLE "snippets_snippet" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, 
"created" datetime NOT NULL, "title" varchar(100) NOT NULL, "code" text NOT NULL, 
"linenos" bool NOT NULL, "language" varchar(100) NOT NULL, "style" varchar(100) NOT NULL);

少し調べてみると、DBを削除して再作成する際に(チュートリアルに書いてあるように)代わりに make migrations コマンドを実行すると、カラムが追加されないだけでなく、何か問題があることも教えてくれませんでした。 make migrations コマンドを実行すると、私に教えてくれます。

You are trying to add a non-nullable field 'highlighted' to snippet without a default;
we can't do that (the database needs something to populate existing rows).
Please select a fix:
 1) Provide a one-off default now (will be set on all existing rows)
 2) Quit, and let me add a default in models.py

をコメントアウトすると highlighted のセクションは models.py の場合、上記と同じメッセージが表示されます。 owner という行があります。つまり highlightedowner しかし、何を使えばいいのかわかりません。また、チュートリアルはそれについて私を助けていない。

どのように解決するのですか?

チュートリアルを進めていくうちに、マイグレーションに関するセクションに行き当たったことでしょう、これは Django 1.7 の大きな変更点の1つだからです

Django 1.7 より前のバージョンでは、 syncdb コマンドは、現在データベースにあるデータを破壊する可能性のある変更を一切行いませんでした。つまり、モデルに対して syncdb を実行した後、モデルに新しい行 (事実上、新しい列) を追加しても、 syncdb はデータベースのその変更に影響を及ぼさないということです。

そのため、そのテーブルを手作業で削除してから再度syncdbを実行するか(データを失ってゼロから作り直すため)、データベースで正しい文を手動で入力してその列だけを追加するかのどちらかでした。

というプロジェクトが登場しました。 south マイグレーションを実装したものです。これは、データベースに対するあらゆる変更を前方にマイグレートし(逆方向には元に戻し)、データの整合性を維持する方法があることを意味します。

Django 1.7では、この機能は south は Django に直接統合されました。マイグレーションを扱う場合、そのプロセスは少し異なります。

  1. を変更します。 models.py (通常通り)。
  2. マイグレーションを作成します。これは、モデルの現在の状態から次の状態に移行するためのコードを生成します。これは makemigrations コマンドを使用します。このコマンドは、何が変更されたかを検知し、その変更をデータベースに反映させるスクリプトを作成するのに十分な賢さを備えています。
  3. 次に、その移行を migrate . このコマンドは、すべてのマイグレーションを順番に適用します。

つまり、通常の syncdb は2段階の処理になりました。 python manage.py makemigrations に続いて python manage.py migrate .

さて、具体的な問題に移ります。

class Snippet(models.Model):
    owner = models.ForeignKey('auth.User', related_name='snippets')
    highlighted = models.TextField()
    created = models.DateTimeField(auto_now_add=True)
    title = models.CharField(max_length=100, blank=True, default='')
    code = models.TextField()
    linenos = models.BooleanField(default=False)
    language = models.CharField(choices=LANGUAGE_CHOICES,
                                            default='python',
                                            max_length=100)
    style = models.CharField(choices=STYLE_CHOICES,
                                     default='friendly',
                                     max_length=100)

このモデルでは、次の2つのフィールドがあります。 highlightedcode が必要です(NULLは不可)。

最初からこれらのフィールドを追加していれば、テーブルには既存の行がないため、問題はなかったのでは?

しかし、テーブルがすでに作成されていて、NULLにできないフィールドを追加する場合、既存の行に提供するデフォルト値を定義する必要があります。そうしないと、データ整合性制約に違反するため、データベースは変更を受け付けません。

これは、コマンドでプロンプトが表示される内容です。 移行中にデフォルトを適用するように Django に指示することもできますし、 "blank" というデフォルトを与えることもできます。 highlighted = models.TextField(default='') をモデル自体に組み込むことができます。