Django FileField upload is not working for me - django

I have been scratching my head FileField. Does the FileField require a seperate process?
Although my url gets saved .. but my file doesn't get uploaded ... what am i doing wrong?
This is my models.py ...
class OpLink(models.Model):
user = models.ForeignKey(User)
file = models.FileField(blank=True, null=True, upload_to="uploads")
url = models.URLField(blank=True, null=True)
my forms.py
class OpLinkForm(ModelForm):
class Meta:
model = OpLink
exclude = ('user')
my views.py
oplinkform = oplinkform(request.POST)
oplink = oplinkform.save(commit=False)
oplink.user = user
oplink.save()
and my html to process it.
<div class="span5">
{{ oplinkform.url|add_class:"span4"|attr:"Placeholder:URL for the item" }}
<br><h4>OR</h4><br>
{{ oplinkform.file|add_class:"input-file" }}
<br />
<input class='btn btn-primary btn-large' type="submit" value='Post' name='action'>
</div>

You need to include the files when creating the form
oplinkform = oplinkform(request.POST, request.FILES)
Also make sure that your form has the correct enctype
<form enctype="multipart/form-data"></form>

Related

generic createview and django form only rendering a button in a template

I have encountered a funny challenge, as am building some apps where they want track some expenses and revenues profits ...
I used generic views to create and get details and delete, all work fine with expenses, but I copied the same code and I used it for revenues from expenses you can't imagine this view is rendering a button only yet it has a form, NOTE SAME CODE WORK WELL ON EXPENSES. I even exchanged templates but it kept rendering the former content even after changing the template. it doesn't matter what's in the template the view just renders the same thing even when I remove the form, even when I put pass.
class AccountsRevenueCreate(CreateView):
template_name='dashboard/expense_create.html'
model= AccountsExpense
success_url = reverse_lazy('dashboard:expenses')
form_class=AccountsExpenseForm
and the form
class AccountsRevenueForm(forms.ModelForm):
class Meta:
model = AccountsRevenue
fields = '__all__'
and in the template
<div class="row">
<div class="col-12">
<h5 class="form-title"><span>revenue Update
</span></h5>
</div>
<form method="post", action="{% url
'dashboard:revenue_add' %}">
{% csrf_token %}
{% comment %} {{ form|crispy }} {% endcomment %}
{{ form.as_p }}
<button type="submit" class="btn btn-primary col-12 col-sm-12">Save
</button>
</form>
</div>
and the URLs
path ('accounts/revenues/create/', AccountsRevenueCreate.as_view(), name='revenue_create'),
I have chosen to show you only where the problem is not paste unnecessary code
here are the models you requested me to update
from django.db import models
class AccountsRevenue(models.Model):
revenue_of = models.CharField(max_length=250, default='',null=False)
revenue_by = models.CharField(max_length=250, default='',null=False)
amount = models.IntegerField( default='100,000')
day_on_which = models.DateField(null=True, blank=True)
evidence_document = models.ImageField(upload_to = 'uploads/', blank=True, default='')
signature = models.ImageField(upload_to = 'uploads/', blank=True, default='')
def __str__(self):
return str(self.revenue_of)
def get_absolute_url(self):
return reverse('dashboard:revenue', kwargs= {'pk':self.pk} )
def get_document(self):
if self.evidence_document and hasattr(self.evidence_document, 'url'):
return self.evidence_document.url
else:
return "/static/assets/img/user.png"
class AccountsExpense(models.Model):
expense_of= models.CharField(max_length=250, default='',null=False)
expense_by = models.CharField(max_length=250, default='',null=False)
amount = models.IntegerField( default='100,000')
day_on_which = models.DateField(null=True, blank=True)
evidence_document = models.ImageField(upload_to = 'uploads/',
blank=True, default='')
signature = models.ImageField(upload_to = 'uploads/', blank=True,
default='')
def __str__(self):
return str(self.expense_of)
def get_absolute_url(self):
return reverse('dashboard:expense', kwargs= {'pk':self.pk} )
def get_document(self):
if self.evidence_document and hasattr(self.evidence_document,
'url'):
return self.evidence_document.url
else:
return "/static/assets/img/user.png"
from django.urls import URLPattern, path
from django.conf.urls.static import static
from. views import profiles, Profile_detail, Profile_update,
Profile_delete, dashboard, Profile_create,\
AccountsRevenues, revenue_detail_view, AccountsRevenueUpdate,
AccountsRevenue_delete, \
AccountsExpenses, AccountsExpenseDetail, AccountsExpenseCreate,
AccountsExpenseUpdate, AccountsExpenseDelete,\
userprofileupdate, revenue_add, AccountsRevenueCreate
app_name = "dashboard"
urlpatterns = [
path ('accounts/revenues', AccountsRevenues.as_view(), name='revenues'),
path ('accounts/revenues/<str:pk>/', revenue_detail_view,
name='revenue'),
path ('accounts/revenues/<str:pk>/update/',
AccountsRevenueUpdate.as_view(), name='revenue_update'),
path ('accounts/revenues/<str:pk>/delete/',
AccountsRevenue_delete.as_view(), name='revenue_delete'),
path ('accounts/revenues/create/', AccountsRevenueCreate.as_view(),
name='revenue_create'),
# accounts expenses
path ('accounts/expenses', AccountsExpenses.as_view(), name='expenses'),
path ('accounts/expenses/<str:pk>', AccountsExpenseDetail.as_view(),
name='expense'),
path ('accounts/expenses/<str:pk>/update/',
AccountsExpenseUpdate.as_view(), name='expense_update'),
path ('accounts/expenses/<str:pk>/delete/',
AccountsExpenseDelete.as_view(), name='expense_delete'),
path ('accounts/expenses/create/', AccountsExpenseCreate.as_view(),
name='expense_create'),
]
I have added a screenshot of what it comes out as enter image description here
left model.py, forms.py, urls.py as it was.
views.py
in the line: template_name = 'bboard/expense_create.html' replace bboard with the name of the folder where the templates are located. I have it templates/bboard. Also in your field: form_class=AccountsExpenseForm changed to form_class = AccountsRevenueForm.
And the return goes to the same page with the form: success_url = reverse_lazy('revenue_create').
success_url can then be returned to what it was, now you need to make sure that everything works.
views.py
class AccountsRevenueCreate(CreateView):
template_name = 'bboard/expense_create.html'
model = AccountsExpense
success_url = reverse_lazy('revenue_create')
form_class = AccountsRevenueForm
expense_create.html
in the template you have an error form method="post", there should not be a comma.
<div class="row">
<div class="col-12">
<h5 class="form-title"><span>revenue Update
</span></h5>
</div>
<form method="post" action="{% url 'revenue_create' %}">
{% csrf_token %}
{% comment %} {{ form|crispy }} {% endcomment %}
{{ form.as_p }}
<button type="submit" class="btn btn-primary col-12 col-sm-12">Save
</button>
</form>
</div>
Followed the link: http://localhost:8000/accounts/revenues/create/
Screenshot attached:

how can I add Image to my django database and display it in frontend

I am making a blogging website in Django. I want to add a functionality with which the user can upload an image in the form, which will be used as a thumbnail for that blog. I have added imageField in models.py file, now I am not getting how shall I take the image input from the user in the form section?
post models.py:
class Post(models.Model):
sno = models.AutoField(primary_key=True)
thumbnail = models.ImageField(null=True, blank=True, upload_to="images/")
title = models.CharField(max_length=50)
content = RichTextField(blank=True, null=True)
author = models.CharField(max_length=50)
slug = models.CharField(max_length=200)
timeStamp = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ['-timeStamp']
def __str__(self):
return self.title + " by " + self.author
html forms:
<form action = "{% url 'addblog' %}" method="post">
<div class="form-group">
<label for="title" id="Title">Title</label>
<input type="text" class="form-control" id="title" name="title"/>
</div>
{% csrf_token %}
<div class="form-group">
<textarea name="content"></textarea>
<script type = 'text/javascript'>
CKEDITOR.replace("content")
</script>
</div>
<button type="submit" class="btn btn-primary my-1" id='contact-button'>Post</button>
</form>
currently the add blog page looks like this:
now I want a choose file option after the content text area where the user can upload an image and then that image gets saved in the database, after which I can display the image in the blog section at frontend.
pip install pillow
change <form> to this:
<form method="post" enctype="multipart/form-data">
<input type='file' name='imagefile'>
require "multipart/form-data" to send image or file from form.
in settings.py add code:
MEDIA_URL = '/media/'
in views.py
if you are using function based view, do this:
image = request.FILES.get('imagefile')
post = Post()
post.thumbnail=image
add other fields of the model.
save model by using post.save() command.
image.filename returns new file name of the image.
it will directly save image in media/images/ folder

How do i upload image to database from django form?

I have tried this but did not work.
class Agent(models.Model):
first_name = models.CharField(max_length=50, blank=False)
last_name = models.CharField(max_length=50, blank=False)
email = models.EmailField(blank=False)
cellPhone = models.IntegerField(blank=False)
picture = models.ImageField(blank=False)
class AgentForm(forms.ModelForm):
class Meta:
model = Agent
fields = ('first_name','last_name','cellPhone','email', 'picture')
<form method="POST" class="post-form" enctype="multipart/form-data">{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="save btn btn-default">Save</button>
</form>
I select the file using the form button but it says "the field is required".
I think it didn't work because you didn't mention the request.FILES in your views.py.
Whitout the request.FILES you can not receive the file uploaded.
form = AgentForm(request.POST, request.FILES)
If your user is uploading pictures, you need to have your MEDIA_ROOT settings on-point. Documentation

Upload file with a text description

I can't manage to upload and save a file with a text value as a description. I don't understand why: the form and model clearly has the related fields. When I remove the reference to the text field tekst from my view, it does upload and save the file correctly. FYI: I am using a subdirectory structure basis one of the model fields, which is why there is def get_upload_to in my model and Overig_Beeld.objects.create in my view, rather than just upload.save().
Model:
def get_upload_to(instance, filename):
return 'bulkafbeeldingen/%s/%s' % (instance.bulknummer, filename)
class Overig_Beeld(models.Model):
file = models.FileField(upload_to=get_upload_to)
bestandnaam = models.CharField(max_length=256, null=True)
upload_date = models.DateTimeField(auto_now_add=True)
bulknummer = models.ForeignKey(Bulk, null=True)
tekst = models.CharField(max_length=512)
Form:
class Overig_BeeldForm(forms.ModelForm):
file = forms.FileField()
tekst = forms.CharField(required=False)
class Meta:
model = Overig_Beeld
fields = ('file', 'tekst')
template:
<form action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
<label for="file">Bestand:</label>
<input type="file" name="file"/>
<input type="text" name="tekst"/>
<input type="submit" value="Upload" />
</form>
View:
if request.method=="POST":
upload = Overig_BeeldForm(request.POST, request.FILES)
if upload.is_valid():
f = request.FILES['file']
Overig_Beeld.objects.create(file=f, bestandnaam=f.name, bulknummer=bulk, tekst=upload.tekst )
return redirect(reverse('bulk', args=(bulk.slug,)))
error:
'Overig_BeeldForm' object has no attribute 'tekst'
Uploaded data contains in cleaned_data attribute in django form's instance. So
text = upload.cleaned_data['tekst']
will fix your problem

how to upload multiple images to a blog post in django

I am trying to allow each user to upload multiple pictures to a single blog post. I have been trying to work out the best way to do this for a few days now. What is the best practice to do this?
From what I have read, I should make a seperate image model from the blog post model and use a foreign key. Is that right?
Then there is the matter of how to allow them to upload multiple pictures at the same time. Am I right in assuming I should use something like drop zone?
Any advice on best practices for storing the photos is also welcome. I have looked at Amazon s3 and cloudinary. I want to create something which is scalable.
Any help would be much appreciated!
You'll just need two models. One for the Post and the other would be for the Images. Your image model would have a foreignkey to the Post model:
from django.db import models
from django.contrib.auth.models import User
from django.template.defaultfilters import slugify
class Post(models.Model):
user = models.ForeignKey(User)
title = models.CharField(max_length=128)
body = models.CharField(max_length=400)
def get_image_filename(instance, filename):
title = instance.post.title
slug = slugify(title)
return "post_images/%s-%s" % (slug, filename)
class Images(models.Model):
post = models.ForeignKey(Post, default=None)
image = models.ImageField(upload_to=get_image_filename,
verbose_name='Image')
You need to create a form for each model, but they will be related to each other, as in when the user is filling out the form post he has to complete the image form too for the post to successfully be posted, and we shall do that in the views, but for now your form can look something like this
from django import forms
from .models import Post, Images
class PostForm(forms.ModelForm):
title = forms.CharField(max_length=128)
body = forms.CharField(max_length=245, label="Item Description.")
class Meta:
model = Post
fields = ('title', 'body', )
class ImageForm(forms.ModelForm):
image = forms.ImageField(label='Image')
class Meta:
model = Images
fields = ('image', )
Now this is the most important part of everything, the views, because this is where uploading multiple images to a single magic happens. For us to be able to upload multiple images at once, we need multiple image fields right? That's where you fall in love with Django formsets. We will need django formsets to make this happen, you can read about formsets in the Django documentation, which I have linked :) But here is how your view should look like:
*Very important the imports
from django.shortcuts import render
from django.forms import modelformset_factory
from django.contrib.auth.decorators import login_required
from django.contrib import messages
from django.http import HttpResponseRedirect
from .forms import ImageForm, PostForm
from .models import Images
#login_required
def post(request):
ImageFormSet = modelformset_factory(Images,
form=ImageForm, extra=3)
#'extra' means the number of photos that you can upload ^
if request.method == 'POST':
postForm = PostForm(request.POST)
formset = ImageFormSet(request.POST, request.FILES,
queryset=Images.objects.none())
if postForm.is_valid() and formset.is_valid():
post_form = postForm.save(commit=False)
post_form.user = request.user
post_form.save()
for form in formset.cleaned_data:
#this helps to not crash if the user
#do not upload all the photos
if form:
image = form['image']
photo = Images(post=post_form, image=image)
photo.save()
# use django messages framework
messages.success(request,
"Yeeew, check it out on the home page!")
return HttpResponseRedirect("/")
else:
print(postForm.errors, formset.errors)
else:
postForm = PostForm()
formset = ImageFormSet(queryset=Images.objects.none())
return render(request, 'index.html',
{'postForm': postForm, 'formset': formset})
In the view, we are getting both of our forms, and it will check both forms whether they are valid or not. In that way, user has to fill the form AND upload all the images which, in this case, are 3 extra=3. Only then will the post successfully get created.
Your template should look like this then:
<form id="post_form" method="post" action="" enctype="multipart/form-data">
{% csrf_token %}
{% for hidden in postForm.hidden_fields %}
{{ hidden }}
{% endfor %}
{% for field in postForm %}
{{ field }} <br />
{% endfor %}
{{ formset.management_form }}
{% for form in formset %}
{{ form }}
{% endfor %}
<input type="submit" name="submit" value="Submit" />
</form>
Step by step solution => Even, I was stuck too. So this is how I successfully do.
Finally, implementing below code, I achieved this
1 Note model with many Images
Multiple Uploads(at the same time, with same Choose File button, & all save together as like in Gmail file upload)
Here are my Note and Image Model- (or see full code)
class Note(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE)
title = models.CharField(max_length=30)
text = models.TextField(null=True,blank=True)
created_date = models.DateTimeField(auto_now_add=True)
last_modified = models.DateTimeField(auto_now=True)
class Images(models.Model):
note = models.ForeignKey(Note,on_delete=models.CASCADE)
image = models.ImageField(upload_to=user_directory_path,null=True,blank=True)
Here is my form (Link of doc. on multiple upload)- (or see full code)
class NoteForm(forms.ModelForm):
class Meta:
model = Note
fields = ['title','text'] #make sure to mention field here, if nothing is mentioned then all will be required.
class NoteFullForm(NoteForm): #extending form
images = forms.FileField(widget=forms.ClearableFileInput(attrs={'multiple': True}))
class Meta(NoteForm.Meta):
fields = NoteForm.Meta.fields + ['images',]
Here is my View file- (or see full code)
def addNoteView(request):
if request.method == "POST":
#images will be in request.FILES
form = NoteFullForm(request.POST or None, request.FILES or None)
files = request.FILES.getlist('images')
if form.is_valid():
user = request.user
title = form.cleaned_data['title']
text = form.cleaned_data['text']
note_obj = Note.objects.create(user=user,title=title,text=text) #create will create as well as save too in db.
for f in files:
Images.objects.create(note=note_obj,image=f)
else:
print("Form invalid")
And, finally my Html file (be sure to bind files as said in docs)- (or see full code)
<form action="{% url 'note:add_note' %}" method="post" class="note-form" enctype="multipart/form-data">{% csrf_token %}
<div class="form-group">
<label for="note-title">Title</label>
<input type="text" name="title" class="form-control" id="note-title" placeholder="Enter Title" required>
</div>
<div class="form-group">
<label for="note-description">Description</label>
<textarea type="text" name="text" class="form-control" id="note-description" placeholder="Description here"></textarea>
</div>
<div class="form-group">
<label for="note-image">Images</label>
<input type="file" name="images" class="form-control-file" id="note-image" multiple>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
The answer is very simple. So much of code is not required.
HTML File
<input type="file" name = "files" multiple />
VIEWS.PY
files = request.FILES.getlist('files')
for f in files:
a = Image(image=f)
a.save()
I had a similar problem. In my model, an article must have a thumbnail(image), then I set five more fields for optional images. The problem came in when after applying the safe filter, the image source would not render because it was not HTML anymore,
<img src="{{article.image1.url}}" class="some class">
would not work. A temporary solution I used was to name the images according to the title of the article. If I am writing on "django filters", I would name my additional images djangofiltersimage1.png or djangofiltersimage2.png, this helps since in my model each article has a unique title. I then changed the image source to:
<img src="/media/djangofiltersimage1.png" class="some class">
The only issue is the strict naming of images. You can upload more images by creating a model for Blog Images. I am still looking for another solution in the meantime.
You can check out my blog here
getlist name and html input name fiels should be same
for models.py
class studentImage(models.Model):
image = models.ImageField(upload_to='media/')
def __str__(self):
return self.image
for views.py
def studentImageView(request):
if request.method == "POST":
images = request.FILES.getlist('images')
for image in images:
photo = studentImage.objects.create(image=image,)
photo.save()
return render(request, 'image.html')
for template
<form method="post" enctype="multipart/form-data" >
{% csrf_token %}
<input required name="images" type="file" multiple >
<button class="btn btn-primary" type="submit">Upload</button>
</form>