im new in python and web2py, im stuck in creating a form to input csv file and the code to import the csv file.
here's my simple code
MODELS = db_tables.py
# -*- coding: utf-8 -*-
db = DAL('sqlite://storage.sqlite')
db.define_table('csvfile',
Field('nomor','integer'),
Field('nama'),
Field('umur','integer'),
migrate=False,
format = '%(name)s'
)
CONTROLLER = default.py
#auth.requires_login()
def index():
grid = SQLFORM.grid(db.csvfile, user_signature = False)
response.flash = T("Hello World")
return locals()
#def import_csv():
# form = FORM('Value:', INPUT(_value = 'name'), INPUT(_type = 'submit'))
# db.csvfile.import_from_csv_file(open('filename.csv'))
# return dict(form = form)
def import_csv():
form = FORM(INPUT(_type = 'file', _name = 'csv_file'),
INPUT(_type = 'submit', _value = T('Import')))
return(form=form)
VIEWS = default/index.html
{{left_sidebar_enabled,right_sidebar_enabled=False,('message' in globals())}}
{{extend 'layout.html'}}
<table>
<tr>{{=form}}
<td>{{pass}}
</td>
</tr>
</table>
actually i already show the table, but i cant make a form to input csv file and create a code to input the csv file with same header in 'csvfile' header
help me, thankyou!
You need to process the form by using form.process() to actually do something with the data.
See http://web2py.com/books/default/chapter/29/07/forms-and-validators#The-process-and-validate-methods
Related
Im working on a social media application in django and would like to rename all the images from the uploaded content to make it easier to reuse them (putting them in to a pdf is the end goal, right now the filenames are the same as uploaded and i don't know how put these paths into the pdf --> solution might be numbering them all).
The filename should be renamed to: postimg{num_post}
all posts are numbered. the specific number or the post should be the end of the filename of the image file.
models.py
def post_images(instance, filename):
ext = filename.split('.')[-1]
filename = "%s_%s.%s" % (instance.post.num_post, ext)
return os.path.join('uploads', filename)
class Post(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4)
num_post = models.IntegerField(default=0)
image = models.ImageField(upload_to='post_images')
caption = models.TextField(max_length=300)
created_at = models.DateTimeField(auto_now_add=True)
number_of_likes = models.IntegerField(default=0)
number_of_dislikes = models.IntegerField(default=0)
def __str__(self):
return self.caption
views.py
def upload(request):
if request.method == 'POST':
#user = request.user.username
image = request.FILES.get('image_upload')
#--> how to rename the image file to "post{num_post}.jpg"
caption = request.POST['caption']
num_post = Post.objects.count()+1
new_post = Post.objects.create(image=image, caption=caption, num_post=num_post)
new_post.save()
#create pdf
buffer = io.BytesIO()
#get the image
#img_file = Image.open(f'{os.getcwd()}/{post.image.url}').convert('RGB')
#img_file = f'media/post_images/postimg{num_post}'
#x_start = 0
#y_start = 0
#saving it on the server
folder_path = f"media/post{num_post}.pdf"
folder_name = os.path.basename(folder_path)
p = canvas.Canvas(folder_name)
#p.drawImage(img_file, x_start, y_start, width=120, preserveAspectRatio=True, mask='auto')
p.drawString(200, 300, new_post.caption)
p.drawString(200, 100, str(new_post.created_at))
p.drawString(200, 600, str(new_post.id))
#p.drawText(new_post.caption)
#p.drawImage(new_post.image)
p.showPage()
p.save()
buffer.seek(0)
return redirect('/'), folder_path
else:
return redirect('/')
so in the end i should be able to put the image in the pdf by using:
img_file = f'media/post_images/postimg{num_post}'
x_start = 0
y_start = 0
p.drawImage(img_file, x_start, y_start, width=120, preserveAspectRatio=True, mask='auto')
I was already able to get the images into the pdf by using the existing filename but since the pdf should be automatically generated for each post, the image name needs to be variable, i think.
Right now, it is not working. The image is not renamed, but there is also no error display. so the function seems not to reach the image? How do I make it work?
Thank you for any suggestions. :) im new to django... any explanation helps.
Lets start with the model field:
class Post(models.Model):
...
image = models.ImageField(upload_to='post_images')
...
It is not showing any errors because you are uploading files to 'post_images' folder and not calling a function with such name. And that is also why your files are not being renamed.
To call the rename function, just remove the single quote:
image = models.ImageField(upload_to=post_image)
Although, it is not going to work because of this line:
def post_images(instance, filename):
...
filename = "%s_%s.%s" % (instance.post.num_post, ext)
...
Where there are two problems. First, instance is a post object instance, you are trying to access it in the wrong way. And second when trying to format three strings with two parameters. That being said:
def post_images(instance, filename):
ext = filename.split('.')[-1]
filename = 'post{}.{}'.format(instance.num_post, ext)
return os.path.join('uploads', filename)
Lets also implement a #property on model Post so we can access its image filename with ease:
class Post(models.Model):
...
#property
def filename(self):
return os.path.basename(self.image.name).split('.')[0]
Now, related to the view, it is always a good practice to work with django forms (model form), it also helps writing less code while doing more (like validating data):
forms.py
from django import forms
from .models import Post
class UploadForm(forms.ModelForm):
class Meta:
model = Post
fields = ['image', 'caption']
views.py
from django.shortcuts import render, redirect
from .forms import UploadForm
from .models import Post
import os
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import A4
def upload(request):
if request.method == 'POST':
form = UploadForm(request.POST, request.FILES)
if form.is_valid():
form.cleaned_data['num_post'] = Post.objects.count() + 1
post = Post.objects.create(**form.cleaned_data)
p = canvas.Canvas(os.getcwd() + f'/uploads/converted/{post.filename}.pdf')
p.drawString(200, 300, post.caption)
p.drawString(200, 100, str(post.created_at))
p.drawString(200, 600, str(post.id))
p.showPage()
p.drawImage(post.image.name, 0,0, width=A4[0], height=A4[1],mask='auto')
p.showPage()
p.save()
return redirect('post:upload')
else:
form = UploadForm()
return render(request, 'upload.html', {'form': form})
In this view, after checking that the data is valid we then update the valid data dictionary and create the object. Furthermore, since we are using .create() it is not necessary to save the object afterwards.
After this first process we create ReportLab PDF object, with two pages, the first one containing the string related data (as in your original function). And, the second one where we draw an image fitting the whole page by using from reportlab.lib.pagesizes import A4 size properties. You can find all this information at the userguide documentation.
upload.html
{% block content %}
<form action="{% url 'post:upload' %}" enctype="multipart/form-data" method="post">
{% csrf_token %}
{{form.as_p}}
<button type="submit">Create</button>
</form>
{% endblock content %}
urls.py
app_name = 'post'
urlpatterns = [
path('upload/', views.upload, name='upload'),
]
Currently, my application is to select the stock data, then analyzing it by using another python script and output the result(in JSON format).
Now I would like to add a button to output the result(w_df_split) to CSV, then when the user clicks the button and download the csv file.
But I am stuck in how to return the output CSV function in this view.
views.py:
def efficient_frontier_select(request):
user_holding = Position.objects.filter(created_by = request.user)
selected_stock = None
w_df_split = None
if request.method == 'POST':
selected_stock = request.POST.getlist('stock_symbol')
ta, tb, tc = ef.combination_frontier(selected_stock)
fy_df, fx_df, w_df, fxfy_df, ef_df = ef.transform_frontier_todf(ta,tb,tc, selected_stock)
w_df_split = json.loads(ef.json_format_split(w_df))
context = {
'w_df_split' : w_df_split,
}
return render(request, 'portfolio/efficient_frontier.html', context)
Asumming df is a dataframe, you you could use pandas's df.to_csv(). Like that: csv_data = w_df.to_csv(). You could do the same to json with w_df.to_json()
Just an update!
Django view design - export CSV from user-generated content
This works by setting the hidden input field to store the JSON data.
I'm currently working through the O'Reilly book, Programming Python. Below is code that reads a shelve and creates a web interface allowing you to access those values from the shelf. You can fetch and update the values
'''
Implement a web-based interface for viewing and updating class instances
stored in a shelve; the shelve lives on server (same machine if localhost)
'''
import cgi, sys, os
import shelve, html
shelvename = 'class-shelve'
fieldnames = ('name', 'age', 'job', 'pay')
form = cgi.FieldStorage()
print('Content-type: text/html')
sys.path.insert(0, os.getcwd())
# main html template
replyhtml = """
<html>
<title>People Input Form</title>
<body>
<form method=POST action=peoplecgi.py>
<table>
<tr><th>key<td><input type=text name=key value="%(key)">
$ROWS$
</table>
<p>
<input type=submit value="Fetch", name=action>
<input type=submit value="Update", name=action>
</form>
</body></html>
"""
# insert html for data rows at $ROWS$
rowhtml = '<tr><th>%s<td><input type=text name=%s value="%%(%s)s">\n'
rowshtml = ""
for fieldname in fieldnames:
rowshtml += (rowhtml % ((fieldname,)*3))
replyhtml = replyhtml.replace('$ROWS$', rowshtml)
def htmlize(adict):
new = adict.copy()
for field in fieldnames:
value = new[field]
new[field] = html.escape(repr(value))
return new
def fetchRecord(db, form):
try:
key = form['key'].value
record = db[key]
fields = record.__dict__
fields['key'] = key
except:
fields = dict.fromkeys(fieldnames, '?')
fields['key'] = 'Missing or invalid key!'
return fields
def updateRecord(db, form):
if not 'key' in form:
fields = dict.fromkeys(fieldnames, '?')
fields['key'] = 'Missing key input!'
else:
key = form['key'].value
if key in db:
record = db[key]
else:
from person_start import Person
record = Person(name='?', age='?')
for field in fieldnames:
setattr(record, field, eval(form[field].value))
db[key] = record
fields = record.__dict__
fields['key'] = key
return fields
db = shelve.open(shelvename)
action = form['action'].value if 'action' in form else None
if action == 'Fetch':
fields = fetchRecord(db, form)
elif action == 'Update':
fields = updateRecord(db, form)
else:
fields = dict.fromkeys(fieldnames, '?')
fields['key'] = 'Missing or invalid action!'
db.close()
print(replyhtml % htmlize(fields))
However, for some reason, printing is continually failing. I've tried many times to remove the "" the error is stating, but to no avail.
Does anyone see why this is failing to print the form?
After checking the complete code , I believe the issue is in the replyhtml , in line -
<tr><th>key<td><input type=text name=key value="%(key)">
The issue is in the format - "%(key)" . You need to specify the type of the element like s or d etc , I believe you may need s (for string). Example -
<tr><th>key<td><input type=text name=key value="%(key)s">
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)