Django application and library for importing and exporting data with included admin integration.
—
Form classes for handling file uploads, format selection, field selection, and import confirmation workflows in web interfaces.
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
"""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
"""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
"""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})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})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})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,
})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)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');
}
});
});
"""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 responseInstall with Tessl CLI
npx tessl i tessl/pypi-django-import-export