I am in a middle of a project. I have a model :-
class CustomersModels(models.Model):
def servChoices(servs):
lst = [x.serv_name for x in servs]
ch =()
for a in lst:
ch += (a,a),
return ch
customer_name = models.CharField(max_length=100)
comp_name = models.CharField(max_length=100)
ph_no = models.CharField(max_length=12)
webs_name = models.URLField(max_length=200)
service_insterested = models.OneToOneField(ServiceModel, on_delete = models.CASCADE)
def __str__(self):
return self.customer_name
I have a corresponding form for this model.
Now what i want is the fields customer_name, comp_name, webs_name
to be optional in one page. And required in another page.
Please guide me to establish the task in the most convenient manner
Deleted in 'def servChoices', service_insterested because I don't have access to them in the model. I also made it to return a string with the name of the class return 'CustomersModels', so that you can edit, delete records with empty values.
The field class 'customer_name', 'comp_name' ,'webs_name' are set to blank=True to make them optional.
In the NoForm, the required field is 'ph_no'. YesForm requires all fields to be filled in. For this, a validator (clean) is used, which will display a message on the page which field is not filled in (the form will not be sent until all fields are filled). You can read about clean here:
In the bboard views, replace with your folder where you have the templates (this is the string template_name = 'bboard/templ_yes.html').
urls.py
urlpatterns = [
path('yes/', YesCreateView.as_view(), name='yes'),
path('no/', NoCreateView.as_view(), name='no'),
]
views.py
from django.views.generic.edit import CreateView
from django.urls import reverse_lazy
from .forms import NoForm, YesForm
class NoCreateView(CreateView):
template_name = 'bboard/templ_no.html'
form_class = NoForm
success_url = reverse_lazy('no')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
return context
class YesCreateView(CreateView):
template_name = 'bboard/templ_yes.html'
form_class = YesForm
success_url = reverse_lazy('yes')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
return context
forms.py
from django.forms import ModelForm
from .models import CustomersModels
from django.core.exceptions import ValidationError
class YesForm(ModelForm):
class Meta:
model = CustomersModels
fields = ('customer_name', 'comp_name', 'ph_no', 'webs_name')
def clean(self):
cleaned_data = super().clean()
customer_name = cleaned_data.get('customer_name')
comp_name = cleaned_data.get('comp_name')
webs_name = cleaned_data.get('webs_name')
if len(customer_name) <= 0 or customer_name == '':
raise ValidationError(
"fill in the field customer_name"
)
if len(comp_name) <= 0 or comp_name == '':
raise ValidationError(
"fill in the field comp_name"
)
if len(webs_name) <= 0 or webs_name == '':
raise ValidationError(
"fill in the field webs_name"
)
class NoForm(ModelForm):
class Meta:
model = CustomersModels
fields = ('customer_name', 'comp_name', 'ph_no', 'webs_name')
models.py
class CustomersModels(models.Model):
customer_name = models.CharField(max_length=100, blank=True)
comp_name = models.CharField(max_length=100, blank=True)
ph_no = models.CharField(max_length=12)
webs_name = models.URLField(max_length=200, blank=True)
def __str__(self):
return 'CustomersModels'
tepmplate(templ_yes.html)
<h2>form</h2>
<form method="post" action="{% url 'yes'%}">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="adding">
</form>
tepmplate(templ_no.html)
<h2>form</h2>
<form method="post" action="{% url 'no'%}">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="adding">
</form>
Related
How To Update Value From Views ? And Parse Id to DetailView ?
Problem Update Value
I Try to write query.attendance and query.status, to get data from database. but the error said "'QuerySet' object has no attribute 'attendance' / 'status'"
Problem Parse Id
I dont now how to parse this id to get_success_url
1. home/views.py
class HomeView(FormView):
template_name = 'home/index.html'
form_class = TicketForm
def form_valid(self, form):
getId = form.cleaned_data['nomor_ticket']
query = Graduates.objects.filter(ticket_id=getId)
if query:
**#FIRST ERROR (attendance and status has no attribute)**
print(query.attendance == timezone.now())
print(query.status == True)
**#FIRST END ERROR**
print('ticket available')
else:
print('no ticket not found ')
print(query)
return super().form_valid(form)
def get_success_url(self):
return reverse('attendance:index' + how to get id ?)
2. attendance/models.py
class StudyProgram(models.Model):
study_program_id = models.IntegerField()
name = models.CharField(max_length=100)
def __str__(self):
return self.name
class Graduates(models.Model):
ticket_id = models.CharField(primary_key=True, max_length=16, unique=True,
default=custom_id)
graduate_number = models.IntegerField()
student_id = models.IntegerField()
full_name = models.CharField(max_length=100)
study_program = models.ForeignKey(StudyProgram, on_delete=models.CASCADE)
attendance = models.DateTimeField(blank=True, null=True, editable=False)
status = models.BooleanField(default=False)
3. attendance/views.py
class Attendance(DetailView):
model = Graduates
template_name = "attendance/index.html"
4. attendance/urls.py
from django.urls import path
from . import views
app_name = 'attendance'
urlpatterns = [
path('<pk>/', views.Attendance.as_view(), name='index'),
]
5. home/form.py
from django import forms
from attendance.models import Graduates
class TicketForm(forms.Form):
nomor_ticket = forms.CharField(label="No Tiket ", required=True)
6. home/templates/home/index.html
#apart of index.html
....
<!-- Modal body -->
<div class="p-6 space-y-6">
<form method="POST">
{% csrf_token %}
{{form.as_p}}
</div>
<!-- Modal footer -->
<div
class="flex items-center p-6 space-x-2 rounded-b border-t border-gray-200 dark:border-gray-600"
>
<button
data-modal-toggle="defaultModal"
type="submit"
class="text-white bg-[#7f1d1d] hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-300 font-bold rounded-lg text-sm px-5 py-2.5 text-center dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800"
>
Cek Tiketmu
</button>
</form>
....
1 Your query object is of type QuerySet, not Graduate. You have to do something like:
try:
graduate = Graduate.objects.get(ticket_id=getId)
except Graduate.DoesNotExist:
print('no ticket not found ')
2 Just forget get_success_url. Do the redirect in form_valid method. The last line in form_valid:
return super().form_valid(form)
is nothing more of doing a redirect.
So your home/views.py would look like:
class HomeView(FormView):
template_name = 'home/index.html'
form_class = TicketForm
def form_valid(self, form):
getId = form.cleaned_data['nomor_ticket']
try:
graduate = Graduate.objects.get(ticket_id=getId)
print(graduate.attendance == timezone.now())
print(graduate.status == True)
print('ticket available')
except Graduate.DoesNotExist:
print('no ticket not found ')
print(graduate)
return redirect('attendance:index', graduate.ticket_id)
I am working on a project that requires an upload of multiple images in one of the form wizard steps. The form wizard also has several models used for the wizard which I think complicates the whole process the more. Here is the relevant code:
models.py
from django.db import models
from django.contrib.auth.models import User
from location_field.models.plain import PlainLocationField
from PIL import Image
from django.core.validators import MaxValueValidator, MinValueValidator
from listing_admin_data.models import (Service, SubscriptionType, PropertySubCategory,
PropertyFeatures, VehicleModel, VehicleBodyType, VehicleFuelType,
VehicleColour, VehicleFeatures, BusinessAmenities, Currency
)
class Listing(models.Model):
listing_type_choices = [('P', 'Property'), ('V', 'Vehicle'), ('B', 'Business/Service'), ('E', 'Events')]
listing_title = models.CharField(max_length=255)
listing_type = models.CharField(choices=listing_type_choices, max_length=1, default='P')
status = models.BooleanField(default=False)
featured = models.BooleanField(default=False)
city = models.CharField(max_length=255, blank=True)
location = PlainLocationField(based_fields=['city'], zoom=7, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
expires_on = models.DateTimeField(auto_now=True)
created_by = models.ForeignKey(User,
on_delete=models.CASCADE, editable=False, null=True, blank=True
)
listing_owner = models.ForeignKey(User,
on_delete=models.CASCADE, related_name='list_owner'
)
def __str__(self):
return self.listing_title
def get_image_filename(instance, filename):
title = instance.listing.listing_title
slug = slugify(title)
return "listings_pics/%s-%s" % (slug, filename)
class ListingImages(models.Model):
listing = models.ForeignKey(Listing, on_delete=models.CASCADE)
image_url = models.ImageField(upload_to=get_image_filename,
verbose_name='Listing Images')
main_image = models.BooleanField(default=False)
class Meta:
verbose_name_plural = "Listing Images"
def __str__(self):
return f'{self.listing.listing_title} Image'
class Subscriptions(models.Model):
subscription_type = models.ForeignKey(SubscriptionType, on_delete=models.CASCADE)
subscription_date = models.DateTimeField(auto_now_add=True)
subscription_amount = models.DecimalField(max_digits=6, decimal_places=2)
subscribed_by = models.ForeignKey(User, on_delete=models.CASCADE)
duration = models.PositiveIntegerField(default=0)
listing_subscription = models.ManyToManyField(Listing)
updated_at = models.DateTimeField(auto_now=True)
status = models.BooleanField(default=False)
class Meta:
verbose_name_plural = "Subscriptions"
def __str__(self):
return f'{self.listing.listing_title} Subscription'
class Property(models.Model):
sale_hire_choices = [('S', 'Sale'), ('R', 'Rent')]
fully_furnished_choices = [('Y', 'Yes'), ('N', 'No')]
listing = models.OneToOneField(Listing, on_delete=models.CASCADE)
sub_category = models.ForeignKey(PropertySubCategory, on_delete=models.CASCADE)
for_sale_rent = models.CharField(choices=sale_hire_choices, max_length=1, default=None)
bedrooms = models.PositiveIntegerField(default=0)
bathrooms = models.PositiveIntegerField(default=0)
rooms = models.PositiveIntegerField(default=0)
land_size = models.DecimalField(max_digits=10, decimal_places=2)
available_from = models.DateField()
car_spaces = models.PositiveIntegerField(default=0)
fully_furnished = models.CharField(choices=fully_furnished_choices, max_length=1, default=None)
desc = models.TextField()
property_features = models.ManyToManyField(PropertyFeatures)
price = models.DecimalField(max_digits=15, decimal_places=2)
currency = models.ForeignKey(Currency, on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
created_by = models.ForeignKey(User, on_delete=models.CASCADE)
class Meta:
verbose_name_plural = "Properties"
def __str__(self):
return f'{self.listing.listing_title}'
The forms for this app is as follows:
forms.py
from django import forms
from .models import Listing, Property, Vehicle, Business, ListingImages
class ListingDetails(forms.ModelForm):
class Meta:
model = Listing
fields = ['listing_title', 'city', 'location']
class PropertyDetails1(forms.ModelForm):
class Meta:
model = Property
fields = ['sub_category', 'for_sale_rent', 'bedrooms', 'bathrooms',
'rooms', 'land_size', 'available_from', 'car_spaces', 'fully_furnished',
'desc', 'currency', 'price'
]
class PropertyDetails2(forms.ModelForm):
class Meta:
model = Property
fields = ['property_features']
class ListingImagesForm(forms.ModelForm):
class Meta:
model = ListingImages
fields = ['image_url']
The view that handles all this, though not yet complete as I am still researching on the best way to save the data to the database is as shown below:
views.py
from django.shortcuts import render
import os
from .forms import ListingDetails, PropertyDetails1, PropertyDetails2, ListingImagesForm
from .models import ListingImages
from formtools.wizard.views import SessionWizardView
from django.conf import settings
from django.core.files.storage import FileSystemStorage
from django.forms import modelformset_factory
from django.contrib import messages
from django.http import HttpResponseRedirect
class PropertyView(SessionWizardView):
ImageFormSet = modelformset_factory(ListingImages, form=ListingImagesForm, extra=3)
template_name = "listings/create_property.html"
formset = ImageFormSet(queryset=Images.objects.none())
form_list = [ListingDetails, PropertyDetails1, PropertyDetails2, ListingImagesForm]
file_storage = FileSystemStorage(location=os.path.join(settings.MEDIA_ROOT, 'media'))
def done(self, form_list, **kwargs):
return render(self.request, 'done.html', {
'form_data': [form.cleaned_data for form in form_list],
})
The template that is used to handle the form fields is as below:
create_property.py
<p>Step {{ wizard.steps.step1 }} of {{ wizard.steps.count }}</p>
<form action="" method="post">
{% csrf_token %}
<table>
{{ wizard.management_form }}
{% if wizard.form.forms %}
{{ wizard.form.management_form }}
{% for form in wizard.form.forms %}
{{ form }}
{% endfor %}
{% else %}
{% for field in wizard.form %}
<div class="form-group">
<label for="{{ field.id_for_label }}">{{ field.label }}</label>
{{ field }}
<span class="message">{{ field.errors }}</span>
</div>
{% endfor %}
{% endif %}
</table>
{% if wizard.steps.prev %}
<div class="d-flex justify-content-around">
<button name="wizard_goto_step" type="submit" class="btn btn-primary" value="{{ wizard.steps.first }}">First Step</button>
<button name="wizard_goto_step" type="submit" class="btn btn-primary" value="{{ wizard.steps.prev }}">Previous Step</button>
</div>
{% endif %}
<div class="d-flex justify-content-end col-12 mb-30 pl-15 pr-15">
<input type="submit" value="{% trans "submit" %}"/>
</div>
</form>
I have tried to attach all the relevant information for this to work.
The main problem I am facing is that the template doesn't give room for multiple uploads, and again, after I attach a single file that is provided and try to submit, I get a field cannot be empty error message.
I am still new to Django and trying to learn as I code, but so far, not much has been documented about the form wizard and the multiple image upload issues. Most of the posts available appear to be shoddy and only uses the contact form which does not store any details on the database.
The solution is from this Project
MultipleUpload.py
from django import forms
FILE_INPUT_CONTRADICTION = object()
class ClearableMultipleFilesInput(forms.ClearableFileInput):
# Taken from:
# https://stackoverflow.com/questions/46318587/django-uploading-multiple-files-list-of-files-needed-in-cleaned-datafile#answer-46409022
def value_from_datadict(self, data, files, name):
upload = files.getlist(name) # files.get(name) in Django source
if not self.is_required and forms.CheckboxInput().value_from_datadict(
data, files, self.clear_checkbox_name(name)):
if upload:
# If the user contradicts themselves (uploads a new file AND
# checks the "clear" checkbox), we return a unique marker
# objects that FileField will turn into a ValidationError.
return FILE_INPUT_CONTRADICTION
# False signals to clear any existing value, as opposed to just None
return False
return upload
class MultipleFilesField(forms.FileField):
# Taken from:
# https://stackoverflow.com/questions/46318587/django-uploading-multiple-files-list-of-files-needed-in-cleaned-datafile#answer-46409022
widget = ClearableMultipleFilesInput
def clean(self, data, initial=None):
# If the widget got contradictory inputs, we raise a validation error
if data is FILE_INPUT_CONTRADICTION:
raise forms.ValidationError(self.error_message['contradiction'], code='contradiction')
# False means the field value should be cleared; further validation is
# not needed.
if data is False:
if not self.required:
return False
# If the field is required, clearing is not possible (the widg et
# shouldn't return False data in that case anyway). False is not
# in self.empty_value; if a False value makes it this far
# it should be validated from here on out as None (so it will be
# caught by the required check).
data = None
if not data and initial:
return initial
return data
enter code here
from django.core.files.uploadedfile import UploadedFile
from django.utils import six
from django.utils.datastructures import MultiValueDict
from formtools.wizard.storage.exceptions import NoFileStorageConfigured
from formtools.wizard.storage.base import BaseStorage
class MultiFileSessionStorage(BaseStorage):
"""
Custom session storage to handle multiple files upload.
"""
storage_name = '{}.{}'.format(__name__, 'MultiFileSessionStorage')
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if self.prefix not in self.request.session:
self.init_data()
################################################################################################
# Helper
################################################################################################
def _get_data(self):
self.request.session.modified = True
return self.request.session[self.prefix]
def _set_data(self, value):
self.request.session[self.prefix] = value
self.request.session.modified = True
data = property(_get_data, _set_data)
################################################################################################
# formtools.wizard.storage.base.BaseStorage API overrides
################################################################################################
def reset(self):
# Store unused temporary file names in order to delete them
# at the end of the response cycle through a callback attached in
# `update_response`.
wizard_files = self.data[self.step_files_key]
for step_files in six.itervalues(wizard_files):
for file_list in six.itervalues(step_files):
for step_file in file_list:
self._tmp_files.append(step_file['tmp_name'])
self.init_data()
def get_step_files(self, step):
wizard_files = self.data[self.step_files_key].get(step, {})
if wizard_files and not self.file_storage:
raise NoFileStorageConfigured(
"You need to define 'file_storage' in your "
"wizard view in order to handle file uploads.")
files = {}
for field in wizard_files.keys():
files[field] = {}
uploaded_file_list = []
for field_dict in wizard_files.get(field, []):
field_dict = field_dict.copy()
tmp_name = field_dict.pop('tmp_name')
if(step, field, field_dict['name']) not in self._files:
self._files[(step, field, field_dict['name'])] = UploadedFile(
file=self.file_storage.open(tmp_name), **field_dict)
uploaded_file_list.append(self._files[(step, field, field_dict['name'])])
files[field] = uploaded_file_list
return MultiValueDict(files) or MultiValueDict({})
def set_step_files(self, step, files):
if files and not self.file_storage:
raise NoFileStorageConfigured(
"You need to define 'file_storage' in your "
"wizard view in order to handle file uploads.")
if step not in self.data[self.step_files_key]:
self.data[self.step_files_key][step] = {}
for field in files.keys():
self.data[self.step_files_key][step][field] = []
for field_file in files.getlist(field):
tmp_filename = self.file_storage.save(field_file.name, field_file)
file_dict = {
'tmp_name': tmp_filename,
'name': field_file.name,
'content_type': field_file.content_type,
'size': field_file.size,
'charset': field_file.charset
}
self.data[self.step_files_key][step][field].append(file_dict)
form.py
from MultipleUpload import MultipleFilesField, ClearableMultipleFilesInput
class ListingImagesForm(forms.ModelForm):
image_url = MultipleFilesField(widget=ClearableMultipleFilesInput(
attrs={'multiple': True, 'accept':'.jpg,.jpeg,.png'}), label='Files')
class Meta:
model = ListingImages
fields = ['image_url']
views.py
from MultipleUpload import MultiFileSessionStorage
class PropertyView(SessionWizardView):
storage_name = MultiFileSessionStorage.storage_name
ImageFormSet = modelformset_factory(ListingImages, form=ListingImagesForm, extra=3)
template_name = "listings/create_property.html"
formset = ImageFormSet(queryset=Images.objects.none())
form_list = [(....), ('ListingImagesForm',ListingImagesForm)]
file_storage = FileSystemStorage(location=os.path.join(settings.MEDIA_ROOT, 'media'))
def done(self, form_list, **kwargs):
cleaned_data = self.get_cleaned_data_for_step('ListingImagesForm')
for f in cleaned_data.get('image_url',[]):
instance = ListingImages(image_url=f, .....)
instance.save()
return render(self.request, 'done.html', {
'form_data': [form.cleaned_data for form in form_list],
})
My project has many physics questions stored in its database where each of these questions belongs to a Physics' topic and a Question type.
I have two ChoiceField:
* One for topics and includes 16 topics.
* One for question type and includes two question types.
I have a submit button that is supposed to show me the results of my filtering, however, I don't know how to write the Query Sets in the views.py although I have read the Documentation but still don't know how to make one query or more to get my results.
This is the models.py
from django.db import models
from home.choices import *
# Create your models here.
class Topic(models.Model):
topic_name = models.IntegerField(
choices = question_topic_name_choices, default = 1)
def __str__(self):
return '%s' % self.topic_name
class Image (models.Model):
image_file = models.ImageField()
def __str__(self):
return '%s' % self.image_file
class Question(models.Model):
question_type = models. IntegerField(
choices = questions_type_choices, default = 1)
question_topic = models.ForeignKey( 'Topic',
on_delete=models.CASCADE,
blank=True,
null=True)
question_description = models.TextField()
question_answer = models.ForeignKey( 'Answer',
on_delete=models.CASCADE,
blank=True,
null=True)
question_image = models.ForeignKey( 'Image',
on_delete=models.CASCADE,
blank=True,
null=True)
def __str__(self):
return '%s' % self.question_type
class Answer(models.Model):
answer_description = models.TextField()
answer_image = models.ForeignKey( 'Image',
on_delete=models.CASCADE,
blank=True,
null=True)
def __str__(self):
return '%s' % self.answer_description
This is the forms.py
from django import forms
from betterforms.multiform import MultiModelForm
from .models import Topic, Image, Question, Answer
from .choices import questions_type_choices, question_topic_name_choices
class TopicForm(forms.ModelForm):
topic_name = forms.ChoiceField(
choices=question_topic_name_choices,
widget = forms.Select(
attrs = {'class': 'home-select-one'}
))
class Meta:
model = Topic
fields = ['topic_name',]
def __str__(self):
return self.fields
class QuestionForm(forms.ModelForm):
question_type = forms.ChoiceField(
choices= questions_type_choices,
widget = forms.Select(
attrs = {'class': 'home-select-two'},
))
class Meta:
model = Question
fields = ['question_type',]
def __str__(self):
return self.fields
class QuizMultiForm(MultiModelForm):
form_classes = {
'topics':TopicForm,
'questions':QuestionForm
}
This is the views.py
from django.shortcuts import render, render_to_response
from django.views.generic import CreateView, TemplateView
from home.models import Topic, Image, Question, Answer
from home.forms import QuizMultiForm
def QuizView(request):
if request.method == "POST":
form = QuizMultiForm(request.POST)
if form.is_valid():
pass
else:
form = QuizMultiForm()
return render(request, "index.html", {'form': form})
This is the index.html
{% extends 'base.html' %} {% block content %}
<form method="POST">
{% csrf_token %} {{ form.as_p }}
<button type="submit" id="home-Physics-time-button">
It is Physics Time</button>
</form>
{% endblock content %}
Any help would be great. Thank you!
i dont know what exactly you want to filter or if i understood correctly (cant add comments yet), but here is an example:
views.py
def QuizView(request):
topics = Topic.objects.filter(topic_name=1) # i dont know your choices, but i go with the set default
if request.method == "POST":
form = QuizMultiForm(request.POST)
if form.is_valid():
pass
else:
form = QuizMultiForm()
return render(request, "index.html", {'form': form, 'topics':'topics})
template part for calling now the query
{% for topic in topics %}
<h1> {{ topic.topic_name }} </h1>
{% endfor %}
explanation: you are filtering the query in your view by .filter(model_field=)
in your template you iterate trough all results (you are passing 'topics' from the view into the template by the context parameter in your curly brackets), filtered by the view
Sorry for my poor english...
I've got a Model called Habitation :
class Habitation(models.Model):
propr = models.ForeignKey(Client, related_name="proprietaire")
locat = models.ForeignKey(Client, related_name="locataire", null=True, blank=True)
etage = models.CharField(max_length=2, blank=True)
numero = models.CharField(max_length=3, blank=True)
ad1 = models.CharField(max_length=64)
ad2 = models.CharField(max_length=64, blank=True)
cp = models.CharField(max_length=5)
ville = models.CharField(max_length=32)
def get_appareils(self):
return Appareil.objects.filter(habitation=self)
def selflink(self):
if self.id:
return 'Editer' % str(self.id)
else:
return 'Indéfini'
selflink.allow_tags = True
def __unicode__(self):
return u'%s - %s %s' % (self.ad1, self.cp, self.ville)
With his edit view :
def edit(request, habitation_id):
habitation = Habitation.objects.get(pk=habitation_id)
if request.POST:
form = HabitationForm(request.POST, instance=habitation)
if form.is_valid():
form.save()
return redirect('clients')
else:
form = HabitationForm(instance=habitation)
print form.fields
return render_to_response('habitations/edit.html', {
'habitation_id': habitation_id,
'form': form,
}, context_instance=RequestContext(request))
and his template :
<table>
<form action="/habitations/edit/{{ habitation_id }}/" method="post">
{{ form }}
{% csrf_token %}
{{ form.as_table }}
</form>
</table>
Form:
from django import forms
from client import models
class HabitationForm(forms.ModelForm):
class meta:
model = models.Habitation
fields = ('propr', 'locat', 'etage', 'numero', 'ad1', 'ad2', 'cp', 'ville',)
My view (or my ModelForm) doesn't retrive any field, so no more form field.
Is anybody has any suggestion ?
The meta class name in form should be Meta not meta.
Update your form to
from django import forms
from client import models
class HabitationForm(forms.ModelForm):
class Meta: #<---- define with capital M
model = models.Habitation
fields = ('propr', 'locat', 'tegae', 'numero', 'ad1', 'ad2', 'cp', 'ville',)
I'm really stuck with this. To show my problem I created a new Django project and started from scratch, focusing only on one single form.
What I'm trying to do is to create a form with several fields of the same name. I tried using modelformset_factory to achieve this but it looks to me like it's not what I really need.
Below is my code (also on dpaste) which currently works fine with one single field called name. How can I create and process a form which would have several name fields? Could somebody point me in the right direction?
# models.py
class Category(models.Model):
name = models.CharField(max_length=30, unique=True)
user = models.ForeignKey(User, blank=True, null=True)
class Meta:
verbose_name_plural = "Ingredience Categories"
def __unicode__(self):
return self.name
# forms.py
class CategoryForm(ModelForm):
class Meta:
model = Category
fields = ('name',)
# views.py
def home(request):
if request.method == 'POST':
catform = CategoryForm(request.POST)
catformInstance = catform.save(commit = False)
catformInstance.save()
return HttpResponseRedirect('')
else:
catform = CategoryForm()
context = {'catform': catform}
return render_to_response('home.html', context, context_instance=RequestContext(request))
# home.html template
<h3>Insert new Category</h3>
<form action="/" method="post" id="ingr-cat-form">{% csrf_token %}
{{ catform.as_p }}
<input type="submit" name="ingrCatForm" value="Save" />
</form>
UPDATE: to clarify, I want to allow user to insert several categories within one form. I think I'm getting close, here is my new version of views.py but it still stores just one category (the last one in the list):
def home(request):
if request.method == 'POST':
catform = CategoryForm(request.POST)
names = request.POST.getlist('name')
catformInstance = catform.save(commit = False)
for name in names:
catformInstance.name = name
catformInstance.save()
return HttpResponseRedirect('')
else:
catform = CategoryForm()
context = {'catform': catform}
return render_to_response('home.html', context, context_instance=RequestContext(request))
You cannot have fields with the same name (on the same Model). If you only need to change the html label in the html form, use
class Category(models.Model):
name = models.CharField(max_length=30, unique=True)
name2 = models.CharField(max_length=30, unique=True, verbose_name="name")
user = models.ForeignKey(User, blank=True, null=True)
or
class CategoryForm(ModelForm):
def __init__(self , *args, **kwargs):
super(CategoryForm, self).__init__(*args, **kwargs)
self.fields['name2'].label = "name"
Here is a working solution. Thanks to #YardenST for pointing me in the right direction. I managed to solve my initial problem by following this tutorial.
# models.py
class Category(models.Model):
name = models.CharField(max_length=30, unique=True)
user = models.ForeignKey(User, blank=True, null=True)
class Meta:
verbose_name_plural = "Ingredience Categories"
def __unicode__(self):
return self.name
# forms.py
class CategoryForm(ModelForm):
class Meta:
model = Category
fields = ('name',)
# views.py
def home(request):
if request.method == 'POST':
catforms = [CategoryForm(request.POST, prefix=str(x), instance=Category()) for x in range(0,3)]
if all([cf.is_valid() for cf in catforms]):
for cf in catforms:
catformInstance = cf.save(commit = False)
catformInstance.save()
return HttpResponseRedirect('')
else:
catform = [CategoryForm(prefix=str(x), instance=Category()) for x in range(0,3)]
context = {'catform': catform}
return render_to_response('home.html', context, context_instance=RequestContext(request))
# home.html template
<h3>Insert new Category</h3>
<form action="/" method="post" id="ingr-cat-form">{% csrf_token %}
{% for catform_instance in catform %} {{ catform_instance.as_p }} {% endfor %}
<input type="submit" name="ingrCatForm" value="Save" />
</form>