【问题标题】:How to uniquely identify a model instance in django如何在 django 中唯一标识模型实例
【发布时间】:2021-05-15 19:11:01
【问题描述】:

我有一个程序可以保存不同学校的书籍记录我有一个学生模型,它使每所学校都可以从 Excel 中上传学生。但是,我收到一个错误,因为已经有两所学校分别具有表格 1 表格 2 和表格 3。它返回 MultipleObjectsReturned 错误。 将文件设置为唯一也不允许其他学校创建相同的类。 我如何能够唯一地识别每个实例 ok Klass 模型,因此它不会返回错误。

get() 返回了多个 Klass -- 它返回了 2 个!

class ImportStudentsResource(resources.ModelResource):
    school = fields.Field(attribute = 'school',column_name='school', widget=ForeignKeyWidget(School, 'name'))
    klass = fields.Field(attribute = 'klass',column_name='class', widget=ForeignKeyWidget(Klass, 'name'))
    stream = fields.Field(attribute = 'stream',column_name='stream', widget=ForeignKeyWidget(Stream, 'name'))
    class Meta:
        model = Student
        fields = ('school','student_id','name','year','klass','stream')
        import_id_fields = ('student_id',)
        import_order = ('school','student_id','name','year','klass','stream')

class uploadStudents(LoginRequiredMixin,View):
    context = {}
    def get(self,request):
        form = UploadStudentsForm()
        self.context['form'] = form
        return render(request,'libman/upload_student.html',self.context)

    def post(self, request):
        form = UploadStudentsForm(request.POST , request.FILES)
        data_set = Dataset()
        if form.is_valid():
            file = request.FILES['file']
            extension = file.name.split(".")[-1].lower()
            resource = ImportStudentsResource()
            if extension == 'csv':
                data = data_set.load(file.read().decode('utf-8'), format=extension)
            else:
                data = data_set.load(file.read(), format=extension)
            result = resource.import_data(data_set, dry_run=True, collect_failed_rows=True, raise_errors=True)
            if result.has_validation_errors() or result.has_errors():
                messages.success(request,f'Errors experienced during import.')
                print("error", result.invalid_rows)
                self.context['result'] = result
                return redirect('upload_students')                
            else:
                result = resource.import_data(data_set, dry_run=False, raise_errors=False)
                self.context['result'] = None
                messages.success(request,f'Students uploaded successfully.')                
        else:
            self.context['form'] = UploadStudentsForm()

        return render(request, 'libman/upload_student.html', self.context)

class Student(models.Model):
    school = models.ForeignKey(School, on_delete=models.CASCADE)
    name = models.CharField(max_length=200)
    now = datetime.datetime.now()
    YEAR = [(str(a), str(a)) for a in range(now.year-2, now.year+2)]
    year = models.CharField(max_length=4, choices = YEAR)
    student_id = models.CharField(max_length=20,unique=True)
    klass = models.ForeignKey(Klass,on_delete=models.CASCADE)
    stream = models.ForeignKey(Stream,on_delete=models.CASCADE)

【问题讨论】:

  • 您能分享一下引发 MultipleObjectsReturned 错误的 get() 查询吗?
  • 我只有问题中已经存在的视图、资源和模型.....我没有得到您的关注吗??
  • 我得到了,返回 self.get_queryset(value, row, *args, **kwargs).get(**{self.field: val}) 表示来自 import_export/小部件.py
  • 我建议你使用docs.djangoproject.com/en/3.2/ref/models/options/… 这就是我问你这个问题的原因。但看起来您只是将一个命名参数传递给 get()。所以你不需要 unique_together。使 self.field unique=True 应该满足您的需求。
  • 我在这方面迷路了,拜托..

标签: django django-views django-import-export


【解决方案1】:

当您导入数据时,逻辑无法唯一标识“klass”的唯一实例。您正在使用与类的外键关系的“名称”属性,但是正如您所说,此“名称”字段无法唯一标识 Klass 的实例,因此您会收到 MultipleObjectsReturned 错误。

解决方案是创建ForeignKeyWidget 的子类,它使用覆盖的get_queryset() 可以唯一标识Klass。您将需要使用可以添加到查询中的附加参数。我猜school_id 可能有用(但我不知道你的数据模型)。​​

class KlassForeignKeyWidget(widgets.ForeignKeyWidget):
    """
    Custom widget to lookup a Klass instance
    """
    def __init__(
        self,
        school_id,
        field="name",
        *args,
        **kwargs,
    ):
        super().__init__(self.model, field=field, *args, **kwargs)
        self.school_id = school_id

    def get_queryset(self, value, row, *args, **kwargs):
        return self.model.objects.filter(school_id=self.school_id)

然后你必须在你的资源中声明这个自定义小部件:

class ImportStudentsResource(resources.ModelResource):

    def __init__(self, school_id):
        super().__init__()
        self.school_id = school_id

        self.fields["klass"] = fields.Field(
            attribute="klass",
            column_name="class",
            widget=myapp.widgets.KlassForeignKeyWidget(
                school_id,
            ),
        )

然后当你实例化ImportStudentsResourceyou pass in the school_id

【讨论】:

    猜你喜欢
    • 2021-12-15
    • 2020-07-04
    • 1970-01-01
    • 1970-01-01
    • 2019-08-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多