Python 如何修改模型谁';已经在数据库中迁移了吗?
我是django的新手,我想修改我的模型(它已经在我的sqlite3数据库中),而不会干扰我的整个项目。上次我修改我的模型时,我花了几个小时来修复它,因为我对整个项目进行了窃听。所以我不想犯同样的错误,你们能帮我一下命令吗?谢谢你的帮助 models.py(目前) 我想对模型进行的编辑(我想在模型中添加一个作者用户,这样我就知道是谁在制作表单。) 我的admin.py文件(不确定是否需要保持不变或修改) my forms.py文件Python 如何修改模型谁';已经在数据库中迁移了吗?,python,django,authentication,django-models,Python,Django,Authentication,Django Models,我是django的新手,我想修改我的模型(它已经在我的sqlite3数据库中),而不会干扰我的整个项目。上次我修改我的模型时,我花了几个小时来修复它,因为我对整个项目进行了窃听。所以我不想犯同样的错误,你们能帮我一下命令吗?谢谢你的帮助 models.py(目前) 我想对模型进行的编辑(我想在模型中添加一个作者用户,这样我就知道是谁在制作表单。) 我的admin.py文件(不确定是否需要保持不变或修改) my forms.py文件 from django import forms from .m
from django import forms
from .models import Post
from crispy_forms.helper import FormHelper
class post_form(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(post_form, self).__init__(*args, **kwargs)
self.helper = FormHelper(self)
class Meta:
model = Post
fields = ["name", "email", "gender", "number"]
views.py
from django.shortcuts import render
from django.http import HttpResponse
from .forms import post_form
# Create your views here.
def home(request):
form = post_form(request.POST or None)
if form.is_valid():
form.save()
context = {
"form": form
}
return render(request, "sms/home.html", context)
您的迁移很棘手,因为您希望每个帖子都与一个用户相关。要解决此问题,您可以执行以下操作: 使用
null=True添加新字段
models.ForeignKey(用户,on_delete=models.CASCADE,null=True)
然后manage.py makemigrations
然后你必须决定怎么做。要么(1)手动将作者添加到现有帖子中,要么(2)将其全部删除
manage.py shell
from x.models import Post
from django.contrib.auth.models import User
# 1
user = User.objects.get(id=1) # get your user
Post.objects.all().update(author=user)
# or 2
Post.objects.all().delete()
然后,您可以最终设置您想要的作者:
models.ForeignKey(用户,on_delete=models.CASCADE)
再次manage.py makemigrations
有关更多信息,请参见注释。首先,您需要编辑您的模型。py
# models.py
class Post(models.Model):
name = models.CharField(max_length=100)
email = models.CharField(max_length=100)
gender = models.CharField(max_length=8, choices=THE_GENDER)
number = models.CharField(max_length=100)
author = models.ForeignKey(User, on_delete=models.CASCADE) # add new field
def __str__(self):
return self.name
注意:您应该使用decorator在请求.用户
属性中获取经过身份验证的用户。详细说明我上面的评论
author = models.ForeignKey(User, on_delete=models.CASCADE)
在Django中添加新的不可为null的ForeignKey通常需要三个步骤
首先,使用null=True
将新的ForeignKey添加到模型定义中,然后运行makemigrations
。这将创建一个将添加字段的迁移,没有什么特别之处。执行此迁移将添加一列,其中所有行的值均为NULL
其次,为同一应用程序创建新的空迁移(makemigrations--empty
),然后编辑该迁移以包含数据迁移步骤。这是您需要根据业务逻辑为新外键选择一些值的地方
第三,修改模型定义中的ForeignKey以设置null=False
,并使用makemigrations
创建第三次迁移。Django会问您是否以某种方式处理过null
s–您需要说“是的,我发誓我已经处理过了”(因为您已经处理过了,在上面的步骤2中)
实际上,对于OP问题的简化版本,我们希望添加用户外键:
原始状态
1a。添加可为空的字段。
1b。运行makemigrations。
2a。创建新的空迁移。
2b。编辑迁移文件。
如往常一样,可以找到有关数据迁移的更多信息
从django.db导入迁移
def分配作者(应用程序、架构编辑器):
User=apps.get_model('auth','User')#或任何您的用户模型
Post=apps.get_model('something','Post')#或无论您的Post model在哪里
user=user.objects.filter(is_superuser=True)。首先()#选择某个用户。。。
断言用户#。。。并确保它存在。。。
Post.objects.all().update(author=user)#并批量更新所有帖子。
类迁移(migrations.Migration):
依赖项=[…]
操作=[
migrations.RunPython(分配作者migrations.RunPython.noop),
]
3a。使字段不可为空。
class Post(models.Model):
name=models.CharField(最大长度=100)
author=models.ForeignKey(User,null=False,on_delete=models.CASCADE))
3b。运行Makemigrations。
如实回答问题–您刚刚添加了一个RunPython操作
$ python manage.py makemigrations something -n post_author_non_null
You are trying to change the nullable field 'author' on something. to non-nullable 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 with a null value for this column)
2) Ignore for now, and let me handle existing rows with NULL myself (e.g. because you added a RunPython or RunSQL operation to handle NULL values in a previous data migration)
3) Quit, and let me add a default in models.py
Select an option: 2
Migrations for 'something':
something/migrations/0004_post_author_non_null.py
- Alter field author on post
全部完成!
运行migrate
现在将运行这三个迁移,您的模型将拥有author
,而不会丢失数据。您可以用不同的方式处理此问题
如果没有数据,您可以轻松添加新字段并运行迁移。你应该没事的
如果已经有帖子,可以允许该字段为空,然后在填充之前运行迁移
一种更直观的方法是在运行迁移时为post分配一个用户,特别是在您已经有数据的情况下
首先创建一个迁移,允许author字段为null,然后
author = models.ForeignKey(User, null=True, on_delete=models.CASCADE)
manage.py makemigrations
manage.py迁移
然后,删除null
属性
author = models.ForeignKey(User, on_delete=models.CASCADE)
manage.py makemigrations
打开现在生成的迁移文件,您将使用下面的自定义方法修改该文件,然后运行migrate
from django.db import migrations, models
# create custom method
def add_author(apps, schema_editor):
User = apps.get_model('auth', 'User')
Post = apps.get_model('something', 'Post')
posts = Post.objects.all()
author = User.object.get(id=1) # whichever user you want to use as the author
for post in posts:
post.author = author
post.save()
class Migration(migrations.Migration):
dependencies = [
('posts', '00000000'),
]
operations = [
migrations.RunPython(add_author), # this will run the method above
migrations.AlterField(
model_name='post',
name='author',
field=models.ForeignKeyField...,
),
]
如果你还没有创建任何帖子,你可以继续添加作者,也不需要在管理员中做任何更改。你也可以添加你的views.py吗?@Bernard'BetaBerlin'Parah我写了两篇帖子。我可以去管理员页面删除这两个,然后再添加作者,否则会对项目造成错误吗?@ArakkalAbu是的,我添加了视图,pywait,现在什么都不要做。我将向您展示处理此问题的最佳方法,以防您遇到此问题。不,删除数据从来都不是正确的选择。相反,对于需要添加外键的迁移,正确的方法是将FK添加为可空,然后添加一个数据迁移(migrations.RunPython
/migrations.RunSQL
),找出合适的值,然后从FK中删除null=True
并再次生成迁移。@AKX Arakkal Abu的方法如何?是的,你是对的,我添加了免责声明。我仍然不明白如果删除null=True
会发生什么。您不会像以前一样遇到同样的问题吗?@ChrisRob No–makemigrations
询问您是否已经处理过空值。但是,如果您没有,那么您的RDBMS将对此进行投诉,并且迁移将失败。@ChrisRob我添加了一个显示ste的答案
class Post(models.Model):
name = models.CharField(max_length=100)
author = models.ForeignKey(User, null=True, on_delete=models.CASCADE))
$ python manage.py makemigrations
Migrations for 'something':
something/migrations/0002_post_author.py
- Add field author to post
$ python manage.py makemigrations something --empty -n assign_author
Migrations for 'something':
something/migrations/0003_assign_author.py
$ python manage.py makemigrations something -n post_author_non_null
You are trying to change the nullable field 'author' on something. to non-nullable 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 with a null value for this column)
2) Ignore for now, and let me handle existing rows with NULL myself (e.g. because you added a RunPython or RunSQL operation to handle NULL values in a previous data migration)
3) Quit, and let me add a default in models.py
Select an option: 2
Migrations for 'something':
something/migrations/0004_post_author_non_null.py
- Alter field author on post
author = models.ForeignKey(User, null=True, on_delete=models.CASCADE)
author = models.ForeignKey(User, on_delete=models.CASCADE)
from django.db import migrations, models
# create custom method
def add_author(apps, schema_editor):
User = apps.get_model('auth', 'User')
Post = apps.get_model('something', 'Post')
posts = Post.objects.all()
author = User.object.get(id=1) # whichever user you want to use as the author
for post in posts:
post.author = author
post.save()
class Migration(migrations.Migration):
dependencies = [
('posts', '00000000'),
]
operations = [
migrations.RunPython(add_author), # this will run the method above
migrations.AlterField(
model_name='post',
name='author',
field=models.ForeignKeyField...,
),
]