Skip to content

Commit

Permalink
Merge 4405f15 into debd86f
Browse files Browse the repository at this point in the history
  • Loading branch information
jonathan-s committed Feb 6, 2018
2 parents debd86f + 4405f15 commit 98544f7
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 10 deletions.
13 changes: 13 additions & 0 deletions AUTHORS
@@ -0,0 +1,13 @@
The following people have contributed to django-postgres-copy

Ben Welsh (palewire)
Chaim Kirby (ckirby)
James Gordon (gordonje)
Ryan Murphy (rdmurphy)
Magnum Leno (magnunleno)
Yury Paykov (ojomio)
Douglas Denhartog (denhartog)
Michael Corey (mikejcorey)
Jonathan Barratt (reduxionist)
Daniel Cloud (dcloud)
Jonathan Sundqvist (jonathan-s)
14 changes: 13 additions & 1 deletion docs/index.rst
Expand Up @@ -46,10 +46,22 @@ And here's how it exports a database table to a CSV.
from myapp.models import MyModel
MyModel.objects.to_csv("./data.csv")
You can also use these methods standalone if you so need.

.. code-block: python
from postgres_copy import from_csv
from myapp.models import MyModel
from_csv(MyModel, './data.csv', dict(name='NAME', number='NUMBER'))
query = MyModel.objects.all()
to_csv('./export.csv', query, db='default')
Installation
============

Expand Down
6 changes: 4 additions & 2 deletions postgres_copy/__init__.py
Expand Up @@ -2,7 +2,7 @@
# -*- coding: utf-8 -*-
from .copy_from import CopyMapping
from .copy_to import SQLCopyToCompiler, CopyToQuery
from .managers import CopyManager, CopyQuerySet
from .managers import CopyManager, CopyQuerySet, from_csv, to_csv
__version__ = '2.3.0'


Expand All @@ -11,5 +11,7 @@
'CopyMapping',
'CopyQuerySet',
'CopyToQuery',
'SQLCopyToCompiler'
'SQLCopyToCompiler',
'from_csv',
'to_csv'
)
1 change: 1 addition & 0 deletions postgres_copy/copy_from.py
Expand Up @@ -153,6 +153,7 @@ def validate_mapping(self):
Raises errors if something goes wrong. Returns nothing if everything is kosher.
"""

# Make sure all of the CSV headers in the mapping actually exist
for map_header in self.mapping.values():
if map_header not in self.headers:
Expand Down
35 changes: 31 additions & 4 deletions postgres_copy/managers.py
Expand Up @@ -131,6 +131,23 @@ def from_csv(self, csv_path, mapping=None, drop_constraints=True, drop_indexes=T
"""
Copy CSV file from the provided path to the current model using the provided mapping.
"""
command = CopyCommand(self.model)
return command.from_csv(csv_path, mapping, drop_constraints, drop_indexes, silent, **kwargs)

def to_csv(self, csv_path, *fields, **kwargs):
"""
Copy current QuerySet to CSV at provided path.
"""
command = CopyCommand(self.model)
command.to_csv(csv_path, self.query, self.db, *fields, **kwargs)


class CopyCommand(ConstraintQuerySet):

def __init__(self, model):
self.model = model

def from_csv(self, csv_path, mapping=None, drop_constraints=True, drop_indexes=True, silent=True, **kwargs):
mapping = CopyMapping(self.model, csv_path, mapping, **kwargs)

if drop_constraints:
Expand All @@ -147,16 +164,16 @@ def from_csv(self, csv_path, mapping=None, drop_constraints=True, drop_indexes=T

return insert_count

def to_csv(self, csv_path, *fields, **kwargs):
def to_csv(self, csv_path, query, db, *fields, **kwargs):
"""
Copy current QuerySet to CSV at provided path.
"""
try:
# For Django 2.0 forward
query = self.query.chain(CopyToQuery)
query = query.chain(CopyToQuery)
except AttributeError:
# For Django 1.11 backward
query = self.query.clone(CopyToQuery)
query = query.clone(CopyToQuery)

# Get fields
query.copy_to_fields = fields
Expand All @@ -173,8 +190,18 @@ def to_csv(self, csv_path, *fields, **kwargs):
query.copy_to_null_string = "" if null_string is None else "NULL '{}'".format(null_string)

# Run the query
compiler = query.get_compiler(self.db, connection=connection)
compiler = query.get_compiler(db, connection=connection)
compiler.execute_sql(csv_path)


def from_csv(model, csv_path, mapping=None, drop_constraints=True, drop_indexes=True, silent=True, **kwargs):
command = CopyCommand(model)
return command.from_csv(csv_path, mapping, drop_constraints, drop_indexes, silent, **kwargs)


def to_csv(csv_path, query, db, *fields, **kwargs):
command = CopyCommand(query.model)
command.to_csv(csv_path, query.query, db, *fields, **kwargs)


CopyManager = models.Manager.from_queryset(CopyQuerySet)
34 changes: 31 additions & 3 deletions tests/tests.py
@@ -1,6 +1,10 @@
import os
import csv
from datetime import date
from django.test import TestCase
from django.db.models import Count
from django.core.exceptions import FieldDoesNotExist
from django.conf import settings
from .models import (
MockObject,
MockFKObject,
Expand All @@ -11,10 +15,8 @@
HookedCopyMapping,
SecondaryMockObject
)
from django.test import TestCase
from django.db.models import Count
from postgres_copy import CopyMapping
from django.core.exceptions import FieldDoesNotExist
from postgres_copy import from_csv, to_csv


class BaseTest(TestCase):
Expand Down Expand Up @@ -186,6 +188,32 @@ def test_export_multi_db(self):
items
)

class StandAloneTest(PostgresCopyToTest):

def setUp(self):
super(StandAloneTest, self).setUp()
self.export_path = os.path.join(os.path.dirname(__file__), 'export.csv')

def test_standalone_from_csv(self):
from_csv(MockObject, self.name_path, dict(name='NAME', number='NUMBER', dt='DATE'))

self.assertEqual(MockObject.objects.count(), 3)
self.assertEqual(MockObject.objects.get(name='BEN').number, 1)
self.assertEqual(
MockObject.objects.get(name='BEN').dt,
date(2012, 1, 1)
)

def test_standalone_to_csv(self):
self._load_objects(self.name_path)
to_csv(self.export_path, MockObject.objects.all(), 'default')
self.assertTrue(os.path.exists(self.export_path))
reader = csv.DictReader(open(self.export_path, 'r'))
self.assertTrue(
['BEN', 'JOE', 'JANE'],
[i['name'] for i in reader]
)


class PostgresCopyFromTest(BaseTest):

Expand Down

0 comments on commit 98544f7

Please sign in to comment.