I have this function that takes a QuerySet and renders a CSV. I would like to write a view that renders a template with options to download different CSV files (Basically for anything defined in models.py)
# Exports CSV file using a QuerySet
def export(qs, fields=None, file_name='data'):
model = qs.model
response = HttpResponse(mimetype='text/csv')
response['Content-Disposition'] = 'attachment; filename={0}-{1}.csv'.format(file_name, str(datetime.date.today()))
writer = csv.writer(response)
# Write headers to CSV file
if fields:
headers = fields
else:
headers = []
for field in model._meta.fields:
headers.append(field.name)
writer.writerow(headers)
# Write data to CSV file
for obj in qs:
row = []
for field in headers:
if field in headers:
val = getattr(obj, field)
if callable(val):
val = val()
row.append(val)
writer.writerow(row)
# Return CSV file to browser as download
return response
Currently I am writing a NON-reusable view:
def csv_of_surveys(request):
r = export(Survey.objects.all(), file_name='surveys')
return r
What can I do? My only idea was to send a code over and write a switch statement, so
{% url "csv_of" 0 %}
{% url "csv_of" 1 %}
{% url "csv_of" 2 %}
{% url "csv_of" 3 %}
Where 0, 1, 2 and 3 would correspond to downloading different things.
The new view would look something like:
def csv_of(request, code):
if code == 0:
r = export(Survey.objects.all(), file_name='surveys')
return r
elif code == 1:
r = export(User.objects.all(), file_name='teachers')
return r
elif code == 2:
r = export(Student.objects.all(), file_name='students')
return r
# ...
else:
return HttpResponseRedirect('/')
Is there a better way?
Create a dictionary that maps the given code to the associated object, then reduce all the if statements you have into one if. For the file name, it looks like you're doing the same thing each time, which is pluralizing and lowercasing it, in which case you should set it in model._meta.verbose_name_plural, then access that when you need it:
file_codes = {0:Survey,1:User...}
def csv_of(request, code):
if int(code) in file_codes.keys():
obj = file_codes[int(code)]
return export(obj.objects.all(), file_name = obj._meta.verbose_name_plural.title())
else:
return HttpResponseRedirect('/')
Related
i'm trying to create and API for some validation:
I want to have a option to upload one CSV.
I want to pass that CSV through some validations, to modify the original CSV (to add 2 new columns)
I want to have a posibility to download the modified CSV (with my 2 new columns)
I implemented the first part, i created the validation, but after i download, i've got the same output (file wasn't modified)
Could anyone help me with this part pls?
This is my code for my view:
def upload(request):
context = {}
if request.method == 'POST':
promo2 = request.FILES['document']
if request.method == 'GET':
promo2 = promo2[~promo2['COMP_ARTICLE_PROMO_TYPE'].isna()]
for index, row in promo2.iterrows():
promo2 = pd.read_csv(promo2, sep=';')
if (row['COMP_ARTICLE_PROMO_NAME'] == '-20%') or (row['COMP_ARTICLE_PROMO_NAME'] == '20.0% korting'):
if 0.95 < round(row['COMP_ART_PRICE'] * 0.80, 2) / row['COMP_ARTICLE_PROMO_PRICE_PER_UNIT'] < 1.05:
promo2.loc[index, 'VALIDATE_ARTICLE_PROMO_PRICE_PER_UNIT'] = 'GOOD'
else:
promo2.loc[index, 'VALIDATE_ARTICLE_PROMO_PRICE_PER_UNIT'] = 'WRONG'
if (row['COMP_ARTICLE_PROMO_NAME'] == '-20%') or (row['COMP_ARTICLE_PROMO_NAME'] == '20.0% korting'):
if row['COMP_ARTICLE_PROMO_PERCENT'] == 20:
promo2.loc[index, 'VALIDATE_ARTICLE_PROMO_PERCENT'] = 'GOOD'
else:
promo2.loc[index, 'VALIDATE_ARTICLE_PROMO_PERCENT'] = 'WRONG'
#fs = FileSystemStorage()
#name = fs.save(promo2.name, promo2)
#context['url'] = fs.url(name)
#promo2.to_excel(response, engine='xlsxwriter', index=False)
fs = FileSystemStorage()
name = fs.save(promo2.name, promo2)
context['url'] = fs.url(name)
return render(request, 'upload.html', context)
Here is my front end part and here i want to have another button to download the CSV file modified (after he will go through my validations)
https://i.stack.imgur.com/mk5x1.png
So I have a Django App, where a CSV-File can be uploaded. My CSV-File has 9 columns that can be divided into two "datasets" where the first 5 columns need to be handled as one information and the other 4 need to be handled as another information. I cannot put the first 5 in one cell and the other ones in another cell. I would like to check whether or not the first dataset exists and if it does, process it. The same applies to the other dataset. And if both datasets do not exist already it should just update the Database with get_or_create.
Here is my views.py idea
def import_csv(request):
if request.method == "POST":
with open('C:/Users/admin/Desktop/djangoexcel/b.csv') as file:
reader = csv.reader(file)
for row in reader:
var = CSV_File4.objects.filter(
attr1=row[0], attr2=row[1], attr3=row[2], attr4=row[3], attr5=row[4],
)
if var.exists():
TemplateResponse(request, "documents/replace_entry.html", {'var' : var})
else:
for row in reader:
switch = CSV_File4.objects.filter(
attr6=row[5], attr7=row[6], attr8=row[7], attr9=row[8]
)
if var2.exists():
TemplateResponse(request, "documents/replace_entry.html", {'var2' : var2})
else:
for row in reader:
_, p = CSV_File4.objects.get_or_create(
attr1=row[0], attr2=row[1], attr3=row[2], attr4=row[3], attr5=row[4],
attr6=row[5], attr7=row[6], attr8=row[7], attr9=row[8]
)
return redirect('documents:index')
form = UploadFileForm()
return render(
request, "documents/csv_upload.html", {"form": form}
)
It should look something like this. How can I make this work. It was just an idea with filter() and exists() but is there a Python way to do something like this? Any help would be appreciated.
Currently, you are trying to recursively iterate through reader three times. That's not possible, because it is an Iterator, not a list. Anyway, you only need to do it once and then work on that particular line, before skipping to the next.
def import_csv(request):
if request.method == "POST":
with open('C:/Users/admin/Desktop/djangoexcel/b.csv') as file:
reader = csv.reader(file)
for row in reader:
ds1 = CSV_File4.objects.filter(
attr1=row[0], attr2=row[1], attr3=row[2], attr4=row[3], attr5=row[4],
).exists()
ds2 = CSV_File4.objects.filter(
attr6=row[5], attr7=row[6], attr8=row[7], attr9=row[8]
).exists()
if ds1:
pass # Process first dataset
if ds2:
pass # Process second dataset
if not (ds1 and ds2):
_, p = CSV_File4.objects.get_or_create(
attr1=row[0], attr2=row[1], attr3=row[2], attr4=row[3], attr5=row[4],
attr6=row[5], attr7=row[6], attr8=row[7], attr9=row[8]
)
return redirect('documents:index')
return render(
request, "documents/csv_upload.html", {"form": UploadFileForm()}
)
I've already written a script that parses JSON data from a particular url and stores them into a list. After that I'm able to pass that as an argument to be displayed in my template.
My end goal is to display a table on the template from this JSON data (of which I have currently included only one parameter), for which I believe I need to pass that list into a Django Model.
def index(request):
is_cached = ('raw_json' in request.session)
print(is_cached)
if not is_cached:
# g = {'starttime': '2014-01-01', 'endtime': '2014-01-02', 'minmagnitude': '5'}
g=''
url1 = ul.urlencode(g)
# print(url1)
main_api = 'https://earthquake.usgs.gov/fdsnws/event/1/query?format=geojson&'
final_url = main_api + url1
# print(final_url)
raw_json = requests.get(final_url).json()
string_json = json.dumps(raw_json)
# print(raw_json)
with open('test.txt', 'w') as file:
file.write(string_json)
count = raw_json['metadata']['count']
print('Count: ' + str(count))
maglist = []
placelist = []
for cou in range(0, count):
mag = (raw_json['features'][cou]['properties']['mag'])
maglist.append(mag)
# magdict = dict(list(enumerate(maglist)))
place = (raw_json['features'][cou]['properties']['place'])
placelist.append(place)
# placedict = dict(list(enumerate(placelist)))
# print(placedict)
with open('test2.txt', 'w+') as t1:
for features in raw_json['features']:
coordinates = (features['geometry']['coordinates'])
id = (features['id'])
t1.write("id: %s \n" % (id))
t1.write("coordinates: %s \n" % (coordinates))
# print(singfeature)
for properties, value in features['properties'].items():
t1.write("%s : %s \n" % (properties, value))
# t1.write("\n")
# print (maglist)
args = {'magni': maglist}
print (args)
return render(request, 'earthquake/index.html', args)
The template receives this data with a simple for loop as follows:
{% block content %}
{% for item in magni %}
<p>{{ item }}</p>
{% endfor %}
{% endblock %}
To which the result shows up as follows:
As mentioned previously, I need to display a filterable/sortable table with this parameter (along with other parameters too), so that the end-user may view the data as needed.
I'm quite new to Django.
I'm using the Django Python framework to retrieve data from a CSV.
The code works, but I am trying to make the code reusable and I haven't been able to accomplish that because I can't find a way to pass the url to the csv from an instance.
The code of the view is as follows:
class ThreeLinerCSV(APIView):
authentication_classes = []
permission_classes = []
def get(self, request, format=None):
with open('csvpathhere.csv', newline='') as csvfile:
reader = csv.DictReader(csvfile)
csv1 = list(reader)
header = list(csv1[0].keys())
#Headers
headerData0 = header[0]
headerDataTxt0 = str(headerData0)
headerData1 = header[1]
headerDataTxt1 = str(headerData1)
headerData2 = header[2]
headerDataTxt2 = str(headerData2)
headerData3 = header[3]
headerDataTxt3 = str(headerData3)
#Data arrays
Date = reversed([i[headerDataTxt0] for i in csv1])
DataValue1 = reversed([i[headerDataTxt1] for i in csv1])
DataValue2 = reversed([i[headerDataTxt2] for i in csv1])
DataValue3 = reversed([i[headerDataTxt3] for i in csv1])
#Data to send to views
data = {
"labels": Date,
"dataAxis1": DataValue1,
"dataAxis2": DataValue2,
"dataAxis3": DataValue3,
"headerData1": headerData1,
"headerData2": headerData2,
"headerData3": headerData3,
}
return Response(data)
#I call the class here
OISLIBOR = ThreeLinerCSV()
Then, the urls.py has this:
url(r'^api/OISLIBOR/data/$', OISLIBOR.as_view()),
I need to find a way to get the "csvpathhere.csv" out of the class and be able to input it from the instance. Any idea of how to do that?
If I understand your questions correctly, you could pass the target CSV name as a GET query string parameter.
You would have to change one line in your view:
with open(request.GET.get('target_name'), newline='') as csvfile:
And the call your endpoint like this
http: ... api/OISLIBOR/data/?target_name=here.goes.the.target.url
Suppose there is list a=[1,2,3,4] in jinja2
and i want to access only 3rd index of list .In other languages we write a[2]
but it shows error in jinja2.
def dashboard(request):
user = request.user
staff_detail = []
staffs = models.Staff.objects.all()
rec_total = models.Recordings.objects.all().count()
rec_enquiry = models.Recordings.objects.filter(type=1).count()
rec_complaint = models.Recordings.objects.filter(type=2).count()
for staff in staffs:
st = dict()
st['staff_detail'] = staff
st['total_recordings'] = staff.recordings_set.all().count()
st['enquiry'] = staff.recordings_set.filter(type=1).count()
st['complaint'] = staff.recordings_set.filter(type=2).count()
staff_detail.append(st)
return render(request, 'hackathon/index.html', {
'staff_detail': staff_detail,
'rec_total': rec_total,
'rec_enquiry': rec_enquiry,
'rec_complaint': rec_complaint,
'staff_first': staff_detail[0],
})
In html file want only the 1st element of staff_detail currently I write
{{staff_detail[0].staff_detail.name}}
but it is showing error
I can only access them using for loop
It should be written as {{staff_detail.0.staff_detail.name}}