CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-django-import-export

Django application and library for importing and exporting data with included admin integration.

Pending
Overview
Eval results
Files

forms-ui.mddocs/

Forms and UI Components

Form classes for handling file uploads, format selection, field selection, and import confirmation workflows in web interfaces.

Capabilities

Base Import/Export Form

Foundation form class providing common functionality for import/export operations.

class ImportExportFormBase(forms.Form):
    file_format = forms.ChoiceField(label='Format', choices=())

    def __init__(self, import_formats, **kwargs):
        """
        Initialize form with available formats.
        
        Parameters:
        - import_formats: List of format classes available for import/export
        - **kwargs: Additional form initialization options
        """

    def get_format_choices(self):
        """
        Get format choices for the file_format field.
        
        Returns:
        List of (value, label) tuples for format selection
        """

Import Forms

Forms specifically designed for data import workflows.

class ImportForm(ImportExportFormBase):
    import_file = forms.FileField(label='File to import')
    resource = forms.ChoiceField(label='Resource', choices=(), required=False)

    def __init__(self, import_formats, resources=None, **kwargs):
        """
        Initialize import form with formats and resources.
        
        Parameters:
        - import_formats: List of format classes for import
        - resources: List of resource classes (optional)
        - **kwargs: Additional form options
        """

    def is_valid(self):
        """
        Validate form data including file upload and format selection.
        
        Returns:
        bool, True if form is valid
        """

class ConfirmImportForm(forms.Form):
    import_file_name = forms.CharField(widget=forms.HiddenInput())
    original_file_name = forms.CharField(widget=forms.HiddenInput())
    input_format = forms.CharField(widget=forms.HiddenInput())
    resource = forms.CharField(widget=forms.HiddenInput(), required=False)

    def __init__(self, confirm_form_class, import_form_data, **kwargs):
        """
        Initialize confirmation form with import data.
        
        Parameters:
        - confirm_form_class: Form class for confirmation
        - import_form_data: Data from initial import form
        - **kwargs: Additional form options
        """

Export Forms

Forms for data export operations with format and field selection.

class ExportForm(ImportExportFormBase):
    resource = forms.ChoiceField(label='Resource', choices=(), required=False)

    def __init__(self, export_formats, resources=None, **kwargs):
        """
        Initialize export form with formats and resources.
        
        Parameters:
        - export_formats: List of format classes for export
        - resources: List of resource classes (optional)
        - **kwargs: Additional form options
        """

class SelectableFieldsExportForm(ExportForm):
    """Export form with field selection capability."""
    
    def __init__(self, export_formats, resources=None, resource_class=None, **kwargs):
        """
        Initialize export form with field selection.
        
        Parameters:
        - export_formats: List of format classes for export
        - resources: List of resource classes (optional)
        - resource_class: Specific resource class for field extraction
        - **kwargs: Additional form options
        """

    def get_export_fields(self):
        """
        Get selected fields for export.
        
        Returns:
        List of field names selected for export
        """

Usage Examples

Basic Import Form Usage

from import_export.forms import ImportForm
from import_export.formats.base_formats import CSV, XLSX, JSON
from django.shortcuts import render, redirect
from django.contrib import messages

def import_view(request):
    """View for handling data import."""
    
    formats = [CSV, XLSX, JSON]
    
    if request.method == 'POST':
        form = ImportForm(formats, data=request.POST, files=request.FILES)
        if form.is_valid():
            import_file = form.cleaned_data['import_file']
            file_format = form.cleaned_data['file_format']
            
            # Process import
            resource = BookResource()
            format_class = next(f for f in formats if f().get_title() == file_format)
            
            try:
                dataset = format_class().create_dataset(import_file.read().decode('utf-8'))
                result = resource.import_data(dataset, dry_run=True)
                
                if result.has_errors():
                    messages.error(request, f"Import errors: {len(result.base_errors)} errors found")
                else:
                    messages.success(request, f"Import preview: {result.total_rows} rows to import")
                    # Store data for confirmation
                    request.session['import_data'] = {
                        'dataset': dataset.dict,
                        'format': file_format,
                    }
                    return redirect('confirm_import')
                    
            except Exception as e:
                messages.error(request, f"Import failed: {e}")
    else:
        form = ImportForm(formats)
    
    return render(request, 'import.html', {'form': form})

Export Form with Field Selection

from import_export.forms import SelectableFieldsExportForm
from django.http import HttpResponse

def export_view(request):
    """View for handling data export with field selection."""
    
    formats = [CSV, XLSX, JSON]
    resource_class = BookResource
    
    if request.method == 'POST':
        form = SelectableFieldsExportForm(
            formats, 
            resource_class=resource_class,
            data=request.POST
        )
        if form.is_valid():
            file_format = form.cleaned_data['file_format']
            selected_fields = form.get_export_fields()
            
            # Perform export with selected fields
            resource = resource_class()
            queryset = Book.objects.all()
            dataset = resource.export(queryset, selected_fields=selected_fields)
            
            # Get format class and export data
            format_class = next(f for f in formats if f().get_title() == file_format)
            export_data = format_class().export_data(dataset)
            
            # Create response
            response = HttpResponse(
                export_data,
                content_type=format_class().get_content_type()
            )
            filename = f"books.{format_class().get_extension()}"
            response['Content-Disposition'] = f'attachment; filename="{filename}"'
            
            return response
    else:
        form = SelectableFieldsExportForm(formats, resource_class=resource_class)
    
    return render(request, 'export.html', {'form': form})

Custom Import Form with Validation

from import_export.forms import ImportForm
from django import forms

class CustomImportForm(ImportForm):
    """Custom import form with additional validation and fields."""
    
    encoding = forms.ChoiceField(
        choices=[
            ('utf-8', 'UTF-8'),
            ('latin-1', 'Latin-1'),
            ('cp1252', 'Windows-1252'),
        ],
        initial='utf-8',
        help_text='Character encoding of the import file'
    )
    
    skip_errors = forms.BooleanField(
        required=False,
        help_text='Skip rows with errors and continue import'
    )
    
    def clean_import_file(self):
        """Validate import file."""
        import_file = self.cleaned_data.get('import_file')
        
        if not import_file:
            return import_file
        
        # Check file size (limit to 10MB)
        if import_file.size > 10 * 1024 * 1024:
            raise forms.ValidationError('File too large. Maximum size is 10MB.')
        
        # Check file extension
        allowed_extensions = ['.csv', '.xlsx', '.xls', '.json', '.yaml']
        file_extension = import_file.name.lower().split('.')[-1]
        if f'.{file_extension}' not in allowed_extensions:
            raise forms.ValidationError(
                f'Unsupported file type. Allowed: {", ".join(allowed_extensions)}'
            )
        
        return import_file
    
    def clean(self):
        """Additional form validation."""
        cleaned_data = super().clean()
        
        import_file = cleaned_data.get('import_file')
        file_format = cleaned_data.get('file_format')
        
        if import_file and file_format:
            # Validate format matches file extension
            file_ext = import_file.name.lower().split('.')[-1]
            format_ext = file_format.lower()
            
            if file_ext != format_ext and not (file_ext == 'xls' and format_ext == 'xlsx'):
                raise forms.ValidationError(
                    f'File extension .{file_ext} does not match selected format {format_ext}'
                )
        
        return cleaned_data

# Usage in view
def custom_import_view(request):
    formats = [CSV, XLSX, JSON]
    
    if request.method == 'POST':
        form = CustomImportForm(formats, data=request.POST, files=request.FILES)
        if form.is_valid():
            # Access custom fields
            encoding = form.cleaned_data['encoding']
            skip_errors = form.cleaned_data['skip_errors']
            
            # Process import with custom options
            # ...
    else:
        form = CustomImportForm(formats)
    
    return render(request, 'custom_import.html', {'form': form})

Confirmation Form with Preview

from import_export.forms import ConfirmImportForm
from django.forms import formset_factory

class ImportPreviewForm(forms.Form):
    """Form for displaying import preview data."""
    
    def __init__(self, dataset, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.dataset = dataset
        
        # Add fields for each row to allow editing
        for i, row in enumerate(dataset):
            for j, header in enumerate(dataset.headers):
                field_name = f'row_{i}_col_{j}'
                self.fields[field_name] = forms.CharField(
                    initial=row[j],
                    required=False,
                    widget=forms.TextInput(attrs={'class': 'form-control'})
                )

class CustomConfirmImportForm(ConfirmImportForm):
    """Enhanced confirmation form with options."""
    
    dry_run = forms.BooleanField(
        required=False,
        initial=True,
        help_text='Perform dry run (no actual import)'
    )
    
    use_transactions = forms.BooleanField(
        required=False,
        initial=True,
        help_text='Use database transactions'
    )
    
    skip_unchanged = forms.BooleanField(
        required=False,
        help_text='Skip unchanged rows'
    )

def confirm_import_view(request):
    """View for import confirmation with preview."""
    
    if 'import_data' not in request.session:
        return redirect('import_view')
    
    import_data = request.session['import_data']
    dataset = Dataset()
    dataset.dict = import_data['dataset']
    
    if request.method == 'POST':
        confirm_form = CustomConfirmImportForm(data=request.POST)
        if confirm_form.is_valid():
            # Perform actual import
            resource = BookResource()
            result = resource.import_data(
                dataset,
                dry_run=confirm_form.cleaned_data.get('dry_run', True),
                use_transactions=confirm_form.cleaned_data.get('use_transactions', True),
                skip_unchanged=confirm_form.cleaned_data.get('skip_unchanged', False)
            )
            
            if result.has_errors():
                messages.error(request, f"Import failed with {len(result.base_errors)} errors")
            else:
                messages.success(request, f"Successfully imported {result.total_rows} rows")
                del request.session['import_data']
                return redirect('success_view')
    else:
        confirm_form = CustomConfirmImportForm(initial=import_data)
    
    preview_form = ImportPreviewForm(dataset)
    
    return render(request, 'confirm_import.html', {
        'confirm_form': confirm_form,
        'preview_form': preview_form,
        'dataset': dataset,
    })

Multi-Step Import Wizard

from django.contrib.formtools.wizard.views import SessionWizardView
from django.core.files.storage import default_storage

class ImportWizard(SessionWizardView):
    """Multi-step import wizard."""
    
    form_list = [
        ('upload', CustomImportForm),
        ('preview', ImportPreviewForm),
        ('confirm', CustomConfirmImportForm),
    ]
    
    templates = {
        'upload': 'wizard/upload.html',
        'preview': 'wizard/preview.html',
        'confirm': 'wizard/confirm.html',
    }
    
    def get_form_kwargs(self, step=None):
        """Get form kwargs for each step."""
        kwargs = super().get_form_kwargs(step)
        
        if step == 'upload':
            kwargs['import_formats'] = [CSV, XLSX, JSON]
        elif step == 'preview':
            # Get dataset from previous step
            upload_data = self.get_cleaned_data_for_step('upload')
            if upload_data:
                import_file = upload_data['import_file']
                file_format = upload_data['file_format']
                
                # Create dataset
                format_class = self.get_format_class(file_format)
                dataset = format_class.create_dataset(import_file.read().decode('utf-8'))
                kwargs['dataset'] = dataset
        
        return kwargs
    
    def done(self, form_list, **kwargs):
        """Process completed wizard."""
        upload_form, preview_form, confirm_form = form_list
        
        # Get final import settings
        import_file = upload_form.cleaned_data['import_file']
        file_format = upload_form.cleaned_data['file_format']
        dry_run = confirm_form.cleaned_data.get('dry_run', False)
        
        # Perform import
        resource = BookResource()
        format_class = self.get_format_class(file_format)
        dataset = format_class.create_dataset(import_file.read().decode('utf-8'))
        
        result = resource.import_data(dataset, dry_run=dry_run)
        
        return render(self.request, 'wizard/complete.html', {
            'result': result,
        })
    
    def get_format_class(self, format_name):
        """Get format class by name."""
        formats = {'csv': CSV, 'xlsx': XLSX, 'json': JSON}
        return formats.get(format_name.lower(), CSV)

AJAX Import Form

from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
import json

@csrf_exempt
def ajax_import_view(request):
    """AJAX endpoint for import operations."""
    
    if request.method != 'POST':
        return JsonResponse({'error': 'Method not allowed'}, status=405)
    
    form = ImportForm([CSV, XLSX, JSON], data=request.POST, files=request.FILES)
    
    if not form.is_valid():
        return JsonResponse({
            'success': False,
            'errors': form.errors
        })
    
    try:
        import_file = form.cleaned_data['import_file']
        file_format = form.cleaned_data['file_format']
        
        # Process import
        resource = BookResource()
        format_class = {'csv': CSV, 'xlsx': XLSX, 'json': JSON}[file_format.lower()]
        
        dataset = format_class().create_dataset(import_file.read().decode('utf-8'))
        result = resource.import_data(dataset, dry_run=True)
        
        return JsonResponse({
            'success': True,
            'preview': {
                'total_rows': result.total_rows,
                'has_errors': result.has_errors(),
                'errors': [str(error) for error in result.base_errors],
                'valid_rows': len(result.valid_rows()),
            }
        })
        
    except Exception as e:
        return JsonResponse({
            'success': False,
            'error': str(e)
        })

# JavaScript for AJAX form
"""
$('#import-form').on('submit', function(e) {
    e.preventDefault();
    
    var formData = new FormData(this);
    
    $.ajax({
        url: '{% url "ajax_import" %}',
        type: 'POST',
        data: formData,
        processData: false,
        contentType: false,
        success: function(response) {
            if (response.success) {
                $('#preview-section').html(
                    '<p>Preview: ' + response.preview.total_rows + ' rows</p>' +
                    '<p>Valid rows: ' + response.preview.valid_rows + '</p>'
                );
                if (response.preview.has_errors) {
                    $('#errors-section').html(
                        '<ul><li>' + response.preview.errors.join('</li><li>') + '</li></ul>'
                    );
                }
            } else {
                alert('Import failed: ' + response.error);
            }
        },
        error: function() {
            alert('Request failed');
        }
    });
});
"""

Form Integration with Class-Based Views

from django.views.generic import FormView
from django.urls import reverse_lazy

class ImportFormView(FormView):
    """Class-based view for import form."""
    
    template_name = 'import_form.html'
    form_class = CustomImportForm
    success_url = reverse_lazy('import_success')
    
    def get_form_kwargs(self):
        kwargs = super().get_form_kwargs()
        kwargs['import_formats'] = [CSV, XLSX, JSON]
        return kwargs
    
    def form_valid(self, form):
        # Process import
        import_file = form.cleaned_data['import_file']
        file_format = form.cleaned_data['file_format']
        
        resource = BookResource()
        format_class = self.get_format_class(file_format)
        dataset = format_class.create_dataset(import_file.read().decode('utf-8'))
        
        result = resource.import_data(dataset, dry_run=False)
        
        # Store result in session for success page
        self.request.session['import_result'] = {
            'total_rows': result.total_rows,
            'has_errors': result.has_errors(),
            'errors': [str(error) for error in result.base_errors],
        }
        
        return super().form_valid(form)
    
    def get_format_class(self, format_name):
        formats = {'csv': CSV, 'xlsx': XLSX, 'json': JSON}
        return formats.get(format_name.lower(), CSV)

class ExportFormView(FormView):
    """Class-based view for export form."""
    
    template_name = 'export_form.html'
    form_class = SelectableFieldsExportForm
    
    def get_form_kwargs(self):
        kwargs = super().get_form_kwargs()
        kwargs['export_formats'] = [CSV, XLSX, JSON]
        kwargs['resource_class'] = BookResource
        return kwargs
    
    def form_valid(self, form):
        file_format = form.cleaned_data['file_format']
        selected_fields = form.get_export_fields()
        
        # Perform export
        resource = BookResource()
        queryset = Book.objects.all()
        dataset = resource.export(queryset, selected_fields=selected_fields)
        
        # Create download response
        format_class = self.get_format_class(file_format)
        export_data = format_class.export_data(dataset)
        
        response = HttpResponse(
            export_data,
            content_type=format_class.get_content_type()
        )
        filename = f"books.{format_class.get_extension()}"
        response['Content-Disposition'] = f'attachment; filename="{filename}"'
        
        return response

Install with Tessl CLI

npx tessl i tessl/pypi-django-import-export

docs

admin-integration.md

file-formats.md

forms-ui.md

index.md

management-commands.md

resources-fields.md

widgets-transformation.md

tile.json