Adding uploaded text file to textbox field - Django - python

I am pretty new to Django and still learning, but I am having a hard time trying to figure out how to let a user upload a .txt file but instead have the uploaded .txt file overwrite in the textfield itself.
Example: When uploaded https://imgur.com/a/jdCjlVS
I haven't been able to find understandable resources, but this is all I have at the moment:
forms.py
class NewInput(forms.Form):
text = forms.CharField(label='Input', max_length=1000, required=False)
file = forms.FileField(required=False)
models.py
class Collection(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="collection", null=True)
text = models.TextField(max_length=1000, default='')
create.html
{% extends 'main/base.html' %}
{% load crispy_forms_tags %}
{% block title %}
New Input
{% endblock %}
{% block content %}
<center>
<h3>Create a New Input:</h3>
<p class="text-primary"></p>
<form method = "post" action = "/create/" class="form-group" enctype="multipart/form-data">
{% csrf_token %}
{{form|crispy}}
<div class="input-group mb-3">
<div class="col text-center">
<button type="submit" name="save" class="btn btn-success">Create</button>
</div>
</div>
</form>
</center>
{% endblock %}
views.py
def create(response):
if response.user.is_authenticated:
username = response.user.username
if response.method == "POST":
form = NewInput(response.POST)
if form.is_valid():
n = form.cleaned_data["text"]
t = Collection(text=n)
t.save()
response.user.collection.add(t)
return HttpResponseRedirect("/collections/%s" % username)
else:
form = NewInput()
return render(response, "main/create.html", {"form": form})
else:
return HttpResponseRedirect("/login")
I tried adding a separate class as a form field but I was unable to figure out how to make it overwrite the text area instead.

Related

Nested for loop in html using django to display information from 2 different models

I have a model called Section and a model called SectionInfo. Section has one field and that's name. A user will create a section by giving it a name. SectionInfo has a foreign key section_name which links it to the Section model. I have a few other fields inside SectionInfo such as things like detail, date_created, etc. What I am trying to accomplish here is using a for loop to display section names that have already been created inside or above some cards that I have set up in an html template. Then I want to use a nested loop to gather the data that is tied to that section name which is what the user inputs in for the SectionInfo model. I am able to display the section names correctly, but the issue im having is in the loop inside that loop. The same detail link is being displayed in every section that was made. Information should only be displayed in the chosen section for which it was made.
Here is a bit of code to help you understand what I am trying to accomplish.
Template file:
{% extends "base.html" %}
{% load bootstrap5 %}
{% load crispy_forms_tags %}
{% load static %}
{% block content %}
{% for i in object %}
{{ i.name}}
<div class="row">
<div class="col-sm-4">
<div class="card">
<div class="card-body">
{% for ii in object_2 %}
Details
{% endfor %}
</div>
</div>
</div>
</div>
{% endfor %}
{% endblock content %}
Here is what I am getting displayed
whats being displayed
Here is the view that's being used
def section_info_detail(request, pk):
object = get_object_or_404(Section, id=pk)
object_2 = get_object_or_404(SectionInfo, id=pk)
context = {
'object': object,
'object_2':object_2,
}
return render(request, 'manufacturing/section_info_detail.html', context)
Models.py:
class Section(models.Model):
name = models.CharField(max_length=30)
def __str__(self):
return self.name
class SectionInfo(models.Model):
section_name = models.ForeignKey(Section, on_delete=models.CASCADE)
detail = models.CharField(max_length=50)
text = models.TextField(max_length=2000)
date_created = models.DateField('Date created', auto_now_add=True)
date_updated = models.DateField('Date updated', auto_now=True)
Forms.py:
class SectionNameForm(forms.ModelForm):
class Meta:
model = Section
fields = [
'name',
]
class SectionInfoForm(forms.ModelForm):
class Meta:
model = SectionInfo
fields = [
'section_name',
'detail',
'text',
]
If any other information is needed, do tell.
<div class="row">
{% for object in object_list %}
<div class="col-sm-4">
<div class="card">
<div class="card-header">
<h1><strong>{{ object.name }}</strong></h1>
<hr>
</div>
<div class="card-body">
<div class="row">
{% for info in object.section_infos.all %}
<ul id="list">
<li>{{ info.date_created }}</li> |
<li>{{ info.detail|truncatechars:20 }}</li>
<hr>
</ul>
{% endfor %}
</div>
</div>
</div>
</div>
{% endfor %}
</div>
This did it for me. So basically what my problem was I was not drilling down far enough to get the data that I needed to be displayed from the template. Also I had changed some things up in my models and had created a manyTomany and through field

Simple-file-upload addon returns no file on submit - django

I've been trying to add a heroku addon on my deploy. I have tried configuring the simple-file-upload but it still doesn't give the desired result.
It returns (Hidden field File) This field is required.
Here are my attempts.
views.py
class AddDownloadView(LoginRequiredMixin,CreateView):
model = Download
form_class = AddDownloadsForm
template_name = 'add_file.html'
success_url = reverse_lazy('all_downloads')
models.py
class Download(models.Model):
File = models.FileField(upload_to='files')
File_Name = models.CharField(max_length=200)
class Meta:
ordering = ('-pk','File_Name')
def get_absolute_url(self):
return reverse('home')
def __str__(self):
return self.File_Name
forms.py
class AddDownloadsForm(forms.ModelForm):
class Meta:
model = Download
fields = ("File",'File_Name')
widgets = {
"File":forms.FileInput(attrs={"class":'simple-file-upload','type':'hidden'}),
"File_Name":forms.TextInput(attrs={"class":"form-control"}),}
add_file.html < form for adding the file uploads >
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ form.media }}
{{ form.as_p }}
<button class="btn btn-outline-primary">Add</button>
</form>
form for displaying the uploads
<div style="min-height:350px;columns:200px 2;overflow-y:scroll;" class="container alert alert-
default" role="alert">
{% for item in file %}
{% if item.File_Name %}
--> {{ item.File_Name }}<br>
{% if user.is_authenticated %}
==> Edit ||
Delete<hr>
{% endif %}
{% endif %}
{% empty %}<br><br>
<h6><i>No files to download yet</i></h6><br><br>
{% endfor %}
</div>
I've struglled through same problems but have not come up with a solution, please help.

Django form_valid() in CreateView not executing when trying to create a new dish object

In this code, the form_valid() function inside DishCreateView is not being executed when I try to create a new dish ie I am unable to create a new dish, when I click on create button page url not changes and remains the same. For detecting this I have put print statement inside form_valid() but this is not executed. Please help me out. Thanks
models.py
class Dish(models.Model):
name = models.CharField(max_length=100)
image = models.ImageField(upload_to='dishes_pics')
description = models.TextField()
ingredients = models.TextField(blank=True)
required_time_to_cook = models.CharField(max_length=100)
favourite = models.ManyToManyField(User, related_name='favourite', blank=True)
cuisine_id = models.ForeignKey(Cuisine, on_delete=models.CASCADE)
user_id = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('dish-detail', kwargs={'pk': self.pk})
def save(self):
super().save()
img = Image.open(self.image.path)
if img.height > 300 or img.width > 300:
output_size = (300,300)
img.thumbnail(output_size)
img.save(self.image.path)
views.py
class DishCreateView(LoginRequiredMixin,CreateView):
model = Dish
fields = ['name', 'image', 'description','required_time_to_cook','cuisine_id','user_id']
def form_valid(self, form):
form.instance.user_id = self.request.user
print('self==========form==create=====',form)
return super().form_valid(form)
form_template.html
{% extends "cookbook/base.html"%}
{% load crispy_forms_tags %}
{% block content %}
<div class="content-section">
<form method="POST">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4">
Add Dish
</legend>
{{ form|crispy }}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">Create</button>
</div>
</form>
</div>
{% endblock content %}
dish_detail.html
{% extends 'cookbook/base.html' %}
{% load static %}
{% block content %}
<link rel="stylesheet" type="text/css" href="{% static 'cookbook/dish.css' %}">
<div class="media">
<img class="rounded-circle account-img" src="{{ object.image.url }}">
<div class="media-body">
<h2 class="account-heading">{{ object.name }}</h2>
<p class="text-secondary">{{ object.description }}</p>
<p class="text-secondary">{{ object.required_time_to_cook }}</p>
<p class="text-secondary"> {{object.cuisine_id}}</p>
</div>
</div>
{% endblock content %}
First thing i notice is that the name of the template is called form_template.html. Accourding the docs the createview uses a default suffix value for naming them template '_form' this in combination with you model name. So you should change your template name to:
from : form_template.html
to : dish_form.html
I think your view does not receive the data you post because the naming is not correct and you didn't add an action value to the form. This should not be problem if the naming matches the view.
If this still not fixes your problem step 2 would be to add a
def form_invalid(self, form):
print(form.errors)
to your view and put a print statement in there
this would give you the error back with the problem. so you know where the problem is.

How to customize html of one form field in a form?

I need the user to enter data into a form in my django app. I am currently doing this like so:
forms.py: (using model form)
class BabysittingForm(forms.ModelForm):
class Meta:
model = models.Babysitting
fields = [
'title',
'pay',
'start_date',
'end_date',
'num_children',
'babysitting_address',
'babysitting_day_of_week',
'babysitting_start_time_of_day',
'babysitting_session_length_hours',
'description',
]
Here is my models.py:
class Job(models.Model):
employer = models.ForeignKey(settings.AUTH_USER_MODEL, related_name="jobs")
hired_user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True)
created_at = models.DateTimeField(auto_now_add=True)
start_date = models.DateTimeField(default=datetime.now())
end_date = models.DateTimeField(default=datetime.now())
location = models.CharField(default="None", max_length=40)
title = models.CharField(max_length=30)
description = models.TextField()
category = models.CharField(max_length=3, choices=JOB_CATEGORY_CHOICES)
pay = models.FloatField()
hourly_pay = models.BooleanField(default=True)
complete = models.BooleanField(default=False)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('jobs:detail', kwargs={
'job_pk': self.id
}
)
class Babysitting(Job):
num_children = models.PositiveSmallIntegerField()
babysitting_address = models.CharField(default="None", max_length=40)
babysitting_day_of_week = models.CharField(max_length=2, choices=DAYS_OF_WEEK_CHOICES)
babysitting_start_time_of_day = models.CharField(max_length=8)
babysitting_session_length_hours = models.FloatField()
Here is my layout:
{% extends 'layout.html' %}
{% load bootstrap3 %}
{% block title %}{{ form.instance.title|default:"New Job" }}{% endblock %}
{% block content %}
<div class="container">
<h1>{{ form.instance.title|default:"New Job" }}</h1>
<form action="" method="POST">
{% bootstrap_form form %}
{% csrf_token %}
<input type="submit" value="Post Job" class="btn btn-default"/>
</form>
</div>
{% endblock %}
I need to change the appearance of the pay form field to this:
I know how to style it this way but I don't know how to change the form template to do this.
How do you customize a single form's appearance in django?
Sorry I should have been more specific, I want to replace one of the form fields with this html (bootstrap):
<div class="row">
<div class="col-lg-6">
<div class="input-group">
<div class="input-group-btn">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Action <span class="caret"></span></button>
<ul class="dropdown-menu">
<li>Action</li>
<li>Another action</li>
<li>Something else here</li>
<li role="separator" class="divider"></li>
<li>Separated link</li>
</ul>
</div><!-- /btn-group -->
<input type="text" class="form-control" aria-label="...">
</div><!-- /input-group -->
</div><!-- /.col-lg-6 -->
</div>
Thank you.
Maybe you could use django-widget-tweaks
If you need to customize your field class, you can render one by one and to add a class to each field
ie, in your template
{% extends 'layout.html' %}
{% load bootstrap3 %}
{% load widget_tweaks %}
{% block title %}{{ form.instance.title|default:"New Job" }}{% endblock %}
{% block content %}
<div class="container">
<h1>{{ form.instance.title|default:"New Job" }}</h1>
<form action="" method="POST">
{% csrf_token %}
<!-- ie field 1 -->
{% render_field form.field1 class+="form-control other_class" %}
<input type="submit" value="Post Job" class="btn btn-default"/>
</form>
</div>
{% endblock %}
Documentation about django-widget-tweaks here
If you want to style your form with custom CSS classes, ids etc you should override the widget class attribute of the Meta class of your form. More on this in overriding the default fields.
Example:
# forms.py
from django.forms import ModelForm
from .models import Babysitting
class BabysittingForm(forms.ModelForm):
class Meta:
model = Babysitting
fields = [...] # as is
widgets = {
# add here any css classes or attributes per field (on the specific widget)
'title': forms.TextInput(attrs={'class': 'custom-class', 'id': 'custom-id',}),
'pay': forms.NumberInput(attrs={'class': 'another-class', 'id': 'another-id',}),
}

Want to display an image

I am having a slight problem. I want a django app that can upload and display an image. Currently, it can upload the image but I cannnot display that image.
So for example, {{comment.photo}} will print out the path C:/Users/AQUIL/Desktop/myproject/images/P1000992.JPG. But I want to see that image on the screen. Not the path. How do I print out the image to the screen?
Here is some information that may help.
models.py
class Comment(models.Model):
name = models.CharField(max_length = 40)
datetime = models.DateTimeField(default=datetime.now)
photo = models.ImageField(upload_to='C:/Users/AQUIL/Desktop/myproject/media/images', blank=True, null=True)
note = models.TextField()
def __unicode__(self):
return unicode(self.name)
views.py
def home(request):
comments = None
try:
comments = Comment.objects.order_by('-datetime')
except:
return HttpResponseNotFound()
return render_to_response('home.html', {'comments':comments}, context_instance=RequestContext(request))
def add_notes(request):
comments = Comment.objects.all()
if request.method == 'POST':
form = CommentForm(request.POST or None, request.FILES)
if form.is_valid():
comments.datetime = datetime.now()
form.save(True)
return HttpResponseRedirect(reverse(home))
else:
form = CommentForm()
return render_to_response('form.html', {'form':form,'comments':comments}, context_instance = RequestContext(request))
home.html
{% extends "base.html" %}
{% block content %}
<H2>List of Comments</H2>
<div style="overflow:auto;padding: 10px; border:1px solid black; height:150px; width:700px;">
{% for comment in comments %}
{{comment.photo}} <br/>
<b>Posted by: {{ comment.name }} Date: {{ comment.datetime.date }} Time: {{comment.datetime.time}}</b><br/>
<div style="font-size:125%">{{ comment.note }}</div><br/>
{% endfor %}
</div>
{% endblock %}
form.html
{% extends "base.html" %}
{% block content %}
<h3>Add Notes</h3>
<form enctype="multipart/form-data" action="" method="POST">
{% csrf_token %}
<table>
{{form.as_table}}
<br/>
</table>
<input type="submit" value="Save" STYLE="background-color:#E8E8E8; color:#181818 "/>
</form>
{% endblock %}
{% if comment.photo %} <img src="{{ comment.photo.url }}" alt="Photo" /> {% endif %}
See Geoffrey's comment for how to upload the image correctly.
The upload parameter of ImageField must be a local path, so replace:
photo = models.ImageField(upload_to='C:/Users/AQUIL/Desktop/myproject/media/images', blank=True, null=True)
by:
photo = models.ImageField(upload_to='images', blank=True, null=True)
Then set the MEDIA_ROOT in settings.py as:
MEDIA_ROOT = 'C:/Users/AQUIL/Desktop/myproject/media/'
Finally your image 'myImage.png' will be accessible at:
C:/Users/AQUIL/Desktop/myproject/media/images/myImage.png
And this tag should load the image:
<img src="/media/images/myImage.png" alt=""/>
depends of your MEDIA_URL in settings.py which should be:
MEDIA_URL = '/media/'
Rather then {{comment.photo}}
use {{comment.photo.url}}
see sample in the docs

Categories