diff --git a/binary_database_files/storage.py b/binary_database_files/storage.py index 9615140..6886064 100644 --- a/binary_database_files/storage.py +++ b/binary_database_files/storage.py @@ -126,7 +126,18 @@ def path(self, name): """ localpath = self._path(self.get_instance_name(name)) if not os.path.exists(localpath): - raise NotImplementedError + try: + # Load file from database. + f = models.File.objects.get_from_name(name) + # Automatically write the file to the filesystem + # if it's missing and exists in the database. + # This happens if we're using multiple web servers connected + # to a common database behind a load balancer. + # One user might upload a file from one web server, and then + # another might access if from another server. + utils.write_file(name, f.content) + except models.File.DoesNotExist: + raise NotImplementedError return localpath def exists(self, name): diff --git a/binary_database_files/tests/tests.py b/binary_database_files/tests/tests.py index 5854175..81d7f5c 100644 --- a/binary_database_files/tests/tests.py +++ b/binary_database_files/tests/tests.py @@ -322,7 +322,6 @@ class Meta: self.assertTrue(t1.upload.storage.exists(t1.upload.name)) os.remove(t1.upload.path) self.assertTrue(t1.upload.storage.exists(t1.upload.name)) - self.assertRaises(NotImplementedError, lambda t1: t1.upload.path, t1) data2 = b"22222222" open(os.path.join(tmpdir, "dummy.txt"), "wb").write(data2) t2 = Location2Thing.objects.create( @@ -330,7 +329,6 @@ class Meta: ) os.remove(t2.upload.path) self.assertTrue(t2.upload.storage.exists(t2.upload.name)) - self.assertRaises(NotImplementedError, lambda t2: t2.upload.path, t2) self.assertEqual(File.objects.count(), 2) self.assertEqual(Location2Thing.objects.get(pk=t2.pk).upload.file.read(), data2) self.assertEqual(Location1Thing.objects.get(pk=t1.pk).upload.file.read(), data1) @@ -405,6 +403,18 @@ def test_reading_file(self): self.assertEqual(response["content-type"], "text/plain") self.assertEqual(response["content-length"], "10") + def test_path_for_file_from_database(self): + call_command("loaddata", "test_files.json") + self.assertEqual(File.objects.count(), 1) + test_fqfn = os.path.join(DIR, "media", "1.txt") + os.remove(test_fqfn) + # File only exists in the database at this point + self.assertFalse(os.path.exists(test_fqfn)) + storage = DatabaseStorage() + self.assertEqual(storage.path("1.txt"), test_fqfn) + # File now exists in the filesystem so that it can be accessed directly + self.assertTrue(os.path.exists(test_fqfn)) + def test_serve_file_from_database(self): call_command("loaddata", "test_files.json") self.assertEqual(File.objects.count(), 1)