I'm trying to upload a picture with rest framework and to test it with the django test client. It almost works, however when I save the file I have this on the top of my file:
--BoUnDaRyStRiNg
Content-Disposition: form-data; name="plop.png"
If I delete those lines, I can perfectly read my picture, but I don't know how to rid of them.
models.py
class GenericUser(User):
avatar = models.ImageField(upload_to=user_directory_path)
views.py
class AvatarView(APIView):
parser_classes = (FileUploadParser,)
def post(self, request):
up_file = request.data['file']
user = get_object_or_404(GenericUser, pk=request.user.id)
user.avatar.save(up_file.name, up_file)
user.save()
return Response(status=204)
tests.py
cl = Client(HTTP_AUTHORIZATION="Token {}".format(token))
with open(MY_FILE, 'rb') as f:
data = f.read()
res = cl.post('/avatar', {"plop.png" : data}, HTTP_CONTENT_DISPOSITION="attachment; filename=plop.png;")
any hints, how I could make this work?
This worked as I expected:
views.py
class AvatarView(APIView):
parser_classes = (MultiPartParser,)
def post(self, request):
up_file = request.data["file"]
user = get_object_or_404(GenericUser, pk=request.user.id)
user.avatar.save(up_file.name, up_file)
user.save()
return Response(status=204)
test.py
cl = Client(HTTP_AUTHORIZATION="Token {}".format(token))
with open(MY_FILE, 'rb') as f:
res = cl.post('/avatar', {"file" : f})
Try this:
res = cl.post('/avatar?filename=plop.png', {"plop.png" : data})
Or more or less from the Django docs:
with open(MY_FILE, 'rb') as f:
cl.post('/avatar', {"filename" : f})
Related
Unable to store all the data into Django database. Its printing the correct list of data from an open API but not storing.
But if i give direct values of data1 in ( client.py ) for eg:
data1 = {
'employee_name':'Name',
'employee_salary':'20000',
'employee_age':'22',
'profile_image':' '
}
Then it store the above dictionary values into Django database.But the data i am getting using requests is a list.It prints in cmd but doesn't store in DB.
client.py file
def get_alldata():
url1 = "http://dummy.restapiexample.com/api/v1/employees"
url = "http://127.0.0.1:8000/employee/"
my_response = requests.get(url1)
token = get_token()
header = {'Authorization' : f'Token {get_token()}'}
data1 = [ my_response.json() ]
for d in range(len(data1)):
payload = data1[d]
res = requests.post(url, data=data1[d] , headers=header )
print(data1[d])
get_alldata()
This is the Api.py file in which includes the get and post method using serializers in django rest framework.
from rest_framework.authtoken.views import ObtainAuthToken
from rest_framework.authtoken.models import Token
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework import status
from employee.serializers import *
class EmployeeAuthentication(ObtainAuthToken):
def post(self,request, *args, **kwargs):
serializer = self.serializer_class(data=request.data, context={'request':request})
serializer.is_valid(raise_exception=True)
user = serializer.validated_data['user']
token , created = Token.objects.get_or_create(user=user)
return Response(token.key)
class EmployeeView(APIView):
def get(self, request):
model = Employee.objects.all()
serializer = EmployeeSerializer(model, many=True)
return Response(serializer.data)
def post(self, request):
serializer = EmployeeSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors,status=status.HTTP_400_BAD_REQUEST)
I got the solution.There is no problem in code yet.Problem was the data i was getting from an open API contains a Null value in a field which was unable to store into Django database.If anyone having same issue, don't GET any field having null value.
Hi I am trying to make a test case to test my upload image API. But I think I am not returning something when I pass the files for request.FILES
#models.py
class Image(models.Model):
name = models.CharField(max_length=200)
imagefile = models.ImageField(
null=True,
blank=True,
max_length=500,
upload_to='temp/images/')
def __str__(self):
return self.name
#views.py
class ImagesView(APIView):
def post(self, request):
print("DATA!!!", request.data)
print("FILE!!!", request.FILES)
params = Image(
imagefile=request.FILES['image'])
params.save()
print(params)
return Response({"status": "ok"})
#test.py
class CanalImagesApiTests(TestCase):
fixtures = []
def test_post_image(self):
c = Client()
response = c.post('/admin/login/', {'username': 'admin', 'password': 'passwrd'})
filename = 'data/sample_image.jpg'
name = 'sample_image.jpg'
data = {"data": "passthis"}
print(to_upload)
with open(filename, 'rb') as f:
c.post('/images/', data=data, files={"name": name, "image": f}, format='multipart')
response = c.get('/images/')
results = response.json()
My request.FILES is empty: <MultiValueDict: {}>
and my test gets an error: django.utils.datastructures.MultiValueDictKeyError: 'image'
You can pass a file object inside the data dictionary.
files parameter is not needed. format parameter means output format, not input format.
You can use APITestCase instead of TestCase if you are testing Django REST Framework API. This allows you can test some method like PUT.
from rest_framework import status
from rest_framework.test import APITestCase
class CanalImagesApiTests(APITestCase):
def test_post_image(self):
with open('data/sample_image.png', 'rb') as f:
data = {
"data": "passthis",
"image": f,
}
response = self.client.post('/images/', data=data)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.json(), {"status": "ok"})
Test result (which is passing):
DATA!!! <QueryDict: {'data': ['passthis'], 'image': [<InMemoryUploadedFile: sample_image.png (image/png)>]}>
FILE!!! <MultiValueDict: {'image': [<InMemoryUploadedFile: sample_image.png (image/png)>]}>
I have a scenario where a user uploads some data, Django does some processing in pandas and returns a potentially large txt file. I've got this working but I'm unsure about the scalability of the approach and want to know if there's a better way.
Adapted the Outputting to CSV section of the Django doc I have the following:
class MyClass(LoginRequiredMixin,FormView):
template_name = 'myapp/mytemplate.html'
form_class = MyForm
success_url = '/' # Replace with your URL or reverse().
def post(self, request, *args, **kwargs):
if request.method == 'POST':
form = MyForm(request.POST, request.FILES)
#print("filename",files[0].name)
if form.is_valid() :
filename = "my-file.txt"
content = 'any string generated by django'
response = HttpResponse(content, content_type='text/plain')
response['Content-Disposition'] = 'attachment; filename={0}'.format(filename)
return response
else:
print("i am invalid")
return self.form_invalid(form)
In practice I will need to output a text file of perhaps 1000 lines, built by looping over numerous dataframes, should I just build an extremely long text string (content), or is there a better way? In pure python I am more used to creating txt file output using:
f = open( 'some_file.txt', 'w+')
f.write("text")
f.write("text")
f.close()
Which seems more intuitive.
As requested by comments, updated to show exactly the code I was trying in Django which was returning an empty text file:
class MyClass(LoginRequiredMixin,FormView):
template_name = 'myapp/mytemplate.html'
form_class = MyForm
success_url = '/' # Replace with your URL or reverse().
def post(self, request, *args, **kwargs):
if request.method == 'POST':
form = MyForm(request.POST, request.FILES)
if form.is_valid() :
f = open( 'some_file.txt', 'w+')
f.write("text")
return FileResponse(f, as_attachment=True, filename='some_file.txt')
It's very simple:
response = HttpResponse(content_type='text/plain')
response['Content-Disposition'] = 'attachment; filename="filename.txt"'
response.write('Hello')
return response
https://docs.djangoproject.com/en/3.2/howto/outputting-csv/
It's same as CSV, just change extension to .txt
Example:
response = HttpResponse(content_type='text/plain')
response['Content-Disposition'] = 'attachment; filename="filename.txt"'
writer = csv.writer(response)
writer.writerow(['Hello'])
Hi I am trying to insert data to the database in django without forms.
This is my views.py file
def updatetrans(request):
json_data=open('/home/ttt/Abc/a.json').read()
data = json.loads(json_data)
for pk, pv in data.iteritems():
for k,v in pv.iteritems():
try:
print k, " =>> ", pv['transcript'][1]
except:
pass
This is my url.py file
url(r'^updatetrans/$', 'booki.account.views.updatetrans', name='updatetrans'),
Here is my models.py file. I have created two tables. And want to insert data in both of them separately.
class TransType(models.Model):
name = models.TextField()
def __unicode__(self):
return self.name
class Trans(models.Model):
trans = models.ForeignKey(TransType)
script = models.CharField(max_length=200)
def __unicode__(self):
return self.trans
I am getting the output on console. That output I want to save to the database.
Plz help.
Thank you.. I tried some other way. I am getting error as:
global name 'TransType' is not defined
Not inserted ==> e
My code:
def updatetrans(request):
json_data=open('/home/ttt/Ali/a.json').read()
data = json.loads(json_data)
for pk, pv in data.iteritems():
for k,v in pv.iteritems():
try:
trans_type = TransType.objects.get_or_create(name=k)
trans = Trans()
trans.trans_id = trans_type.id
trans.script = pv[k][1]
trans.save()
print " Inserted ==>", pv[k][1]
except Exception, e:
print e
print "Not inserted ==>", pv[k][1]
pass
return HttpResponse("Done")
The problem is solved. The answer is as follows.
To Store the records in the django database without using any input or form.
To avoid duplicate entries in the database.
This is my views.py file
def updatetrans(request):
json_data=open('/home/ttt/Ali/a.json').read()
data = json.loads(json_data)
for pk, pv in data.iteritems():
for k,v in pv.iteritems():
try:
trans_type = TransType.objects.get_or_create(name=k)
trans = Trans()
trans.transtype_id = trans_type[0].id
if isinstance(pv[k], basestring):
script = pv[k]
else:
print "****** List ****"
script = pv[k][1]
trans.script = script
trans.save()
print " Inserted ==>", script
except Exception, e:
print e
#print "Not inserted ==>", pv[k][1]
pass
return HttpResponse("Done")
This is my models.py file.
class TransType(models.Model):
name = models.TextField()
created = models.DateTimeField(auto_now_add = True)
updated = models.DateTimeField(auto_now = True)
def __unicode__(self):
return self.name
class Trans(models.Model):
transtype = models.ForeignKey(TransType)
script = models.CharField(max_length=200)
created = models.DateTimeField(auto_now_add = True)
updated = models.DateTimeField(auto_now = True)
class Meta:
unique_together = (("transtype", "script"),)
def __unicode__(self):
return self.trans
You just want to save data to database, so you can do it like this easily
>> cd project_directory
>> python manage.py shell
>> from xxx.models import TransType,Trans
>> tt = TransType.objects.create(name='read from file')
>> Trans.objects.create(trans=tt, script='read from file')
or write a python script to import data to database, put it in your project directory,run python manage.py shell then import yourscript
if you don't like python manage.py shell, just set DJANGO_SETTINGS_MODULE environment, then just run python yourscript in terminal. Such as
import os
os.environ["DJANGO_SETTINGS_MODULE"] = "yoursite.settings"
# The above two lines could be written simply as:
# from project.wsgi import *
from xxx.models import import TransType,Trans
TransType.objects.create()
Trans.objects.create()
remember to replace xxx with your app name
see QuerySet API:https://docs.djangoproject.com/en/dev/ref/models/querysets/#create
Chinese people could see here (other people could just read the code): http://www.ziqiangxuetang.com/django/django-import-data.html
You can do it using Model.objects.create()
Let's say you're receiving data from post form and want to save in QuillModel, here's how to do it in python2 django
from __future__ import unicode_literals
from django.http import HttpResponse
from django.shortcuts import redirect, render
from .forms import TemplateForm
from .models import QuillModel
def app3(request):
if request.method == "POST":
print(request.POST)
html_content = request.POST.get('html_content')
input_area = request.POST.get('input_area')
if html_content and input_area:
obj = QuillModel.objects.create(html_content=html_content, input_area=input_area)
obj.save()
return redirect('/app3/app3')
else:
form = TemplateForm()
return render(request, 'app3/forms/f1_post_form.html', {'form' : form})
See the if request.method == "POST": part for saving into database.
Since I have been doing the same thing..
For example:
models.py
class Dataset(models.Model):
hash = models.CharField(max_length=32)
category = models.CharField(max_length=10)
views.py
if request.method == "POST":
uploaded_file = request.FILES['document']
fs = FileSystemStorage()
fs.save(uploaded_file.name,uploaded_file)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
media_path = os.path.join(BASE_DIR,'dataset')
full_path=os.path.join(media_path,uploaded_file.name)
f = default_storage.open(full_path, 'r')
data = f.read()
for i in data.split("\n"):
hash,category = i.strip("\n").split(",")
Dataset.objects.create(hash=hash,category=category)
print("yes")
f.close()
Conclusion
You just specify your models and then create with what variable or column that you have.
MODELS.objects.create(column1=data1,column2=data2)
Example inside of my file
12345678,good
12345678,bad
I'm fairly new to django and Python and want to be able to export a list of items in my model i.e products. I'm looking at the documentation here - https://docs.djangoproject.com/en/dev/howto/outputting-csv/
I'm persuming I need will need to create a variable that stores all the data that I want. But not sure where it would within the snippet of code on the link above.
Apologies as this is a very noobish question but would really Any help at all.
Here is the code to my script so far:
import csv
from products.models import Product
from django.http import HttpResponse
def export_to_csv(request):
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename="mytest.csv"'
Have a look at the python csv module.
You'll probably want to get the models fields with
def get_model_fields(model):
return model._meta.fields
Then use
getattr(instance, field.name)
to get the field values (as in this question).
Then you'll want something like
with open('your.csv', 'wb') as csvfile:
writer = csv.writer(csvfile)
# write your header first
for obj in YourModel.objects.all():
row = ""
for field in fields:
row += getattr(obj, field.name) + ","
writer.writerow(row)
It's a bit verbose (and untested), but it should give you an idea. (Oh and don't forget to close your file)
Depending on the scenario - you may want to have a CSV of your model. If you have access to the Django Admin site, you can plug in a generic action for any model displayed as a list (google: django admin actions)
http://djangosnippets.org/snippets/790/
If you're operating with a console (python manage.py ...), you can use such a script, which I just used:
(place it in: yourapp/management/commands/model2csv.py)
"""
Prints CSV of all fields of a model.
"""
from django.core.management.base import BaseCommand, CommandError
import csv
import sys
class Command(BaseCommand):
help = ("Output the specified model as CSV")
args = '[appname.ModelName]'
def handle(self, *app_labels, **options):
from django.db.models import get_model
app_name, model_name = app_labels[0].split('.')
model = get_model(app_name, model_name)
field_names = [f.name for f in model._meta.fields]
writer = csv.writer(sys.stdout, quoting=csv.QUOTE_ALL)
writer.writerow(field_names)
for instance in model.objects.all():
writer.writerow([unicode(getattr(instance, f)).encode('utf-8') for f in field_names])
This does not catch any exceptions etc., but as an Admin you won't cause them to be raised, right?
Use it like:
./manage.py model2csv my_ecommerce.Product > products.csv
You can also make a template to assist in formatting!
The template is a common Django template
from django.template import loader
def export_to_csv(request):
response = HttpResponse(mimetype='text/csv')
response['Content-Disposition'] = 'attachment; filename="products-list.csv"'
template = loader.get_template('templates/products_template.csb')
response.write(template.render(Context({'products': Products.objects.all()})))
return response
Using django.db.models.query.QuerySet.values results in more optimised queries for my use case.
import csv
from datetime import datetime
from django.http import HttpResponse
# Populate this list with your model's fields
# Replace MODEL with your model
fields = [f.name for f in MODEL._meta.fields]
# The following code will live inside your view
timestamp = datetime.now().isoformat()
response = HttpResponse(content_type="text/csv")
response[
"Content-Disposition"
] = f"attachment; filename={timestamp}.csv"
writer = csv.writer(response)
# Write the header row
writer.writerow(fields)
# Replace MODEL with your model
for row in MODEL.objects.values(*fields):
writer.writerow([row[field] for field in fields])
return response
I use this on my code. A function called from view.
It automatically get model fields to make columns.
You can also customize the field list you want to export.
Function
import csv
from django.http import HttpResponse
from .models import Books
def export_qs_to_csv(model_class = None, qs = None, field_names = None):
if model_class and not qs:
qs = model_class.objects.all()
if qs and not model_class:
model_class = qs.model
meta = model_class._meta
if not field_names:
field_names = [field.name for field in meta.fields]
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename={}.csv'.format(meta)
writer = csv.writer(response)
writer.writerow(field_names)
for obj in qs:
row = writer.writerow([getattr(obj, field) for field in field_names])
return response
Usage
#user_passes_test(lambda u: u.is_superuser)
def export_books(request):
return export_qs_to_csv(model_class = Books)
# or
return export_qs_to_csv(qs = Books.objects.filter(published = True))
# or
return export_qs_to_csv(
qs = Books.objects.filter(published = True),
field_names = [
"title",
"price",
"publishing_date",
]
)
Original answer
It works, and it needs only to define model class in model_class variable.
This Django view let use downloads CSV. CSV name is Django_app.model_name.csv.
import csv
from django.http import HttpResponse
from .models import Trade
def export_to_csv(request):
# The only line to customize
model_class = Trade
meta = model_class._meta
field_names = [field.name for field in meta.fields]
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename={}.csv'.format(meta)
writer = csv.writer(response)
writer.writerow(field_names)
for obj in model_class.objects.all():
row = writer.writerow([getattr(obj, field) for field in field_names])
return response
Here is a potential solution, based on #tomasz-gandor 's answer, but updated to 2020:
"""
Prints CSV of all fields of a model.
"""
import csv
from django.core.management.base import BaseCommand, CommandError
class Command(BaseCommand):
help = ("Output the specified model as CSV")
def add_arguments(self, parser):
parser.add_argument('model',
nargs=1,
type=str,
help='Model name to export, like <app.model> or "members.Member"')
parser.add_argument('outfile',
nargs=1,
type=str,
help='Save path, like </path/to/outfile.csv> or "/data/members.csv"')
def handle(self, *app_labels, **options):
from django.apps import apps
app_name, model_name = options['model'][0].split('.')
model = apps.get_model(app_name, model_name)
field_names = [f.name for f in model._meta.fields]
writer = csv.writer(open(options['outfile'][0], 'w'), quoting=csv.QUOTE_ALL, delimiter=',')
writer.writerow(field_names)
for instance in model.objects.all():
writer.writerow([str(getattr(instance, f)) for f in field_names])
Can easily be used with:
python manage.py model2csv members.Member /data/members_export.csv
If you don't care about fieldnames and want all the fields, just do this.
with open('file_name.csv', 'w') as csvfile:
writer = csv.writer(csvfile)
for obj in YourModel.objects.values_list():
row = list(obj)
writer.writerow(row)
I combined some of the previous answers, because I needed to import some data from production and change some of it along the way. So here is my solution, which you can use to override some field values while writing the CSV file.
Export some queryset data into CSV file:
import csv
from myapp.models import MyModel
from user.models import User
# Make some queryset manually using Django shell:
user = User.objects.get(username='peterhil')
queryset = MyModel.objects.filter(user=user)
def query_to_csv(queryset, filename='items.csv', **override):
field_names = [field.name for field in queryset.model._meta.fields]
def field_value(row, field_name):
if field_name in override.keys():
return override[field_name]
else:
return row[field_name]
with open(filename, 'w') as csvfile:
writer = csv.writer(csvfile, quoting=csv.QUOTE_ALL, delimiter=',')
writer.writerow(field_names) # write the header
for row in queryset.values(*field_names):
writer.writerow([field_value(row, field) for field in field_names])
# Example usage:
query_to_csv(queryset, filename='data.csv', user=1, group=1)
Use this solution for model csv file.might being helpful
# Create the HttpResponse object with the appropriate CSV header.
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment;
filename="somefilename.csv"'
writer = csv.writer(response);
writer.writerow(["username","Email"]);
for i in User.objects.all():
writer.writerow([i.username,i.email])
return response
I used the django-queryset-csv package.
Follow these steps:
pip install django-queryset-csv
Your views.py:
import djqscsv
from products.models import Product
def get_csv(request):
qs = Product.objects.all()
return djqscsv.render_to_csv_response(qs)