Django file upload using Form - python

I'm trying to upload a file on a model in Django framework.
class banner(models.Model):
#id is made by Django
name = models.CharField(max_length=255)
created_by = models.CharField(max_length=255)
company = models.CharField(max_length=255)
register_date = models.DateField(auto_now_add=True)
file = models.FileField(null=True, blank=True)
file_name = models.CharField(max_length=255)
this is the model:
class BannerForm(forms.Form):
name=forms.CharField(max_length=255)
created_by=forms.CharField(max_length=255)
company=forms.CharField(max_length=255)
data_type=forms.CharField(max_length=255)
register_date=forms.DateField()
file=forms.FileField()
file_name=forms.CharField(max_length=255)
this is the form:
def add_form(request):
form=BannerForm()
last=models.banner.objects.all().last()
if request.method == "POST":
form = forms.BannerForm(request.POST, request.FILES or None)
if form.is_valid():
form.cleaned_data['created_by']
new_banner=models.banner()
new_banner.id=last.id+1
new_banner.name=form.cleaned_data['name']
new_banner.register_date=form.cleaned_data['register_date']
new_banner.company=form.cleaned_data['company']
new_banner.file=form.cleaned_data['file']
new_banner.file_name=new_banner.file.name
new_banner.created_by=form.cleaned_data['created_by']
new_banner.save()
return render(request, "add_banner.html",{"form":form})
this is the view.
Now every time I try to add a banner, I browse the file, but after I click "submit", it is that the file must be chosen, like it doesn't recognize what I browse to the form button.

well you need to specify the upload path in your models
file = models.FileField(null=True, blank=True,upload_to='files')
and make sure you have MEDIA_ROOT and MEDIA_URL defined in your settings.py
in your form
<form method="post" action="" enctype="multipart/form-data">
{% csrf_token %}
...
</form>

You need to include enctype="multipart/form-data" in your form definition.
<form method="post" action="your action" enctype="multipart/form-data">
{% csrf_token %}
...
</form>

Try this something like this :
Models.py :
class banner(models.Model):
#id is made by Django
name = models.CharField(max_length=255)
created_by = models.CharField(max_length=255)
company = models.CharField(max_length=255)
register_date = models.DateField(auto_now_add=True)
file = models.FileField(upload_to='files/', null=True, blank=True)
file_name = models.CharField(max_length=255)
forms.py :
class BannerForm(forms.ModelForm):
class Meta:
model = banner #Or Banner ??
fields = ('name', 'created_by', 'company', 'file', 'file_name' )
views.py :
from myapp.forms import BannerForm
if request.method == "POST":
form = BannerForm(request.POST, request.FILES)
if form.is_valid():
entry = form.save(commit=False)
entry.name = request.POST['name']
entry.created_by = request.POST['created_by']
entry.company = request.POST['company']
entry.file_name = request.POST['file_name']
form.save()
else:
form = BannerForm()
return render(request, "add_banner.html",locals())
And like already said, don't forget :
<form method="POST" action="" enctype="multipart/form-data">
{% csrf_token %}
{{form.name}}
{{form.created_by}}
{{form.company}}
{{form.file_name}}
{{form.file}}
<input type="submit">
</form>
You don't have to specify these things :
new_banner.file=form.cleaned_data['file']
new_banner.register_date=form.cleaned_data['register_date'] -> useless because in your model you set auto_now_add=True, so you don't need te make a field in your HTML form.
Note : if your field created_by = models.CharField(max_length=255) is to put an existing user, so you should make a foreign key field like :
from django.contrib.auth.models import User
created_by = models.ForeignKey(User, verbose_name="Created by")

Related

Form returning not valid in django

In my django app I have a User model that has a Boolean field of is_manager.
User model in models.py:
class User(AbstractUser):
name = models.CharField(max_length=15, null=True, blank=True)
last_name = models.CharField(max_length=15, null=True, blank=True)
title = models.CharField(max_length=50, null=True, blank=True)
email = models.EmailField(unique=True)
bio = models.TextField(null=True, blank=True)
company = models.ForeignKey(Company, on_delete=models.DO_NOTHING, null=True)
is_manager = models.BooleanField(default=False)
can_assign = models.BooleanField(default=False)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username']
I've been trying to create an edit page in order for managers and users to be able to change some of their fields.
Regular users should be able to change their bio and title, and the managers can change the can_assign Boolean.
I have a form that deals with the logic of that in forms.py:
class EditUserForm(ModelForm):
def __init__(self, *args, **kwargs):
self.user = kwargs.pop('user')
if self.user.is_manager:
super().__init__(**kwargs)
else:
super().__init__(**kwargs)
del self.fields['can_assign']
class Meta:
model = User
fields = ['title', 'can_assign', 'bio']
views.py:
#login_required
def editUser(request, pk):
user = User.objects.get(id=pk)
if request.user.is_manager or request.user == user:
#POST
if request.method == 'POST':
form = EditUserForm(request.POST, instance=user, user=request.user)
if form.is_valid():
form.save()
redirect('user-page', pk)
else:
print('nope')
#GET
form = EditUserForm(user=request.user, instance=user)
context = {'user': user, 'form': form}
return render(request, 'users/user_edit.html', context)
else:
return HttpResponse('<h1>Access Denied</h1>')
template:
{% extends 'main.html' %}
{% block content %}
<form method="POST" action="">
{% csrf_token %}
{{form.as_p}}
<input type="submit" value="Submit">
</form>
{% endblock content %}
for some reason the form.is_valid() method returns False. I have no idea why.
I have tried to use the .errors method on the form and on the form fields. No errors shown.
Thanks for any help!
" Oh! I completely missed that. I think the *args is required because that's how you pass in the request.POST. if you would have an explicit key like myform(data=request.POST) it would have worked because it would be in the *kwargs .. So it was basically failing cause it was acting like you were just initiating a new form, not submitting one –
Nealium
"

Page not found (404) - The current path, editEstHab/, didn't match any of these

I have a problem when I want to update an existing object... in another project, I used a similar lines of code, but now, it doesn't work when I'm going to save the actual information...
the more stranger thing is... at the end says The current path, editEstHab/, didn't match any of these., but when I search on my project, the only time that I use editEstHab/ is in urls.py...
So... help :( I don't have any clue about what is my mistake.
models.py
class habitacion(models.Model):
nroHabitacion = models.IntegerField(null=False)
tipoHabitacion = models.CharField(max_length=70, null=True)
tipoCama = models.ForeignKey(tipoCama, on_delete=models.CASCADE, blank=True, null=False)
accesorios = models.CharField(max_length=70, null=True)
precio = models.IntegerField(null=False)
estado_habitacion = models.ForeignKey(estadoHab, on_delete=models.CASCADE, blank=True, null=True)
def __str__(self):
return self.tipoHabitacion
forms.py
class UpdateHabForm(forms.ModelForm):
class Meta:
model = habitacion
fields = ['estado_habitacion']
views.py
def editHab(request,id_habitacion):
# llamando datos de habitacion seleccionada
hab = habitacion.objects.get(id=id_habitacion)
if request.method == 'GET':
form = UpdateHabForm(instance=hab)
else:
form = UpdateHabForm(request.POST, instance=hab)
if form.is_valid():
form.save()
context = {
'form' : form,
'hab' : hab
}
return render(request,"editEstHab.html",context)
urls.py
path('editEstHab/<id_habitacion>', views.editHab, name="editEstHab"),
Error ScreenShot
It seems like the error is the url of the POST request
If you leave the action attribute of the html form blank, it should work fine
<form class="" action="" method="post">
{% csrf_token %}
{% for field in form %}
{{field}}
{% endfor %}
<button type="submit" name="button">UPDATE</button>
</form>

create a distinct model option in a dropdown using django

I have created this application but the problem I face now is one that has kept me up all night. I want users to be able to see and select only their own categories when they want to create a post. This is part of my codes and additional codes would be provided on request
category model
class Category(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, default=1,related_name='categories_created')
name = models.CharField(max_length = 120)
slug = models.SlugField(unique= True)
timestamp = models.DateTimeField(auto_now=False, auto_now_add=True)
post model
class Post(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, default=1,related_name='posts_created') #blank=True, null=True)
title = models.CharField(max_length = 120)
slug = models.SlugField(unique= True)
category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name='category_created', null= True)
addition codes would be provided immediately on request. Thanks
View.py in post app
def create(request):
if not request.user.is_authenticated():
messages.error(request, "Kindly confirm Your mail")
#or raise Http404
form = PostForm(request.POST or None, request.FILES or None)
user = request.user
categories = Category.objects.filter(category_created__user=user).distinct()
if form.is_valid():
instance = form.save(commit=False)
instance.user = request.user
instance.save()
create_action(request.user, 'Posts', instance)
messages.success(request, "Post created")
return HttpResponseRedirect(instance.get_absolute_url())
context = {
"form": form,
}
template = 'create.html'
return render(request,template,context)
Form
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = [
"title",
"content",
"category",
]
html
{% if form %}
<form method="POST" action="" enctype="multipart/form-data">{% csrf_token %}
{{ form|crispy|safe }}
<input type="submit" name="submit" value="Publish">
</form>
{% endif %}
What you need to do is well-described here. Basically, you are using ModelForm which generates the form from your model. Your model doesn't know anything about filtering by user, so you will need to explicitly add a QuerySet to your form that only shows the desired categories. Change your "categories = ..." line to something like:
form.category.queryset = Category.objects.filter(user=user)
form.fields['category'].queryset = Category.objects.filter(user=user)</strike>

Unable to automatically pick foreign key from modelform

I am working on a product app on Python 2.7 / Django 1.7.
I have a model for product namely 'product_profile' and I want to allow my customer (end user) to ask any thing regarding specific products using a form.
However I am unable to allow user to automatically select the product (foreign key) and the customer has to select from a drop-down which quite irrational. I have also assigned the foreign key in url-variable.
here is my code:
MODEL.PY
class ProductProfile(models.Model):
category = models.ForeignKey(Category)
brand = models.ForeignKey(Brand)
product_name = models.CharField(max_length=128)
model_name = models.CharField(max_length=128)
generation = models.CharField(max_length=128)
processor = models.CharField(max_length=128)
ram = models.DecimalField(max_digits=2, decimal_places=0)
hdd = models.DecimalField(max_digits=6, decimal_places=2)
optical_drive = models.CharField(max_length=128)
display = models.CharField(max_length=128)
card_reader = models.CharField(max_length=128)
blue_tooth = models.CharField(max_length=128)
web_cam = models.CharField(max_length=128)
warranty = models.CharField(max_length=128)
price = models.DecimalField(max_digits=9, decimal_places=2)
condition = models.TextField()
product_image = models.ImageField(upload_to=update_Product_image_filename)
post_date = models.DateTimeField(db_index=True, auto_now_add=True)
# Override th __unicode__() method to return out something meaningful!
def __unicode__(self):
return self.product_name
class Customer_ps_contact(models.Model):
name = models.CharField(max_length=128)
email = models.EmailField(max_length=75)
subject = models.CharField(max_length=128 )
product = models.ForeignKey(ProductProfile)
message = models.TextField()
phone_regex = RegexValidator(regex=r'^\+?1?\d{9,15}$', message="Phone number must be entered in the format:
'+999999999'. Up to 15 digits allowed.")
phone_number = models.CharField(validators=[phone_regex], blank=True, max_length=15) # validators should be a
list
def __unicode__(self):
return self.name
FORM.PY
class Customer_ps_contactForm(forms.ModelForm):
class Meta:
model = Customer_ps_contact
product = forms.ModelChoiceField(queryset=ProductProfile.objects.all(),
widget=forms.HiddenInput())
fields = ('name','email', 'product','subject','message', 'phone_number')
VIEWS.PY
def product_inquiry(request, product_id):
product = ProductProfile.objects.get(pk=product_id)
if request.method == 'POST':
#form = Customer_ps_contactForm(request.POST, initial = {'product': product})
#form = Customer_ps_contactForm(initial = {'product': product.id})
form = Customer_ps_contactForm(request.POST)
if form.is_valid():
form_data_dict = form.cleaned_data
print form_data_dict['product']
mail_customer_enquriy(form_data_dict) # Function to send email to admin
thank_u_customer(form_data_dict) # Function to send email to customers
form = form.save(commit=False)
form.product = product
form.save()
return home(request)
else:
print ("form is not valid")
print (form.errors)
else:
form = Customer_ps_contactForm()
context_dict = {'form':form, 'product': product}
return render(request, 'product/product_inquiry2.html',context_dict)
URL Patterns
urlpatterns = patterns('',
url(r'^inquiry/(?P<product_id>\d+)/$', views.product_inquiry, name='price'), # Only relevent url given
)
Template : product_inquiry2.html
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block body_block %}
{% block title %}Product Inquiry{% endblock %}
<div class="row">
<div class="col-md-10 col-md-offset-1">
<h2 style="font-weight:bold">Enquiry regarding '{{product.product_name}}'</h2>
<hr>
<form id="contact_form" method="post" action=""/>
{% csrf_token %}
{{ form | crispy }}
<input class="btn btn-primary pull-right " type="submit" name="submit" value="Submit the Message" />
</form>
</div>
</div>
{% endblock %}
What should I do?
You know what the product is from the id in the url, so there's no need to include it in your form.
To check that the product exists in the database, you can use the get_object_or_404 shortcut.
def product_inquiry(request, product_id):
product = get_object_or_404(ProductProfile, pk=product_id)
Then leave out 'product' from your list of fields, and remove the ModelChoiceField with hidden input widget.
class Customer_ps_contactForm(forms.ModelForm):
class Meta:
model = Customer_ps_contact
fields = ('name','email','subject','message','phone_number')
You are already setting the product when you save it, but it would be clearer to use the variable name instance to make it clearer what's going on. If you change your mail_customer_enquriy and thank_u_customer methods to use the instance instead of cleaned_data, then you won't have to do anything with form.cleaned_data.
if form.is_valid():
instance = form.save(commit=False)
instance.product = product
instance.save()
mail_customer_enquriy(instance) # Function to send email to admin
thank_u_customer(instance) # Function to send email to customers
return home(request)

Problem with forms and Photologue

I'm using Pinax to create a new project. For this project I needed to create a new app 'Business' which is much like Profiles but they wanted to keep everything seperate for Businesses.
I'm trying to have the admin be able to change the logo or "avatar" for the business profile. Im using the ImageModel class from Photologue to control the image upload, etc but I ran into a problem. When going through the form, the form goes through and redirects but the image doesn't actually get updated. When you go through the django admin, the image uploads fine.
If someone could take a look and see if something is missing, I've been staring at it for too long, so I need a fresh pair of eyes.
Business Models.py
class Business(models.Model):
name = models.CharField(verbose_name="Name", max_length=140)
desc = models.TextField(verbose_name="Description", null=True, blank=True)
bus_type = models.CharField(verbose_name="Business Type", choices=BUSINESS_TYPES, max_length=20)
location = models.CharField(_("location"), null=True, blank=True, max_length=200)
website = models.URLField(_("website"), null=True, blank=True, verify_exists=False)
created_by = models.ForeignKey(User, related_name="Created By")
admin = models.ManyToManyField(User, related_name="Admin User", null=True, blank=True)
followers = models.ManyToManyField(User, related_name="Followed by", null=True, blank=True)
date_added = models.DateField(verbose_name="Date Added")
class Meta:
verbose_name = "Business"
verbose_name_plural = "Businesses"
def __unicode__(self):
return self.name
class BusinessLogo(ImageModel):
business = models.ForeignKey(Business, related_name="Business Association")
My views.py
#login_required
def changeLogo(request, bus_id):
user = request.user
b = get_object_or_404(Business, pk = bus_id)
if request.method == 'POST':
form = ChangeLogoForm(request.POST, request.FILES, instance = b)
if form.is_valid():
biz_logo = form.save(commit=False)
biz_logo.save()
return HttpResponseRedirect('/')
else:
form = ChangeLogoForm()
return render_to_response('business/changelogo.html',
{'user': user, 'form':form, 'b':b}, context_instance=RequestContext(request))
Forms.py
class ChangeLogoForm(ModelForm):
class Meta:
model = BusinessLogo
def save(self, force_insert=False, force_update=False, commit=True):
f = super(ChangeLogoForm, self).save(commit=False)
if commit:
f.save()
print "form save method was called with commit TRUE"
return f
And finally my changelogo.html
...
{% block body %}
<h1>Change Logo</h1>
<form method="POST" action="" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Upload">
</form>
{% endblock %}
...
Thanks everyone, for taking a look.
Steve
The ChangeLogoForm's model is BusinessLogo, but when calling it's constructor you pass it a Business instance:
b = get_object_or_404(Business, pk = bus_id)
...
form = ChangeLogoForm(request.POST, request.FILES, instance = b)
(And you should probably use a OneToOneField field instead of ForeignKey)

Categories

Resources