Building dynamic forms from models - django

I have the following model in models.py
class TProfiles(models.Model):
id = models.IntegerField(primary_key=True) # AutoField?
first_name = models.CharField(max_length=45, blank=True)
surname = models.CharField(max_length=45, blank=True)
email = models.CharField(max_length=45, blank=True)
class Meta:
managed = False
db_table = 'profiles'
And in my template I want to produce a form based on the model attributes. Is there a way of looping through them dynamically?
register.html
{% block content %}
<form enctype="multipart/form-data" action="" method="post">
<!-- Loop through model attributes here -->
</form>
{% endblock %}

in models.py add:
class TProfilesForm(ModelForm):
class Meta:
model = TProfiles
fields = ['first_name', 'surname', 'email']
And in views.py create form like this:
form = TProfilesForm()
Then pass it to template like this:
return render_to_response("register.html", {
"form": form,
})
And in template:
{% for field in form %}
{{ field.label_tag }} {{ field }}
{% endfor %}
Also you can find all about ModelForm here

Related

Django forms how to display related data in an inner form

I am struggling with Django forms.
I have the following model.py:
class Property(models.Model):
portfolio = models.ForeignKey("portfolios.Portfolio", on_delete=models.CASCADE)
class PropertyImage(models.Model):
property = models.ForeignKey("Property", on_delete=models.CASCADE)
image = models.ImageField(upload_to = property_image_upload_to)
def __str__(self):
return self.image.url
class PropertyDocument(models.Model):
property = models.ForeignKey("Property", on_delete=models.CASCADE)
document = models.FileField()
class Address(models.Model):
property = models.OneToOneField("Property", on_delete=models.CASCADE)
line1 = models.CharField(max_length=100)
line2 = models.CharField(max_length=100, null=True, blank=True)
line3 = models.CharField(max_length=100, null=True, blank=True)
post_code = models.CharField(max_length=7)
town = models.CharField(max_length=100, null=True, blank=True)
city = models.CharField(max_length=100)
When adding/updating a property, I want the form to show the form for related objects like the address, documents/images instead of the select list's that appear in forms - I want to be able to add/edit the related data.
My view.py file
class PropertyCreate(CreateView):
model = Property
form_class=PropertyAddressFormSet
success_url = reverse_lazy('Property_list')
def get_context_data(self, **kwargs):
data = super(PropertyCreate, self).get_context_data(**kwargs)
return data
Property_form.html
{% extends 'base/base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<form method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" class="btn btn-primary" />
<button class="btn btn-link" onclick="javascript:history.back();">Cancel</button>
</form>
{% endblock %}
urls.py
from . import views
app_name = 'properties'
urlpatterns = [
path('<int:portfolio_id>/<int:pk>/edit', views.PropertyUpdate.as_view(), name='property_edit'),
path('<int:portfolio_id>/create', views.PropertyCreate.as_view(), name='property_new'),
]
I've read about inlineformset_factories and inlineformset's etc, but is this the best choice for my scenario? If so, I can't figure out how to show the portfolio, address form
I;m currently using a inlineformset like so, which creates the Address form on the PropertyCreate view, but I want to also add in the PropertyImages and PropertyDocs to the ProertyCreate view.:
PropertyAddressFormSet = inlineformset_factory(
parent_model=Property,
model=Address,
form=AddressForm,
extra=0,
min_num=1
)
For anyone in the same boat as me, I managed to get this working with the following code:
Forms.py:
class PropertyForm(ModelForm):
""" Edit a property """
class Meta:
model = Property
exclude = ()
PropertyAddressFormSet = inlineformset_factory(
parent_model=Property,
model=Address,
form=AddressForm,
extra=0,
min_num=1
)
Views.py
class PropertyCreate(CreateView):
model = Property
form_class=PropertyForm
success_url = reverse_lazy('Property_list')
def get_context_data(self, **kwargs):
data = super(PropertyCreate, self).get_context_data(**kwargs)
if self.request.POST:
data['address'] = PropertyAddressFormSet (self.request.POST, instance=self.object)
else:
data['address'] = PropertyAddressFormSet ()
return data
template:
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form |crispy }}
<fieldset class="border p-2">
<legend class="w-auto">Address</legend>
{{ address.management_form }}
{% for form in address.forms %}
<div >
{{ form.as_p }}
</div>
{% endfor %}
</fieldset>
</form>
Hope this helps someone.

Display foriegnkey fields in Django template for a CreateView

I am trying to display a checklist in the CreateView using the values in the ForeignKey fields for descriptions.
models.py
class Structure(models.Model):
name = models.CharField(max_length = 30)
description =models.CharField(max_length = 300, null=True, blank=True)
def __str__(self):
return self.name
class SelectedFramework(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
structure = models.ForegignKey(Structure)
selected = models.BooleanField(default = False)
views.py
class FrameworkCreateView(generic.CreateView):
model = SelectedFramework
fields =['structure', 'selected']
template_name = 'catalogue/structure.html'
def form_valid(self, form):
form.instance.user = self.request.user
return super(FrameworkCreateView, self).form_valid(form)
structure.html
{% extends 'catalogue\base.html' %}
{% block container %}
<h2>{% block title %}Structures{% endblock title %}</h2>
<form action="" method="post">
{% csrf_token %}
{% for field in form %}
<div class="col-sm-10">{{form.structure}} {{form.selected}}</div><br>
{% endfor %}
</div>
</form>
{% endblock %}
The code above works but will display the ForeignKey 'structure' as a dropdown list with the values of __str__. Is there a way to display string for structure.name and structure.description with the checkbox from selected in the CreateView?
In your template use:
{{ form.structure.name }}
{{ form.structure.description}}
You can write custom form, override the save method and create Structure object manually there:
class FrameworkForm(forms.ModelForm):
structure_name = forms.CharField(required=True)
structure_description = forms.CharField(required=False)
class Meta:
model = SelectedFramework
fields = [
'structure_name', 'structure_description', 'selected'
]
def save(self, commit=False):
instance = super(FrameworkForm, self).save(commit=False)
structure = Structure(
name=self.cleaned_data.get('structure_name'),
description=self.cleaned_data.get('structure_description')
)
structure.save()
instance.structure = structure
instance.save()
return instance
Also add form_class = FrameworkForm to your view instead of fields = ['structure', 'selected']
EDIT:
Perhaps you want something like this:
<ul>
{% for structure in form.fields.structure.choices.queryset %}
<li>{{ structure.name }} - {{ structure.description }}</li>
{% endfor %}
</ul>
If you want to get fields by iterating in the template. You have to use-
{% for field in form %}
{{ field }}
{% endfor %}
don't have to use any dot notation to get the field. If you want to get the label of the field you can use {{ field.label}} usually before {{field}}

Setting a parents value in a childs object's model form in Django?

I wish for one of a parent's variables to be pre-populated in a child's model form specifically a serial number. I have managed to get the serial number as part of the URL but would like to figure out how it can be implemented as a variable on the form page.
Models.py
class Product(models.Model):
serial_number = models.CharField(unique=True, max_length=15)
class ProductInstance(models.Model):
serial_number = models.ForeignKey('Product', on_delete=models.SET_NULL, null=True)
Views.py
class ProductInstanceCreate(CreateView):
model = ProductInstance
template_name = 'myapp/edit_productinstance.html'
form_class = GunInstanceForm
def get_success_url(self):
return reverse_lazy ('product-detail', kwargs={'pk': self.object.serial_number.pk})
Forms.py
class ProductInstanceForm(forms.ModelForm):
class Meta:
model = ProductInstance
fields = '__all__'
templates/myapp/product_detail.html
...
New
...
urls.py
urlpatterns += [
url(r'^productinstance/(?P<serial_number>[-\w]+)/create/$', views.ProductInstanceCreate.as_view(), name='productinstance_create'),]
templates/myapp/edit_productinstance_form.html
{% extends "base_generic.html" %}
{% block content %}
<h2>Serial Number: {{ serial_number }}</h2>
</br>
<form action="" method="post">
{% csrf_token %}
<table>
{{ form }}
</table>
<input type="submit" value="Submit" />
</form>
</br>
Back
{% endblock %}
So currently I can create a URL such as: productinstance/D1430913/create/
I now need to know:
How to use it as a variable for the title?
How to set the the forms default value to it?
For the title:
<h2>Serial Number: {{ form.serial_number.value }}</h2>
I believe if you modify your CreateView like so and implement the serial_number_func() with whatever you need to get the serial number, this will do what you want:
class ProductInstanceCreate(CreateView):
model = ProductInstance
template_name = 'myapp/edit_productinstance.html'
form_class = GunInstanceForm
def get_form_kwargs(self):
kwargs = super(ProductInstanceCreate, self).get_form_kwargs()
kwargs['serial_number'] = serial_number_func()
return kwargs

Checkboxes and Radio buttons in Django ModelForm

Welcome friends,
I'm a newbie in Django. I need your help. Seriously.
I want to add checkboxes and radio button in my form.
Any help will be appreciated.
models.py
from django.db import models
from shop.models import Product
class Order(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
email = models.EmailField()
address = models.CharField(max_length=250)
postal_code = models.CharField(max_length=20)
city = models.CharField(max_length=100)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
paid = models.BooleanField(default=False)
class Meta:
ordering = ('-created',)
def __str__(self):
return 'Order {}'.format(self.id)
def get_total_cost(self):
return sum(item.get_cost() for item in self.items.all())
forms.py
from django import forms
from .models import Order
class OrderCreateForm(forms.ModelForm):
class Meta:
model = Order
fields = ['first_name', 'last_name', 'email', 'address', 'postal_code', 'city']
create.html
{% extends "shop/base.html" %}
{% block title %}
Checkout
{% endblock %}
{% block content %}
<h1>Checkout</h1>
<form action="." method="post" class="order-form">
{{ form.as_p }}
<p><input type="submit" value="Place order"></p>
{% csrf_token %}
</form>
{% endblock %}
Any suggestions are welcome.Please help.
UPDATE
How to add select option ?
you can do something like this
CHOICES=[('item1','item 1'),
('item2','item 2')]
class OrderCreateForm(forms.ModelForm):
postal_code = forms.ChoiceField(choices=CHOICES, widget=forms.RadioSelect())
....
class Meta:
model = Order
fields = ['first_name', 'last_name', 'email', 'address', 'postal_code', 'city']
similarly, you can do for the other field also
and for checkbox, you can define it as a BooleanFileld and you can use
{{ form.paid }}
in you template.
The form will be rendered with the field types you define in the model:
BooleanField is rendered as a checkbox, paid in your case.
ChoiceField can be rendered as radio buttons with the appropiate widget.
You can redefine the widgets in class OrderCreateForm:
CHOICES = [('option1','label 1'), ('option2','label 2')]
some_field = forms.ChoiceField(choices=CHOICES,widget=forms.RadioSelect())

How to show ManyToMany fields using CreateView in Django 1.8

I'm doing a basic application in Django 1.8 and I'm using Create-View, I don't know why the create form doesn't have manyTOmany fields neither foreign-key field previously defined in my model. This is my code:
My Model:
class Autor(models.Model):
nombre = models.CharField(max_length=30)
....
class Editor(models.Model):
nombre = models.CharField(max_length=30)
...
class Libro(models.Model):
titulo = models.CharField(max_length=100)
autores = models.ManyToManyField(Autor) #MANY2MANY FIELD
editor = models.ForeignKey(Editor) #FOREIGN KEY FIELD
fecha_publicacion = models.DateField()
portada = models.ImageField(upload_to = 'portadas/')
def __unicode__(self):
return self.titulo
My View:
class LibroCreateView(CreateView):
model = Libro
template_name = 'biblioteca/crear.html'
fields = ['titulo', 'autores', 'editor', 'fecha_publicacion', 'portada']
My template:
{% block main %}
<form action="" enctype="multipart/form-data" method="POST">{% csrf_token %}
<table>
{{form.as_table}}
</table>
<input type="submit" name="crear" value="Crear">
</form> <br>
{% endblock main %}
My result
Why isn't my fields "Autores"(many2many) and "Editor"(foreign-key) correctly shown?. Thanks.
Try giving form to the view that is CreateView. Make a ModelForm using your model
There you can do query for you foreign key and many to many field.
You can present them as you like