【问题标题】:Django REST Framework tutorial, OperationalError: table snippets_snippet has no column named owner_idDjango REST Framework 教程,OperationalError: table snippets_snippet has no column named owner_id
【发布时间】:2016-07-30 17:42:52
【问题描述】:

在我得到明显的回应之前,关于检查数据库本身,我首先要说我已经检查了this post,它与我的设置几乎相同,以及删除数据库的解决方案和迁移,并且在表中添加默认值没有按预期工作。但是,我确实希望解决方案非常简单。

也就是说,我正在做the tutorial for django-rest-framework,而我的问题始于part 4。教程是这样说的:

现在,如果您再次打开浏览器并刷新页面,您将在页面右上角看到一个“登录”链接。如果您以之前创建的用户之一登录,您将能够再次创建代码 sn-ps。

创建一些代码 sn-ps 后,导航到“/users/” 端点,并注意该表示包括一个列表 与每个用户相关联的 sn-p pks,在每个用户的 'sn-ps' 字段。

所以,我尝试使用 manage.py shell 创建“sn-ps”对象,就像教程的第一部分一样,使用以下代码:

from snippets.models import Snippet
from snippets.serializers import SnippetSerializer

snippet = Snippet(code='foo = "bar"\n')
snippet.save()

这就是它结束的地方。 .save() 触发了错误,我已经在下面打印了回溯。

使用之前回答的问题中的建议,我稍微更改了设置,但我仍然收到错误消息。这是设置:

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(default='')
    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):
        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 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.ReadOnlyField(source='owner.username')

    class Meta:
        model = Snippet
        fields = ('id', 'title', 'code', 'linenos', 'language', 'style', 'owner')


class UserSerializer(serializers.ModelSerializer):
    snippets = serializers.PrimaryKeyRelatedField(many=True, queryset=Snippet.objects.all())

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

views.py:

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


class SnippetList(generics.ListCreateAPIView):
    queryset = Snippet.objects.all()
    serializer_class = SnippetSerializer
    permission_classes = (permissions.IsAuthenticatedOrReadOnly,)

    def perform_create(self, serializer):
        serializer.save(owner=self.request.user)


class SnippetDetail(generics.RetrieveUpdateDestroyAPIView):
    queryset = Snippet.objects.all()
    serializer_class = SnippetSerializer
    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

/sn-ps/urls.py

from django.conf.urls import url, include
from snippets.views import SnippetList, SnippetDetail, UserList, UserDetail
from rest_framework.urlpatterns import format_suffix_patterns


urlpatterns = [

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

]

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

urls.py:

from django.conf.urls import url, include

urlpatterns = [
    url(r'^', include('snippets.urls')),
]

最后是丑陋的回溯:

In [6]: snippet.save()
    ---------------------------------------------------------------------------
    OperationalError                          Traceback (most recent call last)
    C:\Users\Jordon\AppData\Local\Programs\Python\Python35\lib\site-packages\django\db\backends\utils.py in execute(self, sql, params)
         63             else:
    ---> 64                 return self.cursor.execute(sql, params)
         65

    C:\Users\Jordon\AppData\Local\Programs\Python\Python35\lib\site-packages\django\db\backends\sqlite3\base.py in execute(self, query, params)
        322         query = self.convert_query(query)
    --> 323         return Database.Cursor.execute(self, query, params)
        324

    OperationalError: table snippets_snippet has no column named owner_id

    The above exception was the direct cause of the following exception:

    OperationalError                          Traceback (most recent call last)
    <ipython-input-6-fe28bd3dc796> in <module>()
    ----> 1 snippet.save()

    D:\GitHub Repositories\Django\tutorial\snippets\models.py in save(self, *args, **kwargs)
         34                                   full=True, **options)
         35         self.highlighted = highlight(self.code, lexer, formatter)
    ---> 36         super(Snippet, self).save(*args, **kwargs)

    C:\Users\Jordon\AppData\Local\Programs\Python\Python35\lib\site-packages\django\db\models\base.py in save(self, force_insert, force_update, using, update_fields)
        698
        699         self.save_base(using=using, force_insert=force_insert,
    --> 700                        force_update=force_update, update_fields=update_fields)
        701     save.alters_data = True
        702

    C:\Users\Jordon\AppData\Local\Programs\Python\Python35\lib\site-packages\django\db\models\base.py in save_base(self, raw, force_insert, force_update, using, update_fields)
        726             if not raw:
        727                 self._save_parents(cls, using, update_fields)
    --> 728             updated = self._save_table(raw, cls, force_insert, force_update, using, update_fields)
        729         # Store the database on which the object was saved
        730         self._state.db = using

    C:\Users\Jordon\AppData\Local\Programs\Python\Python35\lib\site-packages\django\db\models\base.py in _save_table(self, raw, cls, force_insert, force_update, using, update_fields)
        810
        811             update_pk = bool(meta.has_auto_field and not pk_set)
    --> 812             result = self._do_insert(cls._base_manager, using, fields, update_pk, raw)
        813             if update_pk:
        814                 setattr(self, meta.pk.attname, result)

    C:\Users\Jordon\AppData\Local\Programs\Python\Python35\lib\site-packages\django\db\models\base.py in _do_insert(self, manager, using, fields, update_pk, raw)
        849         """
        850         return manager._insert([self], fields=fields, return_id=update_pk,
    --> 851                                using=using, raw=raw)
        852
        853     def delete(self, using=None, keep_parents=False):

    C:\Users\Jordon\AppData\Local\Programs\Python\Python35\lib\site-packages\django\db\models\manager.py in manager_method(self, *args, **kwargs)
        120         def create_method(name, method):
        121             def manager_method(self, *args, **kwargs):
    --> 122                 return getattr(self.get_queryset(), name)(*args, **kwargs)
        123             manager_method.__name__ = method.__name__
        124             manager_method.__doc__ = method.__doc__

    C:\Users\Jordon\AppData\Local\Programs\Python\Python35\lib\site-packages\django\db\models\query.py in _insert(self, objs, fields, return_id, raw, using)
       1037         query = sql.InsertQuery(self.model)
       1038         query.insert_values(fields, objs, raw=raw)
    -> 1039         return query.get_compiler(using=using).execute_sql(return_id)
       1040     _insert.alters_data = True
       1041     _insert.queryset_only = False

    C:\Users\Jordon\AppData\Local\Programs\Python\Python35\lib\site-packages\django\db\models\sql\compiler.py in execute_sql(self, return_id)
       1058         with self.connection.cursor() as cursor:
       1059             for sql, params in self.as_sql():
    -> 1060                 cursor.execute(sql, params)
       1061             if not (return_id and cursor):
       1062                 return

    C:\Users\Jordon\AppData\Local\Programs\Python\Python35\lib\site-packages\django\db\backends\utils.py in execute(self, sql, params)
         77         start = time()
         78         try:
    ---> 79             return super(CursorDebugWrapper, self).execute(sql, params)
         80         finally:
         81             stop = time()

    C:\Users\Jordon\AppData\Local\Programs\Python\Python35\lib\site-packages\django\db\backends\utils.py in execute(self, sql, params)
         62                 return self.cursor.execute(sql)
         63             else:
    ---> 64                 return self.cursor.execute(sql, params)
         65
         66     def executemany(self, sql, param_list):

    C:\Users\Jordon\AppData\Local\Programs\Python\Python35\lib\site-packages\django\db\utils.py in __exit__(self, exc_type, exc_value, traceback)
         93                 if dj_exc_type not in (DataError, IntegrityError):
         94                     self.wrapper.errors_occurred = True
    ---> 95                 six.reraise(dj_exc_type, dj_exc_value, traceback)
         96
         97     def __call__(self, func):

    C:\Users\Jordon\AppData\Local\Programs\Python\Python35\lib\site-packages\django\utils\six.py in reraise(tp, value, tb)
        683             value = tp()
        684         if value.__traceback__ is not tb:
    --> 685             raise value.with_traceback(tb)
        686         raise value
        687

    C:\Users\Jordon\AppData\Local\Programs\Python\Python35\lib\site-packages\django\db\backends\utils.py in execute(self, sql, params)
         62                 return self.cursor.execute(sql)
         63             else:
    ---> 64                 return self.cursor.execute(sql, params)
         65
         66     def executemany(self, sql, param_list):

    C:\Users\Jordon\AppData\Local\Programs\Python\Python35\lib\site-packages\django\db\backends\sqlite3\base.py in execute(self, query, params)
        321             return Database.Cursor.execute(self, query)
        322         query = self.convert_query(query)
    --> 323         return Database.Cursor.execute(self, query, params)
        324
        325     def executemany(self, query, param_list):

    OperationalError: table snippets_snippet has no column named owner_id

【问题讨论】:

  • 你试过运行makemigrationsmigrate吗?
  • @vmonteco - 是的。正如我之前在我的问题中所述,我最初运行迁移没有问题,直到我在 shell 中点击 .save() 命令。然后我删除了迁移和数据库,我再次运行它们,但同样的问题再次发生。
  • 你可以试试./manage.py makemigrations &lt;name of your app&gt;然后迁移吗?
  • 我已经这样做了。没有要应用的迁移。
  • 是的@vmonteco。除非您明确指定主键,否则 id 会自动添加。

标签: django sqlite django-rest-framework


【解决方案1】:

首先,您在保存 Snippet 对象时没有为“所有者”提供值。你需要做这样的事情:

from django.contrib.auth.models import User
new_user = User.objects.create(...)
snippet = Snippet(owner=new_user, code='foo = "bar"\n')
snippet.save()

尽管如此,它并没有解释为什么没有创建 owner_id 列。你能把模型改成这样,看看它是否检测到所有者列吗?

from django.contrib.auth.models import User

class Snippet(models.Model):
    owner = models.ForeignKey(User, related_name='snippets')
    ...

然后运行这些步骤以尝试创建列。

python manage.py makemigrations snippets
python manage.py migrate

【讨论】:

  • 谢谢。这解决了向 sn-ps 表添加 owner_id 的问题,但是,它可能产生了另一个问题,即 /snippets/urls.py 中定义的端点似乎不起作用,这可能是由于更改了model: url: url(r'^users/$', UserList.as_view()) 以及 UserDetail url 都返回了 AttributeError at /users/1/ 'User' object has no attribute 'snippets',这表明序列化程序没有完成它们的工作。也许OnetoOneField(User) 是错误的选择。
  • 哦,我的错,我在模型更改中删除了related_name='sn-ps'。默认情况下,如果您不提供related_name,django 使用'somefieldname_set' 来反向链接'somefieldname'。所以在 UserSerializer 中,将 'sn-ps' 更改为 'sn-ps_set' 应该可以正常工作。
  • 现在出现我收到TypeError at /users/ 'Snippet' object is not iterable。我去的 UserSerializer。
  • 哦,不。看来我又犯了一个错误。在这个模型中,我们定义了一个onetoonefield——表示一个用户只能有一个sn-p,反之亦然。但事实并非如此。一个用户可以有多个 sn-ps(many=True)。请将 owner 字段更改为 ForeignKey 并运行 makemigration/migrate。我为误导而道歉。
  • 知道了。再次感谢,阿比。我觉得我现在对内部发生的事情有了更好的了解。
【解决方案2】:

看来您没有删除原始数据库。

模型更改后教程将其移除:

rm -f tmp.db db.sqlite3
rm -r snippets/migrations
python manage.py makemigrations snippets
python manage.py migrate

如果你没有删除任何 tmp.db 或 db.sqlite3,那么 Django 可能会认为它已经完成了迁移并且不会重做。

确保您找到上述两个文件之一并将其删除,然后运行上述脚本(加上用于登录的 createsuperuser)。

【讨论】:

  • 我删除的最初方法是拖到垃圾箱,而不是cmd,但是,我尝试了你的方法(没有-f标志,因为我在windows中)但它仍​​然没有不行。在 manage.py shell 中的snippet.save() 出现同样的错误。
  • 你也删除了 sn-ps/migrations 目录的内容吗?
  • 是的。我已经这样做了好几次,并继续得到同样的错误。模型本身或 save() 方法有问题。我正在运行 python 3.5 和 django 1.9。
猜你喜欢
  • 1970-01-01
  • 2019-10-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-31
  • 1970-01-01
  • 2020-10-23
相关资源
最近更新 更多