Você está tentando adicionar um campo não anulável 'new_field' ao perfil do usuário sem um padrão


109

Eu sei que a partir do Django 1.7 não preciso usar o South ou qualquer outro sistema de migração, então estou apenas usando um comando simples python manage.py makemigrations

No entanto, tudo que recebo é este erro:

You are trying to add a non-nullable field 'new_field' to userprofile without a default;
we can't do that (the database needs something to populate existing rows).

Aqui está models.py:

class UserProfile(models.Model):
    user = models.OneToOneField(User)
    website = models.URLField(blank=True)
    new_field = models.CharField(max_length=140)

Quais são as opções?


3
Gostaria de acrescentar que o problema ocorre quando você muda a tabela existente, não quando está criando uma nova.
x-yuri de

Respostas:


91

Você precisa fornecer um valor padrão:

new_field = models.CharField(max_length=140, default='SOME STRING')

E se eu precisar de uma cópia do campo de um site para new_field. Como isso deve ficar? default = websitenão faz o trabalho
Irmantas Želionis

7
Você gostaria de primeiro fazer a migração com um valor padrão falso e, em seguida, criar uma migração de dados para iterar em cada registro e definir new_fieldcomo website.
dgel

o padrão deve ser opcional para CharField
Florent

88

Se você está no início do ciclo de desenvolvimento e não se importa com os dados do banco de dados atual, basta removê-los e migrar. Mas primeiro você precisa limpar o diretório de migrações e remover suas linhas da tabela (django_migrations)

rm  your_app/migrations/*

rm db.sqlite3
python manage.py makemigrations
python manage.py migrate

8
Mais uma coisa. Você precisa limpar a tabela de migrações, por exemplo:mysql -u[user] [database] -e "delete from django_migrations where app=[your_app]"
helpse

Este é o caminho. Eu acho que o Django é péssimo em migração e detecção de modelo, etc.
WesternGun

Eu apaguei todos os arquivos das migrações e apaguei todas as linhas de django_migrations e agora estou recebendo "django.db.migrations.exceptions.NodeNotFoundError: Histórias de migração.0001_initial dependencies referenciam nó pai inexistente ('sources', '0002_auto_20180903_1224')" quando em execução migração.
brainLoop

1
Além disso, certifique-se de não excluir o __init__.py das migrações ou restaurá-lo depois, caso contrário, o makemigrations não funcionará stackoverflow.com/a/46362750/1649917
nmu

python manage.py sqlmigrate name_of_your_app nb_of_the_migrationtambém é obrigatório
zar3bski

37

Uma opção é declarar um valor padrão para 'new_field':

new_field = models.CharField(max_length=140, default='DEFAULT VALUE')

outra opção é declarar 'new_field' como um campo anulável:

new_field = models.CharField(max_length=140, null=True)

Se você decidir aceitar 'new_field' como um campo anulável, você pode querer aceitar 'nenhuma entrada' como entrada válida para 'new_field'. Em seguida, você também deve adicionar a blank=Truedeclaração:

new_field = models.CharField(max_length=140, blank=True, null=True)

Mesmo com null=Truee / ou blank=Truevocê pode adicionar um valor padrão, se necessário:

new_field = models.CharField(max_length=140, default='DEFAULT VALUE', blank=True, null=True)

7
«Evite usar null em campos baseados em string, como CharField e TextField. Se um campo baseado em string tem null = True, isso significa que tem dois valores possíveis para “sem dados”: NULL e a string vazia. » - Referência de campo do modelo
Chema

7

Se você está no início do ciclo de desenvolvimento, pode tentar isso -

Remova / comente esse modelo e todos os seus usos. Aplique migrações. Isso excluiria esse modelo e, em seguida, adicionaria o modelo novamente, executaria as migrações e você teria um modelo limpo com o novo campo adicionado.


E limpe a tabela de migrações django_migrations conforme descrito aqui: stackoverflow.com/questions/26185687/… Ou apenas use uma GUI e exclua as linhas necessárias.
RusI

4

Se "site" pode estar vazio new_field, então também deve ser definido como vazio.

Agora, se você deseja adicionar lógica ao salvar onde se new_fieldestá vazio para obter o valor do "site", tudo o que você precisa fazer é substituir a função de salvamento por você Modelassim:

class UserProfile(models.Model):
    user = models.OneToOneField(User)
    website = models.URLField(blank=True, default='DEFAULT VALUE')
    new_field = models.CharField(max_length=140, blank=True, default='DEFAULT VALUE')

    def save(self, *args, **kwargs):
        if not self.new_field:
            # Setting the value of new_field with website's value
            self.new_field = self.website

        # Saving the object with the default save() function
        super(UserProfile, self).save(*args, **kwargs)

4

Caso alguém esteja definindo um ForeignKey, você pode apenas permitir campos anuláveis ​​sem definir um padrão:

new_field = models.ForeignKey(model, null=True)

Se você já tem dados armazenados no banco de dados, também pode definir um valor padrão:

new_field = models.ForeignKey(model, default=<existing model id here>)

3

Você não pode adicionar referência à tabela que já contém dados.
Mudança:

user = models.OneToOneField(User)

para:

user = models.OneToOneField(User, default = "")

Faz:

python manage.py makemigrations
python manage.py migrate

mudar de novo:

user = models.OneToOneField(User)

faça a migração novamente:

python manage.py makemigrations
python manage.py migrate

2

Em new_file, adicione a propriedade booleana null.

new_field = models.CharField(max_length=140, null=True)

depois de executar um ./manage.py syncdbpara atualizar o banco de dados. e finalmente você corre ./manage.py makemigrations e./manage.py migrate



2

Você já tem entradas de banco de dados na tabela UserProfile? Nesse caso, quando você adiciona novas colunas, o banco de dados não sabe como definir porque não pode ser NULL. Portanto, ele pergunta como você deseja definir esses campos na coluna new_fields. Eu tive que deletar todas as linhas desta tabela para resolver o problema.

(Sei que isso foi respondido há algum tempo, mas acabei de encontrar esse problema e essa foi a minha solução. Espero que ajude alguém novo que vir isso)


1
Não inseri linhas na tabela e ainda consigo entender. Tenho que deletar todo o histórico de migração, limpar a tabela de migração para mudar o modelo, conforme sugerido por Tomasz.
WesternGun

1

Sinceramente, descobri que a melhor maneira de contornar isso era apenas criar outro modelo com todos os campos de que você precisa e com um nome um pouco diferente. Execute migrações. Exclua o modelo não utilizado e execute as migrações novamente. Voila.


1

Se não houver problema em truncar a tabela do modelo em questão, você pode especificar um valor padrão único de Noneno prompt. A migração terá supérflua default=Noneenquanto seu código não tiver padrão. Pode ser aplicado muito bem porque não há mais dados na tabela que exigiriam um padrão.


1

Eu estava no início do meu ciclo de desenvolvimento, então isso pode não funcionar para todos (mas não vejo por que não funcionaria).

Eu adicionei blank=True, null=Trueàs colunas onde estava obtendo o erro. Então executei o python manage.py makemigrationscomando.

Imediatamente após executar este comando (e antes de executar python manage.py migrate), removi o blank=True, null=Truede todas as colunas. Então corri python manage.py makemigrationsnovamente. Foi-me dada a opção de apenas alterar as colunas sozinho, que selecionei.

Aí corri python manage.py migratee deu tudo certo!


0

O que Django realmente diz é:

A tabela de perfil do usuário contém dados e pode haver new_fieldvalores nulos, mas não sei, então tem certeza de que deseja marcar a propriedade como não anulável, porque se o fizer, poderá obter um erro se houver valores com NULL

Se você tiver certeza de que nenhum dos valores na userprofiletabela é NULL - fique livre e ignore o aviso.

A prática recomendada em tais casos seria criar uma migração RunPython para lidar com valores vazios, como afirma na opção 2

2) Ignore por enquanto e deixe-me lidar com as linhas existentes com NULL (por exemplo, porque você adicionou uma operação RunPython ou RunSQL para lidar com valores NULL em uma migração de dados anterior)

Na migração RunPython, você deve encontrar todas as UserProfileinstâncias com new_fieldvalor vazio e colocar um valor correto lá (ou um valor padrão conforme o Django pede que você defina no modelo). Você obterá algo assim:

# please keep in mind that new_value can be an empty string. You decide whether it is a correct value.
for profile in UserProfile.objects.filter(new_value__isnull=True).iterator():
    profile.new_value = calculate_value(profile)
    profile.save() # better to use batch save

Diverta-se!


Não consigo encontrar onde isso está escrito na documentação. Você pode postar o link
Cody

0

Em models.py

class UserProfile(models.Model): user = models.OneToOneField(User) website = models.URLField(blank=True) new_field = models.CharField(max_length=140, default="some_value")

Você precisa adicionar alguns valores como padrão.


-1

Se o SSH lhe dá 2 opções, escolha o número 1 e coloque "Nenhum". Só isso ... por enquanto.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.