No meu modelo eu tenho:
class Alias(MyBaseModel):
remote_image = models.URLField(max_length=500, null=True, help_text="A URL that is downloaded and cached for the image. Only
used when the alias is made")
image = models.ImageField(upload_to='alias', default='alias-default.png', help_text="An image representing the alias")
def save(self, *args, **kw):
if (not self.image or self.image.name == 'alias-default.png') and self.remote_image :
try :
data = utils.fetch(self.remote_image)
image = StringIO.StringIO(data)
image = Image.open(image)
buf = StringIO.StringIO()
image.save(buf, format='PNG')
self.image.save(hashlib.md5(self.string_id).hexdigest() + ".png", ContentFile(buf.getvalue()))
except IOError :
pass
O que funciona muito bem pela primeira vez nas remote_image
mudanças.
Como posso buscar uma nova imagem quando alguém modificou remote_image
o alias? E segundo, existe uma maneira melhor de armazenar em cache uma imagem remota?
django
image
caching
django-models
Paul Tarjan
fonte
fonte
save()
novamente, ele ainda funcionará corretamente.Eu uso o seguinte mixin:
Uso:
Nota
Observe que esta solução funciona bem apenas no contexto da solicitação atual. Portanto, é adequado principalmente para casos simples. No ambiente simultâneo em que várias solicitações podem manipular a mesma instância de modelo ao mesmo tempo, você definitivamente precisa de uma abordagem diferente.
fonte
A melhor maneira é com um
pre_save
sinal. Pode não ter sido uma opção em 2009 quando essa pergunta foi feita e respondida, mas qualquer pessoa que esteja vendo isso hoje deve fazê-lo desta maneira:fonte
E agora para resposta direta: uma maneira de verificar se o valor do campo foi alterado é buscar dados originais do banco de dados antes de salvar a instância. Considere este exemplo:
O mesmo se aplica ao trabalhar com um formulário. Você pode detectá-lo no método clean ou save de um ModelForm:
fonte
pk is not None
pedir às pessoas para verificar se não se aplica, por exemplo, se você estiver usando um UUIDField. Este é apenas um mau conselho.@transaction.atomic
Desde o lançamento do Django 1.8, você pode usar o método de classe from_db para armazenar em cache o valor antigo da imagem_remota. Em seguida, no método save , você pode comparar o valor antigo e o novo do campo para verificar se o valor foi alterado.
fonte
new._loaded_remote_image = new.remote_image
?from_db
é chamado porrefresh_from_db
, os atributos na instância (ou seja, carregados ou anteriores) não são atualizados. Como resultado, eu não consigo encontrar nenhuma razão para isso é melhor do que__init__
como você ainda precisa lidar com 3 casos:__init__
/from_db
,refresh_from_db
, esave
.Observe que o rastreamento de alterações de campo está disponível no django-model-utils.
https://django-model-utils.readthedocs.org/en/latest/index.html
fonte
Se você estiver usando um formulário, poderá usar os dados alterados do formulário ( docs ):
fonte
Estou um pouco atrasado para a festa, mas encontrei esta solução também: Django Dirty Fields
fonte
A partir do Django 1.8, existe o
from_db
método, como Serge menciona. De fato, os documentos do Django incluem este caso de uso específico como um exemplo:https://docs.djangoproject.com/en/dev/ref/models/instances/#customizing-model-loading
fonte
Isso funciona para mim no Django 1.8
fonte
Você pode usar o django-model-changes para fazer isso sem uma pesquisa adicional no banco de dados:
fonte
Outra resposta tardia, mas se você está apenas tentando ver se um novo arquivo foi carregado em um campo, tente o seguinte: (adaptado do comentário de Christopher Adams no link http://zmsmith.com/2010/05/django -check-if-a-field-mudou / no comentário de zach aqui)
Link atualizado: https://web.archive.org/web/20130101010327/http://zmsmith.com:80/2010/05/django-check-if-a-field-has-changed/
fonte
pre_save
receptor. Obrigado por compartilhar isso!A solução ideal provavelmente é aquela que não inclui uma operação de leitura de banco de dados adicional antes de salvar a instância do modelo, nem qualquer outra biblioteca django. É por isso que as soluções da laffuste são preferíveis. No contexto de um site de administração, pode-se simplesmente substituir o
save_model
método-e invocar ohas_changed
método do formulário , como na resposta de Sion acima. Você chega a algo assim, usandochanged_data
a configuração de exemplo de Sion, mas usando para obter todas as alterações possíveis:save_model
:https://docs.djangoproject.com/en/1.10/ref/contrib/admin/#django.contrib.admin.ModelAdmin.save_model
changed_data
-method para um campo:https://docs.djangoproject.com/en/1.10/ref/forms/api/#django.forms.Form.changed_data
fonte
Embora isso não responda à sua pergunta, eu faria isso de uma maneira diferente.
Simplesmente limpe o
remote_image
campo após salvar com êxito a cópia local. Em seu método de salvamento, você sempre pode atualizar a imagem sempre queremote_image
não estiver vazia.Se você quiser manter uma referência ao URL, use um campo booleano não editável para manipular o sinalizador de cache, em vez do
remote_image
próprio campo.fonte
Eu tive essa situação antes de minha solução substituir o
pre_save()
método da classe de campo de destino, ela será chamada apenas se o campo tiver sido alteradoútil com o exemplo FileField:
desvantagem:
não é útil se você deseja executar qualquer operação (post_save) como usar o objeto criado em algum trabalho (se determinado campo foi alterado)
fonte
melhorando a resposta @josh para todos os campos:
apenas para esclarecer, o getattr trabalha para obter campos como
person.name
com strings (ou seja,getattr(person, "name")
fonte
Estendi o mixin de @livskiy da seguinte maneira:
e o DictField é:
ele pode ser usado estendendo-o em seus modelos, um campo _dict será adicionado quando você sincronizar / migrar e esse campo armazenará o estado de seus objetos
fonte
Que tal usar a solução de David Cramer:
http://cramer.io/2010/12/06/tracking-changes-to-fields-in-django/
Eu tive sucesso usando-o assim:
fonte
Uma modificação na resposta de @ ivanperelivskiy:
Isso usa o método público do django 1.10
get_fields
. Isso torna o código mais à prova de futuro, mas o mais importante também inclui chaves estrangeiras e campos em que editável = Falso.Para referência, aqui está a implementação de
.fields
fonte
Aqui está outra maneira de fazê-lo.
Conforme documentação: validando objetos
"A segunda etapa que o full_clean () executa é chamar Model.clean (). Esse método deve ser substituído para executar a validação customizada no seu modelo. Esse método deve ser usado para fornecer validação de modelo customizado e modificar atributos em seu modelo, se desejado Por exemplo, você pode usá-lo para fornecer automaticamente um valor para um campo ou para fazer a validação que requer acesso a mais de um único campo: "
fonte
Há um atributo __dict__ que possui todos os campos como as chaves e o valor como os valores do campo. Então, podemos apenas comparar dois deles
Basta alterar a função salvar do modelo para a função abaixo
Exemplo de uso:
produz saída apenas com os campos que foram alterados
fonte
Muito tarde para o jogo, mas esta é uma versão da resposta de Chris Pratt que protege contra as condições da corrida enquanto sacrifica o desempenho, usando um
transaction
bloco eselect_for_update()
fonte
como uma extensão da resposta do SmileyChris, você pode adicionar um campo de data e hora ao modelo para last_updated e definir algum tipo de limite para a idade máxima que você deixará atingir antes de verificar uma alteração
fonte
O mixin de @ivanlivski é ótimo.
Eu estendi para
O código atualizado está disponível aqui: https://github.com/sknutsonsf/python-contrib/blob/master/src/django/utils/ModelDiffMixin.py
Para ajudar as pessoas novas em Python ou Django, darei um exemplo mais completo. Esse uso específico é pegar um arquivo de um provedor de dados e garantir que os registros no banco de dados reflitam o arquivo.
Meu objeto de modelo:
A classe que carrega o arquivo possui estes métodos:
fonte
Se você não encontrar interesse no
save
método de substituição , poderá fazerfonte