I am having some trouble getting a file to post via a form using generic class-based view CreateView. Below is what i have so far. I am not quite sure how to handle the file and if request.FILES is getting the file being posted or if there is something else i need to be doing to capture the file information in the form. I have tried following the docs, however no luck in getting something working. File uploads as a blank field.
views.py
# Create
class FileUploadCreateView(BSModalCreateView):
template_name = 'fileupload/create-file.html'
form_class = FileUploadModelForm
success_message = 'Success: File was uploaded.'
success_url = reverse_lazy('files_list')
# Add required field my_user prior to posting form
def form_valid(self, form):
form = FileUploadModelForm(self.request.POST, self.request.FILES)
self.object = form.save(commit=False)
self.object.my_user = self.request.user
self.object.file_status = 'ready'
return super().form_valid(form)
forms.py
class FileUploadModelForm(BSModalModelForm):
class Meta:
model = FileUpload
fields = ['file_name', 'file_description', 'file_date_from', 'file_date_to','file_upload']
widgets = {
'file_name': forms.TextInput(attrs={'class':'form-control mb-3', 'id':'ruleset_name'}),
'file_description': forms.Textarea(attrs={'rows':5}),
'file_date_from': DatePickerInput(
options={
"format": "MM/DD/YYYY",
"showClose": True,
"showClear": True,
"showTodayButton": True,
}
),
'file_date_to': DatePickerInput(
options={
"format": "MM/DD/YYYY",
"showClose": True,
"showClear": True,
"showTodayButton": True,
}
),
'file_upload': forms.FileInput(attrs={'class':'form-control-file mb-3', 'id':'file_upload', 'type':'file', }),
}
html
{% load widget_tweaks %}
<form method="post" action="" enctype="multipart/form-data">
{% csrf_token %}
<div class="modal-header">
<h5 class="modal-title" style="color:#7a7a7a;">
<i class="fas fa-plus-square fa-med pr-2 align-middle"></i>
<span class="align-middle">ADD File</span>
</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<div class="{% if form.non_field_errors %}invalid{% endif %} mb-2">
{% for error in form.non_field_errors %}
{{ error }}
{% endfor %}
</div>
{% for field in form %}
<div class="form-group">
<label for="{{ field.id_for_label }}" style="font-size: small; color:#7a7a7a;">{{ field.label }}</label>
{% render_field field class="form-control" %}
<div class="{% if field.errors %} invalid{% endif %}">
{% for error in field.errors %}
<p class="help-block">{{ error }}</p>
{% endfor %}
</div>
</div>
{% endfor %}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline-secondary" data-dismiss="modal">Cancel</button>
<button type="button" class="submit-btn btn btn-primary pr-4 pl-4">Save</button>
</div>
</form>
model.py
class FileUpload(models.Model):
"""
Class for the creation of file uploads
"""
id = models.AutoField(primary_key=True)
my_user = models.ForeignKey('users.MyUser', on_delete=models.CASCADE, related_name='file_uploads', default=None)
file_name = models.CharField(max_length=255, blank=False, default=None, verbose_name='File Name')
file_description = models.CharField(max_length=255, blank=False, default=None, verbose_name='File Description')
file_date_from = models.DateField(default=None, null=True, blank=False, verbose_name='File Date From')
file_date_to = models.DateField(default=None, null=True, blank=False, verbose_name='File Date To')
STATUS_CHOICES = (
('ready','Ready'),
('processed', 'Processed'),
('archived','Archived'),
)
file_status = models.CharField(max_length=9, choices=STATUS_CHOICES, default=None, blank=False, verbose_name='File Status')
file_create_date = models.DateTimeField(verbose_name='File Create Date', auto_now_add=True)
file_upload = models.FileField(upload_to='uploads/%Y/%m/%d/', default=None, verbose_name='File Upload', blank=True)
class Meta:
ordering = ['-file_create_date']
constraints = [
models.UniqueConstraint(fields=['my_user','file_name'], name='Unique MyUser File')
]
def __str__(self):
return self.file_name
Pretty sure you forgot to add the enctype="multipart/form-data" data attribute to the form tag in your template.
To be sure, you would have to provide us with the Model, the Form and the template code.
after working on the view for some time, I was able to get the file to post via the following, using cleaned_data.
# Add required fields prior to posting form
def form_valid(self, form):
self.instance = form.save(commit=False)
self.instance.my_user = self.request.user
self.instance.file_status = 'ready'
self.instance.file_upload = form.cleaned_data['file_upload']
return super().form_valid(form)
Related
I have a view complaints page where a user can view the complaints he/she have submitted. When the user clicks on one of the cards, I need a new page to open where the user can view the details of that complaint and edit it as well.
It should go from here:
to here: Where they can view details and make changes as well:
This is my models.py:
class Complaint(models.Model):
user = models.ForeignKey(User, on_delete= models.CASCADE, null = True, blank=True)
id = models.AutoField(blank=False, primary_key=True)
reportnumber = models.CharField(max_length=500 ,null = True, blank= False)
eventdate = models.DateField(null=True, blank=False)
event_type = models.CharField(max_length=300, null=True, blank=True)
device_problem = models.CharField(max_length=300, null=True, blank=True)
manufacturer = models.CharField(max_length=300, null=True, blank=True)
product_code = models.CharField(max_length=300, null=True, blank=True)
brand_name = models.CharField(max_length = 300, null=True, blank=True)
exemption = models.CharField(max_length=300, null=True, blank=True)
patient_problem = models.CharField(max_length=500, null=True, blank=True)
event_text = models.TextField(null=True, blank= True)
document = models.FileField(upload_to='static/documents', blank=True, null=True)
def __str__(self):
return self.reportnumber
views.py:
def EditComplaints(request):
complaint = request.user.complaint
form = ComplaintForm(instance=complaint)
if request.method == 'POST':
form = ComplaintForm(request.POST, request.FILES, instance=complaint)
if form.is_valid():
form.save()
context = {'form': form}
return render(request, 'newcomplaint.html', context)
template (the view history page):
<div class="col right-pro-con">
<div class="img-cir">
<form method='POST' action="" enctype="multipart/form-data">
{% csrf_token %} {% if request.user.profile.profile_pic.url %}
<img src={{request.user.profile.profile_pic.url}} alt="" width="100px" height="100px" class="pro-img"> {% else %}
<img src="{% static 'profileimages/msi.jpg' %}" alt="" width="100px" height="100px" class="pro-img"> {% endif %}
<p class="my-name">{{request.user.profile.first}}
<p>
<p class="my-email-id">{{request.user.profile.email}}</p>
</form>
</div>
CONTACT US
</div>
template(edit complaint page):
<div class="col-lg middle middle-complaint-con">
<i class="fas fa-folder-open fa-4x comp-folder-icon"></i>
<h1 class="all-comp">New Complaint</h1>
<form class="" action="" method="POST" enctype="multipart/form-data">
{% csrf_token %}
<p class="sub-typ-wr">Submit Type</p>
<button type="button" class="btn btn-secondary document-btn">Document</button>
<div class="rep-num">
<label class="written-label" for="">Report Number</label>
<div class="written-txt-field">{{form.reportnumber}}</div>
</div>
<div class="eve-dte">
<label class="written-label" for="">Event Date</label>
<div class="written-txt-field">{{form.eventdate}}</div>
</div>
<div class="eve-typ">
<label class="written-label" for="">Event Type</label>
<div class="written-txt-field">{{form.event_type}}</div>
</div>
<div class="dev-pro">
<label class="written-label" for="">Device Problem</label>
<div class="written-txt-field">{{form.device_problem}}</div>
</div>
<label class="written-label eve-txt" for="">Event Text</label>
<div class="Manufacturer">
<label class="written-label" for="">Manufacturer</label>
<div class="written-txt-field">{{form.manufacturer}}</div>
</div>
<div class="pro-code">
<label class="written-label" for="">Product Code</label>
<div class="written-txt-field">{{form.product_code}}</div>
</div>
<div class="brand-name">
<label class="written-label" for="">Brand Name</label>
<div class="written-txt-field">{{form.brand_name}}</div>
</div>
<div class="exem">
<label class="written-label" for="">Exemption</label>
<div class="written-txt-field">{{form.exemption}}</div>
</div>
<div class="pat-pro">
<label class="written-label" for="">Patient Problem</label>
<div class="written-txt-field">{{form.patient_problem}}</div>
</div>
<div class="comp-textarea">{{form.event_text}}</div>
<button type="button" class="btn btn-secondary attach-btn-1"><div class="fas fa-file-upload">{{form.document}}</div></button>
<button type="submit" name="submit" class="btn btn-secondary save-btn-1"><i class="fas fa-save"></i> Save</button>
</form>
</div>
url:
urlpatterns = [
path('admin/', admin.site.urls),
path('Home/', landing_page.views1.landing, name= 'Home'),
path('Registration/', accounts.views.RegisterPage),
path('Login/', accounts.views.LoginPage, name='Login'),
path('Login/Profile/', accounts.views.profile, name='Profile'),
path('Logout/', accounts.views.LogoutUser, name='Logout'),
path('Login/Add-Complaint/', accounts.views.NewComplaint, name = 'New'),
path('Login/Add-Complaint/Document-Style/', accounts.views.DocComplaint, name='doc'),
path('My-History/', accounts.views.History, name='MyHistory'),
path('Complaint/', accounts.views.EditComplaints, name='Complaint')
]
How do I do this? What should I add in the code for the code to open that particular complaints details and for that complaints page to edit?
okay, so you already have a view. What you need is some sort of unique identifier to help you figure out the actual object that the user wants to edit.
So, in your urls.py you will have to add a pattern similar to:
urlpatterns = [
...
path('complain/<int:pk>/edit/', views.EditComplaint.as_view(), name='edit-complain'),
...
]
Inside your views.py, handle it in a manner something similar to:
from django.views.generics import UpdateView
from django.contrib.auth.mixins import UserPassesTestMixin
from django.http import Http404
from django.utils.translation import gettext_lazy as _
from .models import Complaint
class EditComplaint(UserPassesTestMixin, UpdateView):
model = Complaint
fields = ('info', ) # define whatever field that you want to render
def form_valid(self, form):
# do your form validation here
def test_func(self):
"""ensuring the reporter themselves is updating the complain"""
complain = self.get_object()
if self.request.user == complain.user:
return True
raise Http404(_('This complain does not exist'))
def success_url(self):
# this is only required if your model doesn't have a `get_absolute_url` method
# return the actual url of the instance
All you need now is to add a link inside your template for the EditComplaint view(assuming you already have the list of donations inside your list template as donations).
Something along the lines should do the job
{% for complaint in complaints %}
Edit Complaint
{% endfor %}
I made a project with net-ninja on youtube now I am adding "uploading media" feature in my own project but it is not working although every thing is set just tell me where i m going wrong.
My form is keep asking me to upload image file even though i had already done, every time i send a post request it renders the page again with no value in image field. what is wrong here, why it is not taking image input?Don't comment set the required to false that is not the solution i don't know why some people said this to others on stackoverflow when they asked the same question as me.
My model class looks like this
class Products(models.Model):
name = models.CharField(max_length=500, unique=True, )
price = models.IntegerField()
stock = models.IntegerField()
date_added = models.DateTimeField(verbose_name="date added", auto_now_add=True, )
thumb = models.ImageField(default='default.png', blank=True)
profile = models.ForeignKey(Profile, on_delete=models.CASCADE, default=None,)
def __str__(self):
return self.name
class Meta():
verbose_name_plural = "Products"
My form looks like this
class AddProduct(forms.ModelForm):
name = forms.CharField(widget=forms.TextInput(attrs={'placeholder':'Product Name', 'required':'True', 'class': 'form-control'}))
price = forms.IntegerField(widget=forms.NumberInput(attrs={'placeholder':'Set Price', 'required':'True', 'class': 'form-control'}))
stock = forms.IntegerField(widget=forms.NumberInput(attrs={'placeholder':'Number of items', 'required':'True', 'class': 'form-control'}))
thumb = forms.ImageField(required=False, widget=forms.ClearableFileInput(attrs={'placeholder':'Upload Picture', 'enctype' : 'multipart/form-data'}))
class Meta():
model = Products
fields = ('name', 'price', 'stock','thumb', )
HTML looks like this
<form class="row contact_form" action="/shop/add_products" method="post">
{% csrf_token %}
{% for field in form %}
<div class="col-md-12 form-group p_star">
{{ field }}
{{ field.errors }}
</div>
{% endfor %}
<!-- {% for field in form %}
{% for error in field.errors %}
<div class="col-md-12 form-group p_star">
{{ error }}
</div>
{% endfor %}
{% endfor %} -->
{% if form.non_field_errors %}
<div class="col-md-12 form-group p_star">
{{ form.non_field_errors }}
</div>
{% endif %}
<div class="col-md-12 form-group">
<button type="submit" value="submit" class="btn_3">
Add Product
</button>
</div>
</form>
My views file looks like this
#login_required(login_url='/shop/login')
def shop_add_products(request):
if request.method == 'POST':
form = AddProduct(request.POST, request.FILES)
if form.is_valid():
instance = form.save(commit=False)
instance.profile = request.user
instance.save()
return redirect("/shop/products")
else:
form = AddProduct()
return render(request, "pillow_site_html/add_product.html", { 'form':form })
Oh sorry i didn't understood the question here, you are getting that because in fact you are not sending the picture inside your form as you have to add this to your form so it can accept files handling
<form class="row contact_form" action="/shop/add_products" method="post" enctype="multipart/form-data">
I am working with this simple form and can't able to display inline validation in each line. I want validation as it worked in the Django admin site, with particular fields. How could it be done! It only shows the HTML validation like "Please fill out the field"
models.py
class MemberRegistration(models.Model):
name = models.CharField(max_length=100)
email = models.EmailField(max_length=100)
phone = models.CharField(max_length=50)
def __str__(self):
return self.name
forms.py
from django import forms
from . models import MemberRegistration
from django.core import validators
class MemberForm(forms.ModelForm):
name = forms.CharField(widget=forms.TextInput(
attrs={'class': 'form-control', 'placeholder':'Name'}),
max_length=100, error_messages = {
'required':"Please Enter your Name"})
email = forms.EmailField(widget=forms.EmailInput(
attrs={'class': 'form-control', 'placeholder':'E-mail'}),
required=True, max_length=100)
phone = forms.CharField(widget=forms.TextInput(
attrs={'class': 'form-control', 'placeholder':'Phone'}),
required=True, max_length=100)
class Meta:
model = MemberRegistration
fields = "__all__"
def clean_name(self):
all_clean_data = super().clean()
name = all_clean_data['name']
if name == "":
raise forms.ValidationError("Name field is required")
member_form.html:
{% block body_block %}
<div class="container">
<h1>This is member reg form</h1>
<form method="post" novalidate>
{% csrf_token %}
<div class="form-group">
<label for="">Name</label>
{{ form.name.errors }}
{{form.name}}
</div>
<div class="form-group">
<label for="">Email</label>
{{ form.email.errors }}
{{form.email}}
</div>
<div class="form-group">
<label for="">Phone</label>
{{form.phone}}
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
{% endblock %}
How I can do this with Django's built-in validation?
I'm using a FilterSet to perform a filtering over a set of product. First of all, here is my code :
models.py
class Plat(models.Model):
titre = models.CharField(max_length = 100)
description = models.TextField(null = True)
allergenes = models.TextField(null = True)
prix = models.IntegerField(verbose_name = "Prix par portion")
chef = models.ForeignKey('inscription.Chef', on_delete = models.CASCADE)
date_prep = models.DateField(default=timezone.now, verbose_name="Date de préparation")
nb_portions = models.IntegerField(verbose_name = "Nombre de portions disponibles")
photo = models.ImageField(upload_to = "photos_plat/")
filters.py
class PlatFilter(django_filters.FilterSet):
class Meta:
model = Plat
fields = {
'titre': ['icontains'],
'prix': ['lte', 'gte'],
'nb_portions': ['gte'],
'date_prep': ['exact'],
}
views.py
def home(request):
plats = Plat.objects.all()
filter = PlatFilter(request.GET, queryset=plats)
return render(request, 'actualites/home.html', locals())
home.html
<form method="get">
{{ filter.form.as_p }}
<button type="submit">Search</button>
</form>
Everything is working perfectly but I want to make the form prettier and being able to customize the label names and so on so I use this code :
{% load widget_tweaks %}
<form method="get">
<div class="well">
<h4 style="margin-top: 0">Filtrer par</h4>
<div class="row">
<div class="form-group col-sm-4 col-md-3">
{{ filter.form.titre.label_tag }}
{% render_field filter.form.titre class="form-control" %}
</div>
</div>
<button type="submit" class="btn btn-primary">
<span class="glyphicon glyphicon-search"></span> Search
</button>
</div>
</form>
And here nothing is displayed except the "Filtrer par" and the submit button. I've correctly installed widget_tweaks. Why isn't it working ? I've made a few researchs and I was not able to find an answer.
Thanks in advance !
I am writing a view to update a record in the database, when I try to switch to a record for editing, I get an error:
Error:
I wrote one to one from an existing view for another model, so I do not understand what the error is. How i can fix this?
urls.py
path(
'keys/<int:key_id>/',
views.UpdateKeyView.as_view(),
name='update_key'
),
views.py
class CreateKeyView(
SuccessMessageMixin,
CustomPermissionRequired,
CreateView
):
model = ApiKey
template_name = 'db_visual/create_key.html'
form_class = KeyForm
permission_required = (
'db_visual.add_keys',
)
success_message = "Ключи %(description)s успешно создан!"
def get_success_url(self):
print(self.object.id)
return reverse_lazy(
'update_key',
kwargs={'key_id': self.object.id}
)
class UpdateKeyView(
SuccessMessageMixin,
CustomPermissionRequired,
UpdateView
):
model = ApiKey
pk_url_kwarg = 'key_id'
template_name = 'db_visual/update_key.html'
form_class = KeyForm
success_url = reverse_lazy('keys')
permission_required = (
'db_visual.change_key',
)
success_message = "Ключ <a href='%(url)s'>%(description)s</a> " \
"успешно изменен!"
def get_success_message(self, cleaned_data):
return self.success_message % dict(
cleaned_data,
url=reverse_lazy(
'update_key',
kwargs={'key_id': self.object.id}
),
)
HTML-code create_key
{% for key in api_keys %}
<tr>
<td class="min-col">
<a href="{% url 'update_key' key_id=key.id %}">
{{ key.description}}
</a>
</td>
<td class="min-col">{{ key.open_key }}</td>
<td class="min-col">{{ key.secret_key }}</td>
<td class="min-col">
<a class="btn btn-sm btn-link"
href="{% url 'update_key' key_id=key.id %}">
<i class="far fa-edit fa-lg"></i>
</a>
</tr>
{% endfor %}
HTML-code update_key
<form action="{% url 'update_key' key_id=key.id %}"
method="post" class="col-12" id="key_form">
{% csrf_token %}
<div class="card">
<h2 class="card-header">
<div class="row">
<div class="col-6">
Ключи для {{ key.description }}
</div>
</div>
</h2>
<div class="card-body">
{% include 'db_visual/key_form_body.html' %}
</div>
<div class="card-footer text-muted">
<input type="submit" class="btn btn-primary" value="Сохранить"/>
</div>
</div>
</form>
Model.py
class ApiKey(models.Model):
open_key = models.CharField(max_length=128)
secret_key = models.CharField(max_length=128)
description = models.CharField(max_length=128)
restrict_ip = models.BooleanField()
ip = ArrayField(
models.CharField(max_length=32, blank=False, null=True), size=8, blank=True, null=True
)
valid_to_date = models.DateField()
restrict_methods = models.BooleanField()
allowed_methods = ArrayField(
models.CharField(max_length=32, blank=True, null=True),
size=8, blank=True, null=True
)
forbidden_methods = ArrayField(
models.CharField(max_length=32, blank=True, null=True),
size=8, blank=True, null=True
)
class Meta:
db_table = '"processing"."api_key"'
UPD: When i create new object and try to do function get_success_url it gets the same error, but self.object.id in not None.
UPD2: found out that the model object is not passed to update_key, but it is not clear why.
Error was in name of object...