Populating Field in Form with Images in Django - python

I'm trying to populate a field with images from a model in Django. The idea is that the user will enter the name of their product, then ultimately an API with google images will look that up and populate a field on the next page with a couple images to select.
At this stage, I'm just trying to get a field on the form to show multiple images for the user to select and I'm having a hard time. Here's some of my code, any input is helpful. I know there is a lot out there around this topic and I've looked through a lot but I'm still stuck. My most recent attempt was to create a custom Widget, I'm really open to any solution that will work.
I'm really not a Django/Python wizard so bear with me :) Thank you!
Models.py
class ProductImage(models.Model):
imageId = models.AutoField(auto_created=True, primary_key=True)
image = models.ImageField(upload_to='images',null=True,blank=True)
def __str__(self):
return str(self.image)
class Item(models.Model):
itemId = models.AutoField(auto_created=True, primary_key=True)
itemName = models.CharField(
"Name",
max_length=1024,
)
category = models.ForeignKey(Category,
on_delete=models.CASCADE,
related_name='category'
)
itemImage = models.ForeignKey(ProductImage,
on_delete=models.CASCADE,
related_name='photo',
default="",
)
itemOwner = models.ForeignKey(Customer,
on_delete=models.CASCADE,
related_name='my_items'
)
itemAvaialable = models.BooleanField()
costPerItem = models.IntegerField(verbose_name='Cost per Item (USD)')
itemDescription = models.TextField(null=True, blank=True)
itemAddedDate = models.DateField(auto_now_add=True)
asin = models.CharField(null=True, blank=True, max_length=10)
forms.py
class ImageCreationForm(forms.ModelForm):
class Meta:
model = ProductImage
fields = ('image',)
def clean_itemImage(self):
itemImage = self.cleaned_data['itemImage']
valid_extensions = ['jpg', 'jpeg']
extension = itemImage.rsplit('.', 1)[1].lower()
if extension not in valid_extensions:
raise forms.ValidationError('The given product Image file does not ' \
'match valid image extensions.')
return itemImage
class ItemCreationForm(forms.ModelForm):
class Meta:
model = Item
fields = '__all__'
widgets = {
'itemAddedDate': forms.HiddenInput,
}
Views.py
class AddImageView(LoginRequiredMixin,CreateView):
model = ProductImage
template_name = 'addImage.html'
fields = ('image',)
def form_valid(self, form):
form.is_valid()
form.instance.itemOwner = self.request.user
return super().form_valid(form)
def get_success_url(self):
return reverse('RentalApp:my_products')
class AddProductView(LoginRequiredMixin, CreateView):
model = Item
template_name = 'addProduct.html'
image = forms.FileField(required=False)
fields = ('itemName',
'category',
'itemImage',
'itemAvaialable',
'costPerItem',
'itemDescription')
login_url = '/users/login/'
def form_valid(self, form):
form.fields["itemImage"].queryset = ProductImage.objects.all()
form.is_valid()
form.instance.itemOwner = self.request.user
return super().form_valid(form)
def get_success_url(self):
return reverse('RentalApp:my_products')
Widgets.py
class ImageWidget(forms.widgets.Widget):
def render(self, name, value, attrs=None, **kwargs):
html = Template("""<img src="$link"/>""")
return mark_safe(html.substitute(link=value))
Serializers.py
class ProductImageSerializer(serializers.ModelSerializer):
product_image = serializers.SerializerMethodField()
class Meta:
model = ProductImage
fields = ('image')
class ProductImageRequirementSerializer(serializers.ModelSerializer):
class Meta:
model = ProductImage
fields = ('image')
class ProductSerializer(serializers.ModelSerializer):
Product_requirement = serializers.SlugRelatedField(many=True,read_only=True,slug_field='text')
club_image = ProductImageSerializer(many=True)
class Meta:
model = ProductImage
fields = ('image')
Template for adding a product:
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<div id="login">
<h5 class="text-center pt-5">Add Product</h5>
<div id="login-row" class="row justify-content-center align-items-center">
<div id="login-column" class="col-md-6">
<div id="login-box" class="col-md-12">
<form action="" method="post" id="login-form" enctype="multipart/form-data" class="form">{% csrf_token %}
{{ form|crispy }}
<br>
<button class="btn btn-success ml-2" type="submit">Save</button>
<a href="{% url 'RentalApp:my_products' %}" class="btn btn-secondary ml-2">
Cancel</a>
</form>
</div>
</div>
</div>
</div>
{% endblock content %}

Related

How I can upload file in django?

I'm trying to upload file in a specific folder and store its path in DB through forms(CBV), but it doesn't work!!
this is my code (forms, models, views, template).
I'm selecting the file through forms then I submit the form, but it doesn't submit.
#views.py
class PostCreateView(LoginRequiredMixin, CreateView):
model = Post
# fields = ['title', 'content']
success_url = reverse_lazy('blog/new_post.html')
template_name = 'blog/new_post.html'
form_class = PostCreateForm
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST, request.FILES)
if form.is_valid():
form.save()
return redirect(self.success_url)
else:
return render(request, self.template_name, {'form': form})
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
#model.py
class Post(models.Model):
title = models.CharField(max_length=1000)
content = models.TextField()
xml_file = models.FileField(null=True, upload_to='xml_files')
rate = models.FloatField(null=True, blank=True, default=None)
post_date = models.DateTimeField(default=timezone.now)
post_update = models.DateTimeField(auto_now=True)
author = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.title
def get_absolute_url(self):
# return '/detail/{}'.format(self.pk)
return reverse('detail', args=[self.pk])
class Meta:
ordering = ('-post_date', )
#forms.py
class PostCreateForm(forms.ModelForm):
title = forms.CharField( max_length=1000)
content = forms.CharField(widget=forms.Textarea(
attrs={'rows': 15, 'placeholder': 'write here'}
), max_length=50000)
xml_file = forms.FileField(label='upload file')
class Meta:
model = Post
fields = ['title', 'content', 'xml_file', ]
#new_post.html
{% block content %}
{% load crispy_forms_tags %}
<div class="border p-4 mb-5">
<legend class="border-bottom pb-1 mb-3">new post</legend>
<form method="POST">
{% csrf_token %}
{{form|crispy}}
<input class="btn btn-secondary mt-4" type="submit" value="post">
</form>
</div>
{% endblock content %}
When you are uploading media like what you've got, it is necessary to add the following part to your <form>:
enctype=multipart/form-data

When I submit this form, neither data is saved onto database nor giving any error in my django project

models.py
here is my model
class Load_post(models.Model):
user = models.ForeignKey(get_user_model(),on_delete=models.CASCADE)
pick_up_station = models.CharField(max_length=150)
destination_station = models.CharField(max_length=150)
sender_name = models.CharField(max_length=150)
phone_number = PhoneNumberField(null=False , blank=False , unique=True)
receiver_name = models.CharField(max_length=150)
sending_item = models.CharField(max_length=150)
weight = models.CharField(max_length=150)
metric_unit = models.CharField(max_length=30, default='SOME STRING')
quantity = models.PositiveIntegerField(default=1)
requested_shiiping_price = models.PositiveIntegerField()
pick_up_time = models.DateField()
drop_time = models.DateField()
paid_by = models.CharField(max_length=150)
created_at = models.DateTimeField(auto_now=True)
published_date = models.DateField(blank=True, null=True)
def __str__(self):
return self.user.username
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
def publish(self):
self.published_date = timezone.now()
self.save()
def get_absolute_url(self):
return reverse('local')
class Meta:
ordering = ["-created_at"]
unique_together = ["sender_name", "receiver_name"]
please check the phone number
forms.py
this is form.py
class Loader_post_form(forms.ModelForm):
phone_number = PhoneNumberField()
metric_unit = forms.ChoiceField(choices=UNIT, required=True)
class Meta:
model = Load_post
fields = ("pick_up_station", "destination_station",
"sender_name", "phone_number", "receiver_name",
"sending_item","image_of_load","weight","metric_unit",
"quantity","requested_shiiping_price","pick_up_time",
"drop_time","paid_by")
views.py
This is my views.py
absolute URL used in models already
class Loader_post_view(CreateView, LoginRequiredMixin):
login_url = 'Driver/login/'
form_class = forms.Loader_post_form
model = Loader_Signup
template_name = "Driver/post.html"
def form_valid(self,form):
form.instance.user = self.request.user
form.save()
return super(Loader_post_view,self).form_valid(form)
post.html
this is html page (template)
{% extends "Driver/base.html" %}
{% block content %}
<h1>create a post</h1>
{% csrf_token %}
{{form}}
<button type="submit">submit</button>
{% endblock content %}
this is html code
how to add it to the database
and I cannot see any error in my forms
thank you
am working on driver and client-side project
From what I see you html template cannot submit the form because you ae missing the <form> tags - if you do not have them hidden in your base.html.
Your html template should be something like this:
{% extends "Driver/base.html" %}
{% block content %}
<h1>create a post</h1>
<form method="POST">
{% csrf_token %}
{{form}}
<button type="submit">submit</button>
</form>
{% endblock content %}
The {{ form }} renders the form with all the inputs but does not create the tags needed for html forms.
In addition there are some other errors in the code you posted.
In your view the model you defined is called Loader_Signup, however the model you posted is Load_post. Either you posted the wrong model or you declared the wrong model in your view.
In your form one field is called image_of_load, however, this field is not part of you model.
In your model you have got a field called phone_number, you are defining a field with the same name in your form. The field in your form has got no connection to your model so take it out.
Unfortunately you are not providing any details about your PhoneNumberField so this cannot be checked.

How to have a Form from another Model inside a DetailView in Django?

I'm working with Django and what I want to do is to have a DetailView of Posts, and inside that detail view I want a comments section with a form for posts comments. When I load the detail view it doesn't show me the form of Comments I'm using Class Based Views for the Detail of the form.
My models.py looks like this:
class Post(models.Model):
author = models.ForeignKey('auth.User', on_delete=models.CASCADE)
title = models.CharField(max_length = 200)
text = models.TextField()
created_date = models.DateTimeField(default = timezone.now)
likes = models.IntegerField(default=0)
tags = models.CharField(max_length = 50, default = '' )
def get_absolute_url(self):
return reverse('blog:post_list')
def __str__(self):
return self.title
class Comments(models.Model):
post = models.ForeignKey('blog.Post', related_name='comments', on_delete=models.CASCADE)
text = models.TextField()
created_date = models.DateTimeField(default = timezone.now)
The views.py looks like this:
class PostDetailView(DetailView):
form_class = CommentsForm
model = Post
The form looks like this:
class CommentsForm(forms.ModelForm):
class Meta:
model = Comments
fields = ('text',)
widgets = {
'text' : forms.Textarea(attrs={'class':'comment-textarea'})
}
And the comments_form.html looks like this:
<div class="container">
<div class="row">
<div class="col">
<h1>Estoy siendo insertado</h1>
<form action="" method="POST">
{%csrf_token%}
{{ form.as_p }}
<input type="submit" class="btn mt-2 btn-comments" value="Comment">
</form>
</div>
</div>
</div>
That's because DetailView does not handle the form_class. You have a few options here:
provide the form via get_context_data
apply the FormMixin on the DetailView. (Can be found under django.view.generic.edit)
Context data example:
def get_context_data(self, **kwargs):
context = super(PostDetailView, self).get_context_data(**kwargs)
context['comments_form'] = CommentsForm()
return context

How can I display a model and a form under one class in views.py in Django?

I am trying to display the data in details template that I would obtain using AgentForm and I am also trying to add a Matrix1Form that will be unique to each agent, and that matrix1form would be displayed in details.html.
Here is my views.py and if I try to display the Matrix1Form, the data from Agent model doesn't get displayed and vice versa, if I want to display an agent, I have to comment out the Matrix1Form. There are no errors popping up so far. The data just don't get displayed.
views.py
class AgentDetailsView(generic.DetailView):
template_name = 'User/AgentDetails.html'
class Meta:
model = Agent
def get(self, request, *args, **kwargs):
matrix1form = Matrix1Form()
return render(request, self.template_name, {'matrix1form':
matrix1form})
forms.py
class AgentForm(forms.ModelForm):
prefix = 'agentform'
class Meta:
model = Agent
fields = '__all__'
class Matrix1Form(forms.ModelForm):
prefix = 'matrix1form'
class Meta:
model = Matrix1
fields = '__all__'
models.py
class Agent(models.Model):
AgencyName = models.CharField(blank=True, max_length = 50,
verbose_name="Agency Name")
OtherAgencyName = models.CharField(max_length=50, blank=True)
FirstName = models.CharField(max_length=50, null=True)
LastName = models.CharField(max_length=50, null=True)
details.html
<ul>
<li>AgencyName: {{agent.AgencyName}} </li>
<li>OtherAgencyName: {{agent.OtherAgencyName}} </li>
<li>First Name: {{agent.FirstName}} </li>
<li>Last Name: {{agent.LastName}} </li>
</ul>
<form class="form-horizontal" action="" method="post"
enctype="multipart/form-data">
{% csrf_token %}
<table>
{{ matrix1form.as_table }}
</table>
</form>
if i understand you correct, you need to override get_context_data for example:
class AgentDetailsView(generic.DetailView):
template_name = 'User/AgentDetails.html'
class Meta:
model = Agent
def get_context_data(self, **kwargs):
# ^^^^^^^^^^^^^^
context = super(AgentDetailsView, self).get_context_data(**kwargs)
matrix1form = Matrix1Form()
context['matrix1form'] = matrix1form
return context

Django passing foreign key to view

Hi Perhaps someone could point me in the right direction, i am learning Django through Tango with Django and i am also following along with the official Django tutorials as well as creating my own Django app for purchase orders.
I need to understand how I can access the Foreign key details of another Model and save it using forms. Basically my app has Orders and Suppliers when creating an order I can get the supplier foreign key options to appear on the form but when I save it I also want to save with the suppier_name into the orders table currently it just saves with the supplier_id, I have searched through many examples of different scenarios but just can't understand it thanks.
view.py
def add_order(request):
if request.method == 'POST':
form = OrderForm(request.POST)
if form.is_valid():
form.save(commit=True)
return orders(request)
else:
print(form.errors)
else:
form = OrderForm()
context_dict = {'form':form}
return render(
request,
'purchaseorders/add_order.html',
context_dict
)
model.py
# Create your models here.
class Supplier(models.Model):
supplier_code = models.CharField(max_length=10)
supplier_name = models.CharField(
max_length=100,
unique=True
)
supplier_email = models.EmailField(max_length=100)
supplier_website = models.URLField(max_length=100)
slug = models.SlugField(unique=True)
def save(self, *args, **kwargs):
self.slug = slugify(self.supplier_name)
super(Supplier,self).save(*args, **kwargs)
def __unicode__(self):
return self.supplier_name
def __str__(self):
return self.supplier_name
class Meta:
verbose_name_plural = "Suppliers"
class Order(models.Model):
supplier = models.ForeignKey(Supplier)
po_number = models.IntegerField(default=0)
ordered_by = models.CharField(max_length=50)
order_date = models.DateTimeField()
supplier_name = models.CharField(max_length=50)
net_value = models.DecimalField(
decimal_places=2,
max_digits=10
)
class Meta:
verbose_name_plural = "Orders"
def __unicode__(self):
return self.po_number
forms.py
from django import forms
from PurchaseOrders.models import Supplier, Order
class SupplierForm(forms.ModelForm):
supplier_code = forms.CharField(
max_length=10,
help_text="Please enter a unique code"
)
supplier_name = forms.CharField(
max_length=100,
help_text="Please enter the Suppliers full name"
)
supplier_email = forms.EmailField(
max_length=100,
help_text="Please enter a email address"
)
supplier_website = forms.URLField(
max_length=100,
help_text="Please enter a website"
)
slug = forms.CharField(
widget=forms.HiddenInput(),
required=False
)
# an inline class to provide additional information on the form
class Meta:
# provide an association between the ModelForm and model
model = Supplier
fields = (
'supplier_code', 'supplier_name',
'supplier_email', 'supplier_website'
)
class OrderForm(forms.ModelForm):
#list all form details except the Foreignkey connection
po_number = forms.IntegerField(
help_text="please enter a PO Number"
)
ordered_by = forms.CharField(
max_length=50,
help_text="please enter your name"
)
order_date = forms.DateTimeField(
help_text="please enter a date of order"
)
#supplier_name = forms.ModelChoiceField(
queryset=Supplier.objects.all()
)
net_value = forms.DecimalField(
decimal_places=2,
max_digits=10,
help_text="please enter a net amount"
)
class Meta:
# provide an association between the ModelForm and model
model = Order
html
{% load staticfiles %} <!-- New line -->
<html>
<head>
<title>Purchase Orders</title>
</head>
<body>
<img src="{% static "purchaseorders/images/po_icon.png" %}"
alt="PO icon" />
<h1>Add a Order</h1>
<form id="order_form" method="post"
action="/PurchaseOrders/add_order/{{ supplier }}">
{% csrf_token %}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
<ul style="list-style-type:none ">
{% for field in form.visible_fields %}
<li></li>
{{ field.errors }}
{{ field.help_text }}
<li>{{ field }}</li>
{% endfor %}
</ul>
<input type="submit" name="submit" value="Add Order" />
</form>
</body>
</html>
To start with the question as-asked, you could capture this data in the model's save() method:
class Order(models.Model):
[...]
def save(self, *args, **kw):
if self.supplier_id is not None:
self.supplier_name = self.supplier.supplier_name
super(Order, self).save(*args, **kw)
HOWEVER, although there are some cases where the above might be correct (such as if supplier name is expected to change), it is much more typical to simply access a related field through the existing relationship, ex:
myorder.supplier.supplier_name

Categories