Storing data from csv file into model in django? - python

I am submitting csv file from form using POST method and want to save its content into model
forms.py
class SaveCsvForm(forms.Form):
upload_file = forms.FileField(label="Uplaod CSV File", help_text="Uploa file in CSV format")
Views.py
def save_csv(request):
if request.method == 'POST':
form = SaveCsvForm(request.POST, request.FILES)
if form.is_valid():
print("All ok I am check One")
# instance = CsvStorage(file_field=request.FILES['file'])
file = request.FILES['upload_file'].read()
print(file)
csv_to_db(file)
ack = {
'status': 'Success',
'message': 'Data is successfuly submited into database'
}
return JsonResponse(ack)
else:
ack = {
'status': 'Error',
'message': 'Server Returned '+form.errors.as_json(),
}
return JsonResponse(ack)
else:
form = SaveCsvForm()
return render(request, 'upload_csv.html', {'form': form})
file handler method for storing data in Model
def csv_to_db(filename):
with open(filename, 'r') as file:
''' reading csv file in dictionary format '''
reader = csv.DictReader(file)
for row in reader:
instance = CsvStorage(username=row['username'],
first_name=row['user'],
city=row['city'],
mobile=row['mobile']
)
instance.save()
if instance:
return({'status': 'successfuly'})
else:
return({'status': 'error'})
Note:
1.The main problem is while reading the file
2.I don't want to store file in models fileField

I ended up using FileSystemStorage class in Django as described in docs.

Related

Check if a file exist in Django

I have created a newclaim.html and editclaims.html. newclaims.html allows me to upload a file while editclaims.html allows me to retrieve the file.
Currently, I am able to retrieve the uploaded file but I want to do an if-else. I want to do an if-else that will delete the old file if a new file is uploaded
This is my views.py
**# Submit a new Claim**
def newclaim(request):
context = initialize_context(request)
user = context['user']
if request.method == 'POST':
receipt = request.FILES['receipt_field']
ins = SaveClaimForm(receipt=receipt)
ins.save()
print("The Data has been written")
return render(request, 'Login/newclaim.html/', {'user':user})
# Edit a claim
def editclaims(request,id):
context = initialize_context(request)
user = context['user']
# get original object
claims = SaveClaimForm.objects.get(id=id)
if request.method == 'POST':
# update original object
claims.receipt = request.FILES.get('receipt')
# save it with original `ID`
claims.save()
return render(request, "Login/editclaims.html", {'claims':claims, 'user':user})
You can check if the old file exist in your file path and delete it. May refer to the code below and modify as per your need :
def editclaims(request,id):
context = initialize_context(request)
user = context['user']
# get original object
claims = SaveClaimForm.objects.get(id=id)
if request.method == 'POST':
# get the old file name:
old_file = claims.receipt
# update original object
claims.receipt = request.FILES.get('receipt')
# save it with original `ID`
claims.save()
#Delete the old file from os if it exist
#Do not forget to import os
#FILE_PATH = path to your file directory
if os.path.isfile(FILE_PATH+old_file):
os.remove(FILE_PATH+old_file)
return render(request, "Login/editclaims.html", {'claims':claims, 'user':user})

Read a csv file and fill in database with it's data in django application

in my Django application, i created a form which permit user to upload csv file.
What i want is when user upload the csv file, the contained data is read and database is filled in with them.
It works but not correctly. data are saved as tuples.
Here's my code
forms.py
class SupplierCSVForm(forms.ModelForm):
class Meta:
model = SuplierCsv
fields = '__all__'
exclude = ('slug',)
views.py
#login_required
def l_supplier(request):
suppliers_list = Supplier.objects.all()
paginator = Paginator(suppliers_list, 3, 2)
page = request.GET.get('page')
suppliers = paginator.get_page(page)
# Supplier csv form
if request.method == 'POST':
form = SupplierCSVForm(request.POST, request.FILES)
if form.is_valid():
uploaded_file = request.FILES['csvfile']
with open('f.csv', 'wb') as destination:
for chunk in uploaded_file.chunks():
destination.write(chunk)
destination.close()
#csvfile = io.TextIOWrapper(open('f.csv', 'rb'))
with open('f.csv', 'r') as the_source:
source_reader = csv.reader(sthe_source)
next(source_reader)
for Name, Email, Contact, City, Website, Activity, Cc, slug in source_reader:
new_supplier = Supplier()
new_supplier.name=Name,
new_supplier.email=Email,
new_supplier.contact=Contact,
new_supplier.city=City,
new_supplier.website=Website,
new_supplier.activity=Activity,
new_supplier.cc=Cc,
new_supplier.slug=slug,
new_supplier.save()
return redirect('good:l_good')
else:
form = SupplierCSVForm()
context = {
'suppliers': suppliers,
'form': form,
}
return render(request, 'supplier/l_supplier.html', context)
Remove the commas where you are assigning the new_supplier objects. Python converts your string objects into tuples if there are any trailing commas.
You have unnecessary commas at the end of your lines:
new_supplier.name=Name,
should be
new_supplier.name=Name
Python thinks that you are creating a tuple
i.e. x, == (x,)

Django Create and output txt file from view

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'])

clean() method causes files to lose data using POST form

I have set up a form and view to upload multiple *.gpx files to my website at once. These files are validated using a clean() method on the form and then once validated passed to a function for processing.
When I upload some invalid files the clean() method catches them and informs the user as expected.
When I upload some valid files the processing function crashes with an error saying the files are empty.
If I comment out the clean() method then the valid files are uploaded fine.
What can be happening to the form during the clean() method than means the files are being blanked?
here is my form:
class UploadGpxForm(forms.Form):
gpx_file = forms.FileField(widget=forms.ClearableFileInput(attrs={'multiple': True}))
here is my view:
class UploadGpxView(FormView):
form_class = UploadGpxForm
template_name = 'dashboard/upload.html' # Replace with your template.
success_url = reverse_lazy('dashboard:index') # Replace with your URL or reverse().
def post(self, request, *args, **kwargs):
form_class = self.get_form_class()
form = self.get_form(form_class)
files = request.FILES.getlist('gpx_file')
if form.is_valid():
for f in files:
SaveGPXtoPostGIS(f)
return self.form_valid(form)
else:
return self.form_invalid(form)
Here is my clean method for the UploadGpxForm:
def clean(self):
file_errors=[]
files = list(self.files.getlist('gpx_file'))
for f in list(files):
#check file has only one full stop in it.
if len(f.name.split('.')) != 2:
file_errors.append(ValidationError(
_('%(file_name)s has not been uploaded:'\
'File type is not supported')
, params = { 'file_name': f.name }
, code = 'file_type')
)
#check file doesn't breach the file size listed in settings
if f.content_type in settings.DASHBOARD_UPLOAD_FILE_TYPES:
if f._size > settings.DASHBOARD_UPLOAD_FILE_MAX_SIZE:
file_errors.append(ValidationError(
_('%(file_name)s has not been uploaded: File too big.'\
'Please keep filesize under %(setting_size)s.'\
'Current filesize %(file_size)s') ,
params = {
'file_name': f.name,
'setting_size': filesizeformat(
settings.DASHBOARD_UPLOAD_FILE_MAX_SIZE),
'file_size': filesizeformat(f._size)
},
code = 'file_size'
)
)
#check it is one of our allowed file types
else:
file_errors.append(ValidationError(
_('%(file_name)s has not been uploaded:'\
'File type is not supported')
, params = { 'file_name' : f.name }
, code = 'file_type'
)
)
#next check the file hasn't been uploaded before
#generate MD5
md5hash = md5()
for chunk in f.chunks():
md5hash.update(chunk)
file_hash = md5hash.hexdigest()
if gpxTrack.objects.filter(file_hash=file_hash).exists():
file_errors.append(ValidationError(
_('%(file_name)s has not been uploaded as a identical file'\
'has already been uploaded previously'),
params = { 'file_name' : f.name },
code = 'file_hash'))
#finally raise errors if there are any
if len(file_errors) > 0:
raise ValidationError(file_errors)
else:
return files
When you read the file content (for calculating md5 hash) you need to move the file object’s position to the beginning (0th byte) using file.seek:
md5hash = md5()
for chunk in f.chunks():
md5hash.update(chunk)
file_hash = md5hash.hexdigest()
f.seek(0) #<-- add this line

How to save uploaded file to disk in Django? - invalid mode: wb+

I would like to know how to save an uploaded file to disk via django.
This is the code
# ...
def spreadsheet_form(request, id = None):
if is_admin_user(request):
instance = get_object_or_404(Spreadsheet, id=id) if id is not None else None
form = SpreadsheetForm(request.POST or None, request.FILES or None, instance=instance)
if form.is_valid():
spreadsheet = form.save(commit=False)
spreadsheet.name = request.POST['name']
spreadsheet.spreadsheet_file = request.FILES['spreadsheet_file']
handle_uploaded_file(request.FILES['spreadsheet_file'])
spreadsheet.save()
return redirect('/spreadsheets/')
return render_to_response("pages/spreadsheet_form.html", {"form": form,"id":id},context_instance=RequestContext(request))
else:
return redirect('/', False)
# ...
def handle_uploaded_file(f):
with open('/tmp/name.txt', 'wb+') as destination:
for chunk in f.chunks():
destination.write(chunk)
Currently it returns the following error:
invalid mode: wb+
Request Method: POST
Request URL: http://0.0.0.0:8000/spreadsheet/new/
Django Version: 1.4.5
Exception Type: IOError
Exception Value:
invalid mode: wb+
If your model Spreadsheet has a FileField, the only thing you need to do to save the file to disk is to pass request.FILES to the form and to save the form:
class Spreadsheet(models.Model):
file = models.FileField(upload_to="directory/relative/to/MEDIA_ROOT/")
other_field = ...
etc.
class SpreadsheetForm(forms.ModelForm):
class Meta:
model = Spreadsheet
fields = ['file', 'other_field', 'etc.']
def spreadsheet_form(request, id=None);
if is_admin_user(request):
instance = get_object_or_404(Spreadsheet, id=id) if id is not None else None
form = SpreadsheetForm(request.POST or None, request.FILES or None, instance=instance)
if form.is_valid():
spreadsheet = form.save()
return redirect('/spreadsheets/')
return render_to_response("pages/spreadsheet_form.html", {"form": form,"id":id},context_instance=RequestContext(request))
else:
return redirect('/', False)

Categories

Resources