Python 如何修改模型谁';已经在数据库中迁移了吗?

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

我是django的新手,我想修改我的模型(它已经在我的sqlite3数据库中),而不会干扰我的整个项目。上次我修改我的模型时,我花了几个小时来修复它,因为我对整个项目进行了窃听。所以我不想犯同样的错误,你们能帮我一下命令吗?谢谢你的帮助

models.py(目前)

我想对模型进行的编辑(我想在模型中添加一个作者用户,这样我就知道是谁在制作表单。)

我的admin.py文件(不确定是否需要保持不变或修改)

my forms.py文件

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...,
            ),
    
        ]