I'm trying to make inline form by using inlineformset_factory but my Image object is not getting saved
models:
class Product(models.Model):
name = models.CharField(max_length=200)
category = models.ForeignKey(Category, on_delete=models.CASCADE)
availability = models.IntegerField()
price = models.DecimalField(max_digits=5, decimal_places=2)
def __str__(self):
return self.name
class Image(models.Model):
file = models.ImageField(upload_to="products_images/", default="static/default.png")
uploaded = models.DateTimeField(auto_now_add=True)
product = models.ForeignKey(Product, on_delete=models.CASCADE)
views:
def CreateNewProductView(request):
context = {}
ProductObj = None
form=ProductForm()
if request.method=='POST':
form = ProductForm(request.POST)
if form.is_valid():
ProductObj = form.save()
print('form is valid, product has been created')
else:
print("form is not valid")
ImageFormset = inlineformset_factory(Product, Image, fields=('file',), extra=1, can_delete=False)
if request.method=='POST':
formset = ImageFormset(request.POST, request.FILES, instance=ProductObj)
if formset.is_valid():
formset.save()
print('formset is valid, product has been created')
else:
print("formset is not valid")
else:
formset = ImageFormset(instance=ProductObj)
if form.is_valid() and formset.is_valid():
return redirect('home')
context = {'form': form, 'formset':formset}
return render(request, 'Ecommerce/test.html', context)
template test.html
{% extends 'base.html' %}
{% block content %}
<form method="POST" action="" id="image-form" style="padding-top:10px;">
{% csrf_token %}
{{form.as_p}}
{{formset}}
{{formset.management_form}}
<button type="submit">submit</button>
</form>
{% endblock content %}
In console I can see "formset is valid, product has been created"
When I printed (request.FILES) i saw <MultiValueDict: {}>. Should it be like that ? In django admin pannel there is no Image objects
What am I doing wrong ?
Add this to your HTML form tag to send files to the server:
enctype="multipart/form-data"
Easy to forget.
Your form will then look like:
<form method="POST" enctype="multipart/form-data" action="" id="image-form" style="padding-top:10px;">
...
Link to Django-docs
Related
URLS.py
urlpatterns = [
path('stock/update/<int:pk>/', views.StockUpdateView, name='stock-update'),
VIEWS.py
def StockUpdateView(request, pk):
stock = Stock.objects.get(id=pk)
form = StockForm(instance=stock)
if request.method == 'POST':
form = StockForm(request.POST, instance=stock)
if form.is_valid():
form.save()
return redirect('/inventory/stock')
context = {"form": form}
return render(request, 'inventory/update-stock.html', context)
TEMPLATE.html
<form action="" method="POST" class="row g-3">
<div class="col-auto">
<h6>Stock update form:</h6>
{% csrf_token %}
{% for field in form %}
<div class="form-control">
{{field}}
</div>
{% endfor %}
MODEL.py
class Stock(models.Model):
class Meta:
verbose_name_plural = "Stocks"
name = models.ForeignKey(Warehouse, on_delete=models.CASCADE)
product_id = models.ForeignKey('products.Product', on_delete=models.CASCADE)
quantity = models.IntegerField(default=0)
product_price = models.DecimalField(max_digits=19, decimal_places=2, default=0 ,validators=[MinValueValidator(0)])
def get_absolute_url(self):
return reverse("stock-update", args=[self.pk])
def __str__(self):
return f"{self.product_id} {self.quantity} {self.product_price}"
I have changed from using the {{ form }} tag to looping over the fields trying to get the name of the related table instead of the IDs.
There has a file upload page for upload file to a object by id in model. However, it shown MultiValueDictKeyError after submitted. I would appreciate if any help.
models.py:
class Order(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, blank=True, null=True)
items = models.ManyToManyField(OrderItem)
img_upload = models.FileField(upload_to='payment', null=True)
forms.py:
class Upload_File(forms.Form):
class Meta:
model = Order
fields = ('img_upload')
views.py:
def upload_page(request, id):
order = get_object_or_404(Order, id=id)
form = Upload_File(request.POST or None, request.FILES or None)
if request.method == 'POST':
order.img_upload = request.FILES['file']
if form.is_valid():
form.save()
messages.success(request, 'Succeed')
return redirect('user_info')
else:
form = Upload_File()
context = {
'form': form,
}
return render(request, 'upload.html', context)
html:
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
<input class="form-group" type="file" name="file">
<button class="form-group" type="submit">Submit</button>
</form>
I am working on a blog in Django and i am trying to update the image of my model BlogPost using a ModelForm.
Initialy , when creating the post, the image is being uploaded with no problems in media/posts. However , nothing happens when trying to update the existing image with another one ( or to add an image to a post already created without one).
I have found a solution online for this issue and that was to override the save() method for the model. I did that but still nothing seems to happen. Clearly, I am doing something wrong.
My code below:
views.py:
def blog_post_update_view(request,slug):
obj = get_object_or_404(BlogPost.objects.filter(user=request.user), slug=slug)
form = BlogPostModelForm(request.POST or None, instance=obj)
if form.is_valid():
form.save()
print(obj.image)
return redirect(obj.get_absolute_url()+"/detail/")
template_name = 'blog/form.html'
context = {"title": f"Update {obj.title}", "form": form}
return render(request, template_name, context)
models.py:
class BlogPost (models.Model):
# id = models.IntegerField() # pk
user= models.ForeignKey(User, default=1, null=True, on_delete=models.SET_NULL)
image=models.ImageField( upload_to='posts/',blank=True,null=True)
title=models.CharField(max_length=120)
slug= models.SlugField() # hello world -> hello-world
content=models.TextField(null=True,blank=True)
publish_date=models.DateTimeField(auto_now=False, auto_now_add=False, null=True, blank=True)
timestamp=models.DateTimeField(auto_now_add=True)
updated=models.DateTimeField(auto_now=True)
objects = BlogPostManager()
class Meta:
ordering = ['-publish_date', '-updated', '-timestamp']
def get_content_length(self):
return len(self.content)
def get_absolute_url(self):
return f"/blog/{self.slug}"
def get_edit_url(self):
return f"{self.get_absolute_url()}/edit"
def get_delete_url(self):
return f"{self.get_absolute_url()}/delete"
def save(self, *args, **kwargs):
try:
this = BlogPost.objects.get(id=self.id)
if this.image!= self.image:
this.image.delete()
except: pass
super(BlogPost, self).save(*args, **kwargs)
def __str__(self):
return self.title
forms.py:
class BlogPostModelForm(forms.ModelForm):
class Meta:
model = BlogPost
fields = ['title','image', 'slug', 'content', 'publish_date']
def clean_title(self, *args, **kwargs):
instance = self.instance
print('instance is: ',instance)
title = self.cleaned_data.get('title')
qs = BlogPost.objects.filter(title__iexact=title)
if instance is not None:
qs = qs.exclude(pk=instance.pk) # id=instance.id
if qs.exists():
raise forms.ValidationError("This title has already been used. Please try again.")
return title
blog/templates/form.html:
<!doctype html>
{% extends "blog/base.html" %}
{% load static %}
{% load crispy_forms_tags %}
{% block head_title %}
{{title}}
{% endblock %}
{% block content %}
{% if title %}
<h1>{{ title }}</h1>
{% endif %}
<form method='POST' enctype="multipart/form-data" action='.'> {% csrf_token %}
{{ form|crispy}}
<button type='submit'>Send</button>
</form>
{% endblock %}
your view should be like:
def blog_post_update_view(request,slug):
obj = get_object_or_404(BlogPost.objects.filter(user=request.user), slug=slug)
if request.method == "POST":
form = BlogPostModelForm(request.POST, request.FILES, instance=obj)
if form.is_valid():
form.save()
return redirect(obj.get_absolute_url()+"/detail/")
form = BlogPostModelForm(instance=obj)
template_name = 'blog/form.html'
context = {"title": f"Update {obj.title}", "form": form}
return render(request, template_name, context)
First some code:
models.py
class Findings(models.Model):
patient = models.ForeignKey(Profile, null=True, blank=True, on_delete=models.CASCADE)
finding_type = models.CharField(max_length=35, null=True)
upload = models.FileField(null=True, blank=True)
date_created = models.DateField(auto_now=True)
description = models.TextField(null=True, blank=True)
def __str__(self):
return self.finding_type
forms.py
class AddFindingForm(ModelForm):
class Meta:
model = Findings
fields = ('finding_type', 'description', 'upload', 'patient')
labels = {
'finding_type' : _('Rodzaj badania'),
'description': _('Opis'),
'upload': _('Dodaj plik'),
}
views.py
def add_finding(request):
form = AddFindingForm()
if request.method == 'POST':
form = UserProfileForm(request.POST, request.FILES)
if form.is_valid():
form = form.save(commit=False)
form.patient = request.user.profile
form.save()
return redirect('profile')
context = {'form': form}
return render(request, 'add_finding.html', context)
template
{% block content %}
<form method="POST" enctype="multipart/form-data" action="">
{% csrf_token %}
{{ form.as_p}}
<button type="submit"> WyĆlij </button>
</form>
{% endblock %}
So, everytime i'm trying to submit a filled form it displays another form to create new Profile, even if i'm setting patient manually.
The empty form it's displaying is on the same url.
I have no idea why it's doing that...
You are submitting your request.POST data to wrong form. Doing this user's submitted data never gets into AddFindingForm() instead it should be,
def add_finding(request):
form = AddFindingForm()
if request.method == 'POST':
form = AddFindingForm(request.POST, request.FILES) # Change Here
if form.is_valid():
form = form.save(commit=False)
form.patient = request.user.profile
form.save()
return redirect('profile')
context = {'form': form}
return render(request, 'add_finding.html', context)
I created a form to update a User's profile, however when I run it, there are no errors, but when I try to open up the page, the header appears but the UpdateBioForm does not appear. Secondly, I was wondering how you would create a large textbox to store someone's biography.
Models.py
class UserProfile(models.Model):
user = models.OneToOneField(User)
biography = models.CharField(max_length = 255, default = '')
city = models.CharField(max_length=100, default = '')
website = models.URLField(default='')
image = models.ImageField(upload_to='profile_image', blank=True)
def setdefault(self, default_path='/profile_image/Default.jpg'):
if self.image:
return self.image
return default_path
def __str__(self):
return self.user.username
Forms.Py
class UpdateBioForm(forms.ModelForm):
class Meta:
model = UserProfile
fields = (
'biography',
'city',
'website'
)
def save(self, commit=True):
savedBio = super(UpdateBioForm, self).save(commit=False)
savedBio.biography = self.cleaned_data['biography']
savedBio.city = self.cleaned_data['city']
savedBio.website = self.cleaned_data['website']
if commit:
savedBio.save()
return savedBio
Views.py
def update_bio(request):
if request.method == 'POST':
form = UpdateBioForm(request.POST, instance=request.user)
if form.is_valid():
form.save()
return redirect('/')
else:
form = UpdateBioForm(instance=request.user)
args = {'form':form}
return render(request, 'accounts/update_bio.html')
urls.py
url(r'^profile/updatebio/$',views.update_bio, name='update_bio'),
update_bio.html
{% extends 'base.html' %}
{% block body %}
<div class="container">
<h1>Update Biography</h1>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Submit</button>
</form>
</div>
{% endblock %}
You are not passing any context to your render() method - you define args but don't do anything with that variable. Change it to:
args = {'form':form}
return render(request, 'accounts/update_bio.html', context=args) # <-- You're missing context