I want to create a charfield input in a django form that has suggestions. Essentially I want a choice field that also allows you to write your own value if needed. In other words a hybrid between a charfield and choice field input. Any suggestions on how to achieve this ?
forms.py
class PDFClassificationForm(forms.ModelForm):
nature = forms.CharField(required=False)
class Meta:
model = Documents
fields = [,
'nature',]
labels = {,,
'nature':'Nature/Concerne:',
}
def __init__(self, uuid_pdf, *args, **kwargs):
super(PDFClassificationForm, self).__init__(*args, **kwargs)
nature_choices= Archivagerecurrencelibelle.objects.filter(Q(id_emetteur=Documents.objects.get(uuid=uuid_pdf).id_emetteur) & Q(source="Nature")).values_list('concerne','concerne')
self.fields['nature'].choices = nature_choices
views.py
class DocumentsArchiveUpdateView(UpdateView):
model = Documents
template_name = 'documents/documents_read_write.html'
form_class = PDFClassificationForm
success_url = lazy(reverse, str)("documents_archive_list")
def get_context_data(self, *args, **kwargs):
# Call the base implementation first to get a context
context = super(DocumentsArchiveUpdateView, self).get_context_data(*args, **kwargs)
id_customer = Documents.objects.get(uuid=self.kwargs['uuid_pdf']).id_customer
context["document_owner"] = Entity.objects.get(id=id_customer)
context["uuid_contrat"] = self.kwargs['uuid_contrat']
context["uuid_group"] = self.kwargs['uuid_group']
context["uuid_pdf"] = self.kwargs['uuid_pdf']
return context
def form_valid(self, form):
obj = form.save(commit=False)
obj.id_document_status = DocumentStatusLst.objects.get(id=3)
obj.save()
return super().form_valid(form)
def get_form_kwargs(self,) :
uuid_pdf = self.kwargs['uuid_pdf']
kwargs = super(DocumentsArchiveUpdateView, self).get_form_kwargs()
kwargs["uuid_pdf"] = uuid_pdf
return kwargs
documents_read_write.html
{% extends 'layout.html' %}
{% load crispy_forms_tags %}
<form action = "{%url 'jnt_customer_create' uuid_contrat uuid_group pdfid%}" method="POST" enctype="multipart/form-data">
<!-- Security token -->
{% csrf_token %}
<!-- Using the formset -->
{{ form |crispy}}
<button type="submit" name="btnform1" class="btn btn-primary">Enregistrer</button>
</form>
{% endblock %}
----------- models.py -------
from django.db import models
class EmployeeModel(models.Model):
name = models.CharField(max_length=255)
age = models.PositiveIntegerField()
city = models.CharField(max_length=255)
def __str__(self):
return self.name
----------- form.py -------
class EmployeeFrom(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(EmployeeFrom, self).__init__(*args, **kwargs)
self.fields['city'].widget = forms.Select(choices = CityModel.objects.values_list('name','name'))
class Meta:
model = EmployeeModel
fields = "__all__"
widgets = {
'name':forms.TextInput(attrs={'class':'form-control'}),
'age':forms.NumberInput(attrs={'class':'form-control'}),
}
----------- Html code for form -----------
<div class="modal-body">
<form action="" method="POST">
{% csrf_token %}
<div class="mb-3">
<label class="form-label">{{form.name.label}}</label>
{{form.name}}
</div>
<div class="mb-3">
<label class="form-label">{{form.age.label}}</label>
{{form.age}}
</div>
<div class="mb-3">
<label class="form-label">{{form.city.label}}</label>
<input class="form-select" placeholder="--- Select city ---" name="city" type="text" list="cities">
<datalist id="cities">
{% for i in form.city %}
<option>{{i}}</option>
{% endfor %}
</datalist>
</div>
<button class="btn btn-primary" type="submit">Add Employee</button>
</form>
</div>
========= Ouput ===============
all cities
after entering keyword
==== last output ==============
You might try with this https://github.com/jazzband/django-taggit
I used it in a similar use case, you can pass a whitelist of "tags" as suggestion or populate it with already used tags, while still allowing the creation of new values
Related
Here is my models, views, forms and template. I need to save the document uploaded to database using def form_valid() method.
models.py:
def upload_qual_document_file_name(instance, filename):
new_name = '%s.%s' % (uuid.uuid4(), filename.split('.')[-1])
return 'core/upload_documents' + new_name
class Qual(models.Model):
name = models.CharField(max_length=100,default=None,null=False, blank=False)
created_at = models.DateTimeField(auto_now_add=True)
document = models.FileField(upload_to=upload_qual_document_file_name, blank=True, null=True)
views.py:
class QualUpdateView(CustomAdminMixin, UpdateView):
model = Qual
template_name = 'core/qual_form.django.html'
form_class = QualUpdateForm
context_object_name = 'qualification'
def get_initial(self):
initial = super(QualUpdateView, self).get_initial()
initial['client'] = self.request.user.client
return initial
def get_queryset(self):
return super(QualView, self).get_queryset().filter(client=self.request.user.client)
def form_valid(self, form):
self.object = form.save(commit=False)
self.object.client = self.request.user.client
try:
self.object.save()
except IntegrityError:
messages.error(self.request, 'Please check the complience updated.')
return redirect(self.get_success_url())
messages.success(self.request, 'Complience successfully updated.')
return redirect(self.get_success_url())
def get_success_url(self):
# messages.success(self.request, 'Qualification was successfully updated.')
return reverse('qualification_list')
forms.py:
class QualUpdateForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.client = kwargs.get("initial", {}).get("client")
super(QualUpdateForm, self).__init__(*args, **kwargs)
def clean_name(self):
client = self.client
name = self.cleaned_data.get('name')
if name:
try:
data = Qual.objects.exclude(is_deleted=True).get(name=name,client_id=client)
except Qual.DoesNotExist:
pass
else:
pass
return name
class Meta:
model = Qual
fields = ['name','document']
widgets = {
'worker_renewal': SwitchCheckbox,
}
template:
<form method="post" action="">
{% csrf_token %}
<fieldset class="add">
<legend> </legend>
<fieldset>
{% for field in form.visible_fields %}
<div class="control-group">
<label class="control-label pull-left" for="{{ field.auto_id }}">{{ field.label }}</label>
<div class="controls">
{{ field }}
</div> <!--/controls-->
<p>{{ field.help_text }} </p>
</div> <!--/control-group-->
{% endfor %}
</div>
</div>
</fieldset>
</fieldset>
<div id="form-buttons-container" class="form-actions">
<div class="controls">
<input type="submit" class="btn btn-inverse" value="Save Compliance">
</div> <!--/form-actions-->
</div>
</form>
How can I save my file uploaded through template using django modelforms and classbased views?
I have reviewed many of the questions related to this topic, in this forum and in Spanish, I have followed the steps, and it does not work for me, on something that seems so simple, at first. I have Django 2.2.6 with a form that needs the selected value of a Select field, which is not in the model, and acquires a list of values (tuples of two) created from the view.
Upon entering the form, throw this error: "__init __ () received an unexpected keyword argument 'carpetas'", in the FotoArtForm class, in the super () line.
This is my code:
models.py
class FotoArt(models.Model):
nombre = models.CharField(max_length=50)
foto = models.ImageField(upload_to='fotos/articulos/', null=True, blank=True)
class Meta:
ordering = ['nombre']
verbose_name = _('Foto Artículo')
verbose_name_plural = _('Fotos Artículos')
def __str__(self):
return self.nombre
def get_absolute_url(self):
return reverse('detalle-fotoArt', args=[str(self.id)])
views.py
class FotoArtActualizar(LoginRequiredMixin, UpdateView):
model = FotoArt
form_class = FotoArtForm
Ruta = os.path.join(MEDIA_ROOT, 'fotos', 'articulos')
def get_form_kwargs(self):
kwargs = super(FotoArtActualizar, self).get_form_kwargs()
kwargs['carpetas'] = self.get_folders_list(self.Ruta)
return kwargs
def get_folders_list(self, ruta):
foldersList = []
for _, listaSubDir, _ in os.walk(ruta):
for dName in listaSubDir:
foldersList.append((dName, dName))
return foldersList
forms.py
class FotoArtForm(forms.ModelForm):
guardar_en_carpeta = forms.ChoiceField(choices=(), required=True)
def __init__(self, *args, **kwargs):
super(FotoArtForm, self).__init__(*args, **kwargs)
self.foldersList = kwargs.pop('carpetas', None)
self.fields['guardar_en_carpeta'].choices = self.foldersList
class Meta:
model = FotoArt
fields = ['nombre', 'guardar_en_carpeta', 'foto']
fotoArt_form.html
{% extends 'catalogo/base.html' %}
{% block content %}
<h2>Crear/Actualizar Fotos Artículos</h2>
<hr/>
<form action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.non_field_errors }}
<div class="input-group mb-3">
<div class="input-group-prepend">
<label class="input-group-text font-weight-bold" for="inputCarpeta">Guardar en carpeta</label>
</div>
{{ form.guardar_en_carpeta.errors }}
{{ form.guardar_en_carpeta }}
</div>
{{ form.foto.errors }}
<strong>{{ form.foto.label_tag }}</strong>
{{ form.foto }}
<div class="form-group row my-2">
<label for="nombreFoto" class="col-sm-2 col-form-label"><strong>Nombre</strong></label>
{{ form.nombre.errors }}
<div class="col-sm-10">
{{ form.nombre }}
</div>
<input type="submit" value="Enviar" />
</div>
</form>
{% endblock %}
Any idea why I get this error?
Perhaps, you should make another approach to pass the list of folders (choices) to the field save_in_folder of the form; instead of overwriting the get_form_kwargs () method, I could overwrite the get_context_data () method and pass it a context ['folders_list'], but then I can't control the value of the save_in_folder selector to use it in another field.
You have not defined the carpetas field in the FotoArtForm.Meta.fields but you're passing the data for that via form hence the error from the FotoArtForm initializer as carpetas is not a valid named argument.
You need to reverse the statements to pop-out the capetas named argument so that the ModelForm.__init__ is called without it:
class FotoArtForm(forms.ModelForm):
...
...
def __init__(self, *args, **kwargs):
self.foldersList = kwargs.pop('carpetas', None)
super(FotoArtForm, self).__init__(*args, **kwargs)
EDITS AVAILABLE BELOW!
My goal:
Category1
----Option1
----Option2
--Option3
Category2
----Option1
----Option2
etc.
I have a parent model (Venue) and a child model (Amenity). A venue can have many amenities.
while configuring my initial data and presenting it with {{form.as_p}} everything works as expected.
But when I try to render my own custom form, so that I can apply a loop, It doesn't pre-populate them.
Here is my template:
<form method="POST" class="ui form">
{% csrf_token %}
{% for category in categories %}
<h4 class="ui horizontal divider header">
<i class="list icon"></i>
{{category.category}}
</h4>
<p class="ui center aligned text"><u>{{category.description}}</u></p>
{% for amenity in category.amenity_set.all %}
<div class="inline field">
<label for="choices_{{amenity.id}}"></label>
<div class="ui checkbox">
<input id="choices_{{amenity.id}}" type="checkbox" value="{{amenity.id}}" name="choices">
<label><span data-tooltip="{{amenity.description}}" data-position="top left">{{amenity}}</span></label>
</div>
</div>
{% endfor %}
{% endfor %}
<button type="submit" name="submit" class="ui button primary">Next</button>
</form>
my ModelForm:
class AmenitiesForm(ModelForm):
class Meta:
model = Venue
fields = ('choices',)
choices = forms.ModelMultipleChoiceField(Amenity.objects.all(), widget=forms.CheckboxSelectMultiple,)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if kwargs.get('instance'):
initial = kwargs.setdefault('initial', {})
initial['choices'] = [c.pk for c in kwargs['instance'].amenity_set.all()]
forms.ModelForm.__init__(self, *args, **kwargs)
def save(self, commit=True):
instance = forms.ModelForm.save(self)
instance.amenity_set.clear()
instance.amenity_set.add(*self.cleaned_data['choices'])
return instance
and my views.py:
class AddAmenitiesView(LoginRequiredMixin, CreateView):
"""
AddAmenitiesView is the view that prompts the user to select the amenities of their venue.
"""
model = Venue
form_class = AmenitiesForm
template_name = 'venues/add_amenities.html'
def parent_venue(self):
"""
returns the parent_venue based on the kwargs
:return:
"""
parent_venue = Venue.objects.get(id=self.kwargs["venue_id"])
return parent_venue
def get_initial(self):
initial = super().get_initial()
initial['choices'] = self.parent_venue().amenity_set.all()
return initial
def form_valid(self, form):
venue = Venue.objects.get(id=self.kwargs['venue_id'])
form.instance = venue
# form.instance.owner = self.request.user
return super().form_valid(form)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["parent_venue"] = self.parent_venue()
context["categories"] = AmenitiesCategory.objects.all()
return context
def get_success_url(self):
return reverse('add-amenities', kwargs={'venue_id': self.object.id,})
I suppose it has to do with my template since rendering the form normally, it does prepopulate the model.
Thank you for taking the time!
EDIT:
With Raydel Miranda's answer below I managed to edit the templates for how the form gets presented:
forms.py:
class CustomAmenitiesSelectMultiple(CheckboxSelectMultiple):
"""
CheckboxSelectMultiple Parent: https://docs.djangoproject.com/en/2.1/_modules/django/forms/widgets/#CheckboxSelectMultiple
checkbox_select.html: https://github.com/django/django/blob/master/django/forms/templates/django/forms/widgets/checkbox_select.html
multiple_input.html: https://github.com/django/django/blob/master/django/forms/templates/django/forms/widgets/multiple_input.html
checkbox_option.html: https://github.com/django/django/blob/master/django/forms/templates/django/forms/widgets/checkbox_option.html
input_option.html: https://github.com/django/django/blob/master/django/forms/templates/django/forms/widgets/input_option.html
"""
template_name = "forms/widgets/custom_checkbox_select.html"
option_template_name = 'forms/widgets/custom_checkbox_option.html'
class AmenitiesForm(ModelForm):
class Meta:
model = Venue
fields = ('choices',)
choices = forms.ModelMultipleChoiceField(Amenity.objects.all(), widget=CustomAmenitiesSelectMultiple,)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if kwargs.get('instance'):
initial = kwargs.setdefault('initial', {})
initial['choices'] = [c.pk for c in kwargs['instance'].amenity_set.all()]
forms.ModelForm.__init__(self, *args, **kwargs)
def save(self, commit=True):
instance = forms.ModelForm.save(self)
instance.amenity_set.clear()
instance.amenity_set.add(*self.cleaned_data['choices'])
return instance
custom_checkbox_select.html:
{% with id=widget.attrs.id %}
<div class="inline field">
<div {% if id %} id="{{ id }}" {% endif %}{% if widget.attrs.class %} class="{{ widget.attrs.class }}" {% endif %}>
{% for group, options, index in widget.optgroups %}{% if group %}
<div>
{{ group }}
<div>
{% if id %} id="{{ id }}_{{ index }}" {% endif %}>{% endif %}{% for option in options %}
<div class="checkbox">{% include option.template_name with widget=option %}</div>
{% endfor %}{% if group %}
</div>
</div>
{% endif %}{% endfor %}
</div>
</div>
{% endwith %}
custom_checkbox_option.html :
<label{% if widget.attrs.id %} for="{{ widget.attrs.id }}"{% endif %}>{% endif %}{% include "django/forms/widgets/input.html" %}{% if widget.wrap_label %} {{ widget.label }}</label>
As requested, also my models.py:
class TimeStampedModel(models.Model):
"""
An abstract base class model that provides self-updating
"created" and "modified" fields.
"""
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
class Meta:
abstract = True
class VenueType(TimeStampedModel):
type = models.CharField(max_length=250)
description = models.TextField()
def __str__(self):
return self.type
class Venue(TimeStampedModel):
owner = models.ForeignKey(User, on_delete=models.CASCADE)
name = models.CharField(max_length=250)
type = models.ForeignKey(VenueType, on_delete=models.CASCADE)
total_capacity = models.PositiveIntegerField(default=0)
description = models.TextField(blank=False)
contact_number = PhoneNumberField(blank=True)
contact_email = models.EmailField(blank=True)
published = models.BooleanField(default=False)
def __str__(self):
return self.name
class AmenitiesCategory(TimeStampedModel):
category = models.CharField(max_length=250)
description = models.TextField()
def __str__(self):
return self.category
class Amenity(TimeStampedModel):
category = models.ForeignKey(AmenitiesCategory, on_delete=models.CASCADE)
venues = models.ManyToManyField(Venue, blank=True)
space = models.ManyToManyField(Space, blank=True)
name = models.CharField(max_length=250)
description = models.TextField()
def __str__(self):
return self.name
class Meta:
ordering = ['category']
You said while configuring my initial data and presenting it with {{form.as_p}} everything works as expected, if so, use {{ form.choices }} in order to render that field.
<form method="POST" class="ui form">
{% csrf_token %}
{{form.choices}}
<button type="submit" name="submit" class="ui button primary">Next</button>
</form>
Then, what you need is have a custom CheckboxSelectMultiple with its own template (in case you want a custom presentation to the user), and use it in your form:
Custom CheckboxSelectMultiple could be:
class MyCustomCheckboxSelectMultiple(CheckboxSelectMultiple):
template_name = "project/template/custom/my_checkbox_select_multiple.html"
And in the form:
class AmenitiesForm(ModelForm):
# ...
choices = forms.ModelMultipleChoiceField(Amenity.objects.all(), widget=forms.MyCustomCheckboxSelectMultiple)
# ...
How to implement the template my_checkbox_select_multiple.html, is up to you.
If you're using some Django prior to 1.11, visit this link to learn about a others things you've to do in order to customize a widget template.
Django widget override template
Hope this help!
I have a class jourListView(ListView). I want to input date in my html template and then retrieve the date to make a filter.
My class jourListView(ListView) refers to two linked tables.
I am stuck at level. How to make my code functional?
here are my models, views and template.
class jour(models.Model):
user = models.ForeignKey(User,on_delete=models.CASCADE, related_name='jour')
date = models.DateField(blank=True, null=True)
commentaire = models.CharField(max_length=500, blank=True, null=True)
class Meta:
managed = False
db_table = 'jour'
unique_together = (('id'),)
verbose_name = 'JOUR'
verbose_name_plural = 'JOUR'
id = models.AutoField(primary_key=True)
def get_absolute_url(self):
return reverse("jour_detail",kwargs={'pk':self.pk})
def __str__(self):
return str(self.date) ##
class activite(models.Model):
jour = models.ForeignKey('blog.jour',on_delete=models.CASCADE, related_name='jour' )
name= models.CharField(max_length=500, blank=True, null=True)
class Meta:
managed = False
db_table = 'activite'
unique_together = (('id'),)
verbose_name = 'ACTIVITÉ'
verbose_name_plural = 'ACTIVITÉ'
id = models.AutoField(primary_key=True)
def __str__(self):
return self.type
def get_absolute_url(self):
return reverse("jour_list")
My view:
class jourListView(ListView):
model = jour
def get_context_data(self, **kwargs):
if request.method == 'POST':
date_insert = request.POST.get('date_ref')
context = super(jourListView, self).get_context_data(**kwargs)
context['count'] = self.get_queryset().count()
return context
def get_queryset(self):
return jour.objects.filter(date__lte=timezone.now()).filter(user=self.request.user).filter(date__in=date_insert)
My html template:
{% if user.is_authenticated %}
<div class="container text-center">
<form class="form-signin" id="login_form" method="post" action="/blog/list/">
{% csrf_token %}
<br>
<input type="date" name="date_ref" class="form-control" placeholder="SAISIE DATE " value="" required autofocus>
<br>
<button class="btn btn-lg btn-primary btn-block" type="submit">OK</button>
</form>
</div>
<div class="centerstage">
{% for jour in jour_list %}
<div class="post">
<p class='postcontent' ><strong>Date:</strong> {{ jour.date }}</p>
<p class='postcontent' ><strong>Commentaire:</strong> {{ jour.commentaire }}</p>
<a class="btn btn-primary" href="{% url 'jour_edit' pk=jour.pk %}"><span class="glyphicon glyphicon-pencil"></span></a>
<h1>Détails activités</h1>
</div>
-----------------
{% endfor %}
</div>
{% endif %}
I changed my view but it does not work.
class jourListView(ListView):
model = jour
template_name = "blog/list.html"
def get_context_data(self, **kwargs):
if request.method == 'POST':
date_insert = request.POST.get('date_ref')
context = super(jourListView, self).get_context_data(**kwargs)
context['count'] = self.get_queryset().count()
return context
def get_queryset(self):
queryset = jour.objects.filter(date__lte=timezone.now()).filter(user=self.request.user)
date_insert = request.POST.get('date_ref')
if date_insert:
queryset = queryset.filter(date=date_insert)
return queryset
In addition I have another error:
NameError at /blog/list/
name 'request' is not defined
Request Method:
GET
Request URL:
http://127.0.0.1:8000/blog/list/
Django Version:
2.0.2
Exception Type:
NameError
Exception Value:
name 'request' is not defined
You need to define date_insert inside the get_queryset method before you use it. For example:
class jourListView(ListView):
model = jour
def get_context_data(self, **kwargs):
if self.request.method == 'POST':
date_insert = self.request.POST.get('date_ref')
context = super(jourListView, self).get_context_data(**kwargs)
context['count'] = self.get_queryset().count()
return context
def get_queryset(self):
queryset = jour.objects.filter(date__lte=timezone.now()).filter(user=self.request.user)
date_insert = self.request.POST.get('date_ref')
if date_insert:
queryset = queryset.filter(date=date_insert)
return queryset
Once that's working, you may want to consider some further improvements
Renaming the model to Jour to match the Django style
Make sure you return a context in get_context_data for GET requests as well as POST requests.
Using LoginRequiredMixin to make sure that only logged in users can access the view
Adding checks to handle the case where date_insert isn't a valid date string.
I found the solution to my problem.
Here is the result:
I was inspired by the example in this link:
Django: Search form in Class Based ListView
My view:
class jourListView(ListView):
model = jour
template_name = "blog/list.html"
def get_context_data(self, **kwargs):
context = super(jourListView, self).get_context_data(**kwargs)
# FILTER BY CURRENT MONTH, USER
filter_ = jour.objects.filter(date__lte=timezone.now()).filter(user_id=self.request.user).order_by('-date')
if self.request.GET.get('date_ref'):
date_insert = self.request.GET.get('date_ref')
filter_ = filter_.filter(date=date_insert)
context['jourListView'] = filter_
return context
My template (blog/list.html):
{% extends 'blog/base.html' %}
{% block content %}
{% if user.is_authenticated %}
<form class="navbar-form navbar-right" action="." method="get">
{{ form.as_p }}
<input id="date_ref" name="date_ref" type="date" placeholder="Localizar..." class="form-control">
<button type="submit" class="btn btn-success form-control"><span class="glyphicon glyphicon-search"></span></button>
</form>
{% if jourListView %}
{% for select_value in jourListView %}
<div class="post">
<p class='postcontent' ><strong>Date:</strong> {{ select_value.date}}</p>
<p class='postcontent' ><strong>User ID:</strong> {{ select_value.user_id}}</p>
<p class='postcontent' ><strong>Status:</strong> {{ select_value.status}}</p>
</div>
-----------------
{% endfor %}
{% endif %}
{% endif %}
{% endblock %}
I was making a online store kind of website and am not able to make my add to cart option to work properly. I haven't yet linked the rest of the code to the button and am using an another link to operate it currently as you can see in the code.I want the form to submit the item name and brand automatically. Please suggest some way.
urls.py
url(r'^(?P<pk>[0-9]+)/addtocart/$', views.ItemAdd.as_view(), name='addtocart'),
models.py
class Mycart(models.Model):
name = models.CharField(max_length=250)
brand = models.CharField(max_length=250)
quantity = models.IntegerField(default='1')
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('products:detail', kwargs={'pk': self.pk})
views.py
class ItemAdd(CreateView):
model = Mycart
fields = ['name', 'brand', 'quantity']
template_name = 'products/add_to_cart.html'
def get_context_data(self, **kwargs):
context = super(ItemAdd, self).get_context_data(**kwargs)
return context
add_to_cart.html
{% extends 'products/base.html' %} {% block body %}
<form action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
<input type="hidden" name="name" value="{{ object.name }}">
<input type="hidden" name="brand" value="{{ object.brand }}">
<br>
<p>Enter Quantity</p>
<input type="number" name="quantity" value="">
<button type="submit" class="btn btn-success">Submit</button>
</form>
{% endblock %}
I understand that, when user click on item (product), you want automatically add name and brand to form, so user only need to enter quantity and submit form? Maybe you can try like this:
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
product_pk = self.kwargs['pk']
product = Product.objects.get(pk=product_pk)
context.update({
'product': product
})
return context
Now you can access product in your template and get name and brand:
{{ product.name }}
{{ product.brand }}
You could use a Formview. Then you will have:
models.py
class Cart(models.Model):
quantity = models.PositiveIntegerField()
product = models.ForeignKey('products.Product')
forms.py
class AddCartForm(forms.ModelForm):
def save(self, product):
instance = super(AddCartForm, self).save(commit=False)
instance.product = product
instance.save()
return instance
class Meta:
model = Cart
fields = '__all__'
views.py
class AddCartView(FormView):
form_class = AddCartForm
success_url = '/'
def dispatch(self, request, *args, **kwargs):
product_pk = kwargs.get('product_pk')
self.product = get_object_or_404(Product, pk=product_pk)
return super(
AddCartView, self).dispatch(request, *args, **kwargs)
def get_context_data(self, **kw):
context = super(AddCartView, self).get_context_data(**kw)
context.update(product=self.product)
return context
def form_valid(self, form):
form.save(product=self.product)
return super(AddCartView, self).form_valid(form)
add_cart.html
{% extends 'products/base.html' %} {% block body %}
<form action="{% url 'cart:add' product.pk %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form }}
<button type="submit" class="btn btn-success">Submit</button>
</form>
{% endblock %}