Tengo este unique field en mi Profile model :
email = models.EmailField(max_length=200, unique=True) y tengo este ProfileResource :
class ProfileResource(resources.ModelResource): # associated_issuer = fields.Field(attribute='add_associated_issuer', widget=ManyToManyWidget(Issuer, field='name'), column_name='Associated Issuer') email = fields.Field(attribute='email', widget=CharWidget(), column_name='email') class Meta: model = Profile clean_model_instances = True import_id_fields = ('id', 'email') def before_import_row(self, row, row_number=None, **kwargs): try: self.email = row["email"] except Exception as e: self.email = "" try: if row["id"] == '': row["id"] = None self.id = row["id"] except Exception as e: self.id = None try: self.firstname = row["firstname"] except Exception as e: self.firstname = "" try: self.lastname = row["lastname"] except Exception as e: self.lastname = ""Ahora, cuando intento hacer una importación desde un archivo, recibo este error:
Necesito poder hacer un método update_or_create , pero ¿dónde agrego ese código? Intenté hacerlo en una after_import_instance posterior a la importación pero no funcionó.
También probé en import_row así:
def import_row(self, row, instance_loader, using_transactions=True, dry_run=False, **kwargs): try: Profile.objects.update_or_create(email=self.email) except Exception as e: print(e, file=sys.stderr)pero produjo este error:
Exception Value: 'NoneType' object has no attribute 'import_type'Cualquier idea sobre una solución sería apreciada.
Observe que tiene esta línea en su ProfileResource
import_id_fields = ('identificación', 'correo electrónico')
Esto significa que la importación observará cada fila en su archivo de importación e intentará cargar cualquier instancia de Profile que coincida con la id y el email .
Por lo tanto, si solo necesita actualizar el email , simplemente elimínelo de la lista de import_id_fields . Al hacerlo, la lógica identificará de forma única las instancias basándose únicamente en el id , y luego se crearán nuevos registros si no existen, y se actualizarán los registros existentes (lo que incluirá la actualización de la dirección de correo electrónico).
Así es como se supone que funciona la import-export y no se requiere más lógica.
Si el email es el "campo único" que coincide con sus instancias existentes, entonces este debería ser el único campo en import_id_fields . No puede haber dos instancias de Profile con el mismo correo electrónico, porque unique=True , por lo tanto, puede usar el email como import_id_field . Sin embargo, no será posible actualizar el correo electrónico del Profile mediante import-export (aunque podría introducir un campo llamado new_email y tener lógica para actualizar el Profile de esa manera, pero ese es un tema aparte).
No sé por qué está viendo el error 'el correo electrónico ya existe'; posiblemente algo más esté sucediendo, y podría ser la lógica en before_import_row() lo que está causando el problema, probablemente debido al hecho de que una fila está siendo creado con una cadena vacía como correo electrónico.
por cierto, no debería necesitar nada de la lógica en before_import_row() : import-export debería manejar esto por usted, y al anularlo, podría estar introduciendo más errores.
El mejor consejo para usar import-export es establecer puntos de interrupción en su IDE y luego avanzar durante una importación y puede ver exactamente lo que está sucediendo. Esto le ahorrará mucho tiempo a largo plazo.
En resumen, use id o email en import_id_fields y debería funcionar.
Deberías intentar cambiar
import_id_fields = ('id', 'email')por
import_id_fields = ('email',) Cuando intenta importar una fila con una ID vacía, siempre se percibirá como una fila nueva. Por lo tanto, crea en lugar de actualizar en este caso. Pero cuando dejas solo el email en tu import_id_fields , obviamente hará una actualización en lugar de crear.
¿Ya has probado esto?
#try this email = models.EmailField(max_length=200, unique=True, null=True) try: self.email = row["email"] except Exception as e: self.email = None unique=True también bloquea duplicados "", pero nulo no está bloqueado.