144👍
From Django docs on Client.post
:
Submitting files is a special case. To POST a file, you need only
provide the file field name as a key, and a file handle to the file
you wish to upload as a value. For example:
c = Client()
with open('wishlist.doc') as fp:
c.post('/customers/wishes/', {'name': 'fred', 'attachment': fp})
168👍
I used to do the same with open('some_file.txt') as fp:
but then I needed images, videos and other real files in the repo and also I was testing a part of a Django core component that is well tested, so currently this is what I have been doing:
from django.core.files.uploadedfile import SimpleUploadedFile
def test_upload_video(self):
video = SimpleUploadedFile("file.mp4", "file_content", content_type="video/mp4")
self.client.post(reverse('app:some_view'), {'video': video})
# some important assertions ...
In Python 3.5+ you need to use bytes
object instead of str
. Change "file_content"
to b"file_content"
It’s been working fine, SimpleUploadedFile
creates an InMemoryFile
that behaves like a regular upload and you can pick the name, content and content type.
- [Django]-Django 1.5 custom User model error. "Manager isn't available; User has been swapped"
- [Django]-Django self-referential foreign key
- [Django]-Django fix Admin plural
7👍
I recommend you to take a look at Django RequestFactory. It’s the best way to mock data provided in the request.
Said that, I found several flaws in your code.
- “unit” testing means to test just one “unit” of functionality. So,
if you want to test that view you’d be testing the view, and the file
system, ergo, not really unit test. To make this point more clear. If
you run that test, and the view works fine, but you don’t have
permissions to save that file, your test would fail because of that. - Other important thing is test speed. If you’re doing something like
TDD the speed of execution of your tests is really important.
Accessing any I/O is not a good idea.
So, I recommend you to refactor your view to use a function like:
def upload_file_to_location(request, location=None): # Can use the default configured
And do some mocking on that. You can use Python Mock.
PS: You could also use Django Test Client But that would mean that you’re adding another thing more to test, because that client make use of Sessions, middlewares, etc. Nothing similar to Unit Testing.
- [Django]-How can I temporarily disable a foreign key constraint in MySQL?
- [Django]-Django models: Only permit one entry in a model?
- [Django]-Auth.User.groups: (fields.E304) Reverse accessor for 'User.groups' clashes with reverse accessor for 'UserManage.groups'
6👍
I do something like this for my own event related application but you should have more than enough code to get on with your own use case
import tempfile, csv, os
class UploadPaperTest(TestCase):
def generate_file(self):
try:
myfile = open('test.csv', 'wb')
wr = csv.writer(myfile)
wr.writerow(('Paper ID','Paper Title', 'Authors'))
wr.writerow(('1','Title1', 'Author1'))
wr.writerow(('2','Title2', 'Author2'))
wr.writerow(('3','Title3', 'Author3'))
finally:
myfile.close()
return myfile
def setUp(self):
self.user = create_fuser()
self.profile = ProfileFactory(user=self.user)
self.event = EventFactory()
self.client = Client()
self.module = ModuleFactory()
self.event_module = EventModule.objects.get_or_create(event=self.event,
module=self.module)[0]
add_to_admin(self.event, self.user)
def test_paper_upload(self):
response = self.client.login(username=self.user.email, password='foz')
self.assertTrue(response)
myfile = self.generate_file()
file_path = myfile.name
f = open(file_path, "r")
url = reverse('registration_upload_papers', args=[self.event.slug])
# post wrong data type
post_data = {'uploaded_file': i}
response = self.client.post(url, post_data)
self.assertContains(response, 'File type is not supported.')
post_data['uploaded_file'] = f
response = self.client.post(url, post_data)
import_file = SubmissionImportFile.objects.all()[0]
self.assertEqual(SubmissionImportFile.objects.all().count(), 1)
#self.assertEqual(import_file.uploaded_file.name, 'files/registration/{0}'.format(file_path))
os.remove(myfile.name)
file_path = import_file.uploaded_file.path
os.remove(file_path)
- [Django]-Is it possible to pass query parameters via Django's {% url %} template tag?
- [Django]-Django – filtering on foreign key properties
- [Django]-How to use MySQLdb with Python and Django in OSX 10.6?
5👍
I did something like that :
from django.core.files.uploadedfile import SimpleUploadedFile
from django.test import TestCase
from django.core.urlresolvers import reverse
from django.core.files import File
from django.utils.six import BytesIO
from .forms import UploadImageForm
from PIL import Image
from io import StringIO
def create_image(storage, filename, size=(100, 100), image_mode='RGB', image_format='PNG'):
"""
Generate a test image, returning the filename that it was saved as.
If ``storage`` is ``None``, the BytesIO containing the image data
will be passed instead.
"""
data = BytesIO()
Image.new(image_mode, size).save(data, image_format)
data.seek(0)
if not storage:
return data
image_file = ContentFile(data.read())
return storage.save(filename, image_file)
class UploadImageTests(TestCase):
def setUp(self):
super(UploadImageTests, self).setUp()
def test_valid_form(self):
'''
valid post data should redirect
The expected behavior is to show the image
'''
url = reverse('image')
avatar = create_image(None, 'avatar.png')
avatar_file = SimpleUploadedFile('front.png', avatar.getvalue())
data = {'image': avatar_file}
response = self.client.post(url, data, follow=True)
image_src = response.context.get('image_src')
self.assertEquals(response.status_code, 200)
self.assertTrue(image_src)
self.assertTemplateUsed('content_upload/result_image.html')
create_image function will create image so you don’t need to give static path of image.
Note : You can update code as per you code.
This code for Python 3.6.
- [Django]-Django REST Framework: adding additional field to ModelSerializer
- [Django]-Get the list of checkbox post in django views
- [Django]-What does "'tests' module incorrectly imported" mean?
3👍
from rest_framework.test import force_authenticate
from rest_framework.test import APIRequestFactory
factory = APIRequestFactory()
user = User.objects.get(username='#####')
view = <your_view_name>.as_view()
with open('<file_name>.pdf', 'rb') as fp:
request=factory.post('<url_path>',{'file_name':fp})
force_authenticate(request, user)
response = view(request)
- [Django]-Django: sqlite for dev, mysql for prod?
- [Django]-How to set a value of a variable inside a template code?
- [Django]-How can i test for an empty queryset in Django?
2👍
As mentioned in Django’s official documentation:
Submitting files is a special case. To POST a file, you need only provide the file field name as a key, and a file handle to the file you wish to upload as a value. For example:
c = Client()
with open('wishlist.doc') as fp:
c.post('/customers/wishes/', {'name': 'fred', 'attachment': fp})
More Information: How to check if the file is passed as an argument to some function?
While testing, sometimes we want to make sure that the file is passed as an argument to some function.
e.g.
...
class AnyView(CreateView):
...
def post(self, request, *args, **kwargs):
attachment = request.FILES['attachment']
# pass the file as an argument
my_function(attachment)
...
In tests, use Python’s mock something like this:
# Mock 'my_function' and then check the following:
response = do_a_post_request()
self.assertEqual(mock_my_function.call_count, 1)
self.assertEqual(
mock_my_function.call_args,
call(response.wsgi_request.FILES['attachment']),
)
- [Django]-Is it secure to store passwords as environment variables (rather than as plain text) in config files?
- [Django]-What is actually assertEquals in Python?
- [Django]-PHP Frameworks (CodeIgniter, Yii, CakePHP) vs. Django
2👍
if you want to add other data with file upload then follow the below method
file = open('path/to/file.txt', 'r', encoding='utf-8')
data = {
'file_name_to_receive_on_backend': file,
'param1': 1,
'param2': 2,
.
.
}
response = self.client.post("/url/to/view", data, format='multipart')`
The only file_name_to_receive_on_backend
will be received as a file other params received normally as post paramas.
- [Django]-Django: Fat models and skinny controllers?
- [Django]-Django count RawQuerySet
- [Django]-No URL to redirect to. Either provide a url or define a get_absolute_url method on the Model
1👍
In Django 1.7 there’s an issue with the TestCase wich can be resolved by using open(filepath, ‘rb’) but when using the test client we have no control over it. I think it’s probably best to ensure file.read() returns always bytes.
source: https://code.djangoproject.com/ticket/23912, by KevinEtienne
Without rb option, a TypeError is raised:
TypeError: sequence item 4: expected bytes, bytearray, or an object with the buffer interface, str found
- [Django]-Differences between STATICFILES_DIR, STATIC_ROOT and MEDIA_ROOT
- [Django]-Separating form input and model validation in Django?
- [Django]-Django proxy model and ForeignKey
1👍
from django.test import Client
from requests import Response
client = Client()
with open(template_path, 'rb') as f:
file = SimpleUploadedFile('Name of the django file', f.read())
response: Response = client.post(url, format='multipart', data={'file': file})
Hope this helps.
- [Django]-">", "<", ">=" and "<=" don't work with "filter()" in Django
- [Django]-No handlers could be found for logger
- [Django]-Factory-boy create a list of SubFactory for a Factory
1👍
I am using django rest framework and I had to test the upload of multiple files.
I finally get it by using format="multipart"
in my APIClient.post
request.
from rest_framework.test import APIClient
...
self.client = APIClient()
with open('./photo.jpg', 'rb') as fp:
resp = self.client.post('/upload/',
{'images': [fp]},
format="multipart")
- [Django]-What is "load url from future" in Django
- [Django]-How to produce a 303 Http Response in Django?
- [Django]-Django migration strategy for renaming a model and relationship fields
1👍
Very handy solution with mock
from django.test import TestCase, override_settings
#use your own client request factory
from my_framework.test import APIClient
from django.core.files import File
import tempfile
from pathlib import Path
import mock
image_mock = mock.MagicMock(spec=File)
image_mock.name = 'image.png' # or smt else
class MyTest(TestCase):
# I assume we want to put this file in storage
# so to avoid putting garbage in our MEDIA_ROOT
# we're using temporary storage for test purposes
@override_settings(MEDIA_ROOT=Path(tempfile.gettempdir()))
def test_send_file(self):
client = APIClient()
client.post(
'/endpoint/'
{'file':image_mock},
format="multipart"
)
- [Django]-Reference list item by index within Django template?
- [Django]-Django Rest Framework – Could not resolve URL for hyperlinked relationship using view name "user-detail"
- [Django]-How to use regex in django query
1👍
Test case
from django.test import TestCase, Client
from django.test.client import MULTIPART_CONTENT
class TestUpload(TestCase):
def test_upload():
with open(file_path, "rb") as f:
response = self.client.post(url, {"file": f},
content_type=MULTIPART_CONTENT
)
Serializer
class FileSerializer(Serializer):
file = serializers.FileField(required=True)
View
you can get file from serializer.validated_data
class TestView(ViewSet):
def post():
serializer = FileSerializer(data=request.FILES)
params = serializer.validated_data
file = params.get("file")
print(file.read())
- [Django]-IOS app with Django
- [Django]-Auth.User.groups: (fields.E304) Reverse accessor for 'User.groups' clashes with reverse accessor for 'UserManage.groups'
- [Django]-Django Form File Field disappears on form error
0👍
I am using Python==3.8.2 , Django==3.0.4, djangorestframework==3.11.0
I tried self.client.post
but got a Resolver404
exception.
Following worked for me:
import requests
upload_url='www.some.com/oaisjdoasjd' # your url to upload
with open('/home/xyz/video1.webm', 'rb') as video_file:
# if it was a text file we would perhaps do
# file = video_file.read()
response_upload = requests.put(
upload_url,
data=video_file,
headers={'content-type': 'video/webm'}
)
- [Django]-How to get a favicon to show up in my django app?
- [Django]-UUID as default value in Django model
- [Django]-Django TypeError: get() got multiple values for keyword argument 'invoice_id'
0👍
I am using GraphQL, upload for test:
with open('test.jpg', 'rb') as fp:
response = self.client.execute(query, variables, data={'image': [fp]})
code in class mutation
@classmethod
def mutate(cls, root, info, **kwargs):
if image := info.context.FILES.get("image", None):
kwargs["image"] = image
TestingMainModel.objects.get_or_create(
id=kwargs["id"],
defaults=kwargs
)
- [Django]-How to get the current URL within a Django template?
- [Django]-Django Admin – Disable the 'Add' action for a specific model
- [Django]-Django Model() vs Model.objects.create()
0👍
Adapting @danilo-cabello example for uploading multiple files –
from django.core.files.uploadedfile import SimpleUploadedFile
def test_upload_video(self):
videos = [
SimpleUploadedFile(name, "file_content", content_type="video/mp4")
for name in ("file_1.mp4", "file_2.mp4")
]
# `video` or whatever the name of the `FileField` is ...
self.client.post(reverse('app:some_view'), data={'video': videos})
I didn’t see a similar example, & was thrown off by using files
instead of data
on self.client
which resulted in an empty request.FILES
in my view code on test runs
- [Django]-Chaining multiple filter() in Django, is this a bug?
- [Django]-Django auto_now and auto_now_add
- [Django]-Filter Queryset on empty ImageField