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?

Irmantas Želionis
fonte
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')
dgel
fonte
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
Tomasz
fonte
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)
Tobi
fonte
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.

Áspero
fonte
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)
Alex carlos
fonte
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>)
Justin Lange
fonte
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
E. Kristiyono
fonte
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

gerachev
fonte
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)

Arnold Lam
fonte
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.

Josh
fonte
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.

jnns
fonte
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!

Joseph Gill
fonte
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!

Taras Matsyk
fonte
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.

George Devasia
fonte
-1

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

Geovanni Atavales
fonte