django在几个相关模型中导入csv

时间:2018-03-06 00:43:22

标签: python django csv import

对于研究蝙蝠(http://www.dbchiro.org)的自然数据的Web应用程序,我需要能够提出一个视图,允许将文件从电子表格(csv,ods文件,xls)导入数据库。要将此数据导入单个表,没问题,存在多个扩展(特别是django-import-export或django-csvimport)。另一方面,我的需求更加特殊,因为我的自然主义数据分布在几个不同的表中(不包括字典表)。

这是示意图:

  1. 模型放置放置(地点是具有唯一x / y的网站 坐标作为建筑物。)。
  2. 1-n模型会话(一个数据=一个日期和一个地方的库存方法)
  3. 1-n模型瞄准(一个数据=每个会话一个物种)
  4. 1-n模型 CountDetail (一个数据=一个物种的1个细节:例如男性数量,女性数量等)
  5. 我想得到的是能够使用单个csv文件导入会话数据,该文件将填充最后两个模型:观察(瞄准)和每个观察(观察到的每个物种),其详细数据( CountDetail)。

    是否有一个或多个简单的解决方案(我做得很好,但我也不是一个优秀的python专家)。

    否则,我想象的解决方案是加载此csv数据(在特定模型中?)并为每次导入执行查询以填充模型:

    1. 按表单导入源文件(CSV,ods,excel)。
    2. 在对应于观察模型(种类)的字段上使用命令“select distinct”在父表中创建并插入数据集。
    3. 然后为会话的每个种类(for ...),在子表中创建和插入数据(CountDetail)。
    4. 我正在接受建议/示例/片段:)

      谢谢!

      佛瑞德。

      class Place(models.Model):
          id_place = models.AutoField(primary_key=True, db_index=True)
          [...]
      
          class Meta:
          verbose_name = "Localité"
          unique_together = ['name', 'municipality', 'type']
      
      
      
      class Session(models.Model):
          id_session = models.AutoField(primary_key=True)
          contact = models.ForeignKey(Contact,models.DO_NOTHING, null=True, verbose_name=_("Type de contact"))
          place = models.ForeignKey(Place,on_delete=models.CASCADE,verbose_name='Localité associée')
          date_start = models.DateField(
          verbose_name='Date de début', help_text=_('Format de date: <em>01/01/2017</em>.'))
          [...]
          timestamp_create = models.DateTimeField(
          auto_now_add=True, editable=False)
          timestamp_update = models.DateTimeField(
          auto_now=True, editable=False)
          created_by = models.ForeignKey(
          settings.AUTH_USER_MODEL, null=True, db_index=True, editable=False, related_name='session_creator')
          updated_by = models.ForeignKey(
          settings.AUTH_USER_MODEL, null=True, db_index=True, editable=False, related_name='session_modifier')
      
          def __str__(self):
          return "%s ∙ %s ∙ %s" % (
              self.place, datetime.date(self.date_start.year, self.date_start.month, self.date_start.day), self.contact)
      
          class Meta:
          verbose_name = "Session d'inventaire/observations"
          unique_together = ["place", "contact", "date_start"]
      
      class Sighting(models.Model):
          id_sighting = models.AutoField(_('id unique'), primary_key=True)
          session = models.ForeignKey(
          Session, on_delete=models.CASCADE, verbose_name=_('Session associée'))
          period = models.CharField(max_length=50, blank=True, null=True, verbose_name=_('Période d\'observation'))
          codesp = models.ForeignKey(
          Specie, on_delete=DO_NOTHING, verbose_name=_('Espèce ou groupe d\'espèce'))
          total_count = models.PositiveIntegerField('Nombre total', blank=True, null=True, help_text=_('Désactivé pour les données acoustiques et en main'))
          breed_colo = models.NullBooleanField(
          verbose_name='Colonie de reproduction')
          [...]
          timestamp_create = models.DateTimeField(
          auto_now_add=True, editable=False)
          timestamp_update = models.DateTimeField(
          auto_now=True, editable=False)
          created_by = models.ForeignKey(
          settings.AUTH_USER_MODEL, null=True, db_index=True, editable=False, related_name='sighting_creator')
          updated_by = models.ForeignKey(
          settings.AUTH_USER_MODEL, null=True, db_index=True, editable=False, related_name='sighting_modifier')
      
          def __str__(self):
          return "%s ∙ %s ∙ %s" % (self.session, self.codesp, self.total_count)
      
          class Meta:
          verbose_name = "Observation"
          verbose_name_plural = "Observations"
          unique_together = ["codesp", "session"]
      
      
      class CountDetail(models.Model):
          id_countdetail = models.AutoField(primary_key=True)
          sighting = models.ForeignKey(Sighting,
                                   on_delete=models.CASCADE, related_name='countdetail_sighting')
          method = models.ForeignKey(Method, on_delete=models.DO_NOTHING, verbose_name=_('Méthode'), blank=True,
                                 null=True)
          sex = models.ForeignKey(Sex,models.DO_NOTHING,blank=True,null=True,verbose_name=_('Sexe'))
          age = models.ForeignKey(Age,models.DO_NOTHING,blank=True,null=True,verbose_name=_('Age estimé'))
          [...]
          timestamp_create = models.DateTimeField(
          auto_now_add=True, editable=False)
          timestamp_update = models.DateTimeField(
          auto_now=True, editable=False)
          created_by = models.ForeignKey(
          settings.AUTH_USER_MODEL, null=True, db_index=True, editable=False, related_name='countdetail_creator')
          updated_by = models.ForeignKey(
          settings.AUTH_USER_MODEL, null=True, db_index=True, editable=False, related_name='countdetail_modifier')
      
          def __str__(self):
          return "%s ∙ %s ∙ %s ∙ %s" % (self.sighting.session.place.name, self.sex, self.age, self.count)
      
          class Meta:
          verbose_name = "4 ∙ Comptage détaillé"
      

1 个答案:

答案 0 :(得分:1)

您可以使用django-import-export。

在admin.py中,您可以创建类资源并添加到admin。

admin.py

    from .models import Place,Session
    from import_export import resources,widgets
    from import_export.fields import Field
    from django.contrib import admin

    class SessionResource(resources.ModelResource):
        id_session = Field(column_name='field_id_sesion_excel',attribute='id_session')
        place = Field(column_name='place_field_excel', attribute='place', widget=widgets.ForeignKeyWidget(Contact))

        class Meta:
            model = Session
            skip_unchanged = True

        def before_import_row(self,row, **kwargs):
            value = row['place_field_excel']
            obj = Place.objects.create(id_place=value) #create object place
            row['place_field_excel'] = obj.id # update value to id ob new object

        def save_instance(self,instance, using_transactions=True, dry_run=False):
            try:
                instance.save() # inside try for ignore error on duplicate primary keys
            except:
                pass

    @admin.register(Session)
    class SessionAdmin(ImportExportModelAdmin,admin.ModelAdmin):
        resource_class = SessionResource

你可以从csv,xls等导入