Django and ModelForm. How to change IntegerField to dropdown box - django

I have a model that looks like this
class RSVP (models.Model):
def __unicode__(self):
return self.firstName + " " + self.lastName
firstName = models.CharField(max_length=30)
lastName = models.CharField(max_length=30)
rsvpID = models.CharField(max_length=9, unique = True)
allowedAdults = models.IntegerField(default = 2)
allowedChildren = models.IntegerField(default = 0)
adultsAttending = models.IntegerField(default = 0)
childrenAttending = models.IntegerField(default = 0)
and I have a ModelForm that looks like this
class RsvpForm(ModelForm):
class Meta:
model = RSVP
exclude= ('firstName', 'lastName', 'allowedAdults', 'allowedChildren')
What I would like to happen is that instead of a text field for the adultsAttending, a dropdown box with the values 0 to allowedAdults shows up. This is for a wedding rsvp site and I'd like to set the max number of +1's an invitee can bring on an individual basis
Any thoughts on how to go about this?

I'm thinking you want to fork the allowed children/ adults as well as the name to another model:
models.py
class Invited(models.Model):
f_name = models.CharField()
l_name = models.CharField()
allowed_adults = models.IntegerField()
allowed_children = models.IntegerField()
class RSVP(models.Model):
invited = models.ForeignKey(Invited)
adults_attending = models.IntegerField()
children_attending = models.IntegerField()
Then you would create the invited objects and assign the allowed adults and children. And the RSVP form would take those number into account when generating the choices for your drop down box.
The drop down can be implemented by overriding the IntegerField widget with a ChoiceField
forms.py
class InvitedForm(forms.ModelForm):
class Meta:
model = Invited
class RSVPForm(forms.ModelForm):
class Meta:
model = RSVP
exclude = ['invited',]
def __init__(self, *args, **kwargs):
max_adults = kwargs.pop('max_adults',2) #default to 2 if no max set
max_children = kwargs.pop('max_children',2) #default to 2 if no max set
super(RSVPForm, self).__init__(*args, **kwargs)
adult_choices = ( (x,str(x)) for x in range(max_adults+1)) )
children_choices = ( (x,str(x)) for x in range(max_children+1)) )
self.fields['adults_attending'] = forms.ChoiceField(choices = adult_choices)
self.fields['children_attending'] = forms.ChoiceField(choices = children_choices)
views.py
def rsvp_view(request, invited_id):
invited = get_object_or_404(Invited, pk=invited_id)
if request.method=='POST':
form = RSVPForm(request.POST, max_adults=invited.allowed_adults,
max_children=invited.allowed_children)
if form.is_valid():
rsvp = form.save(commit=False)
rsvp.invited = invited
rsvp.save()
return HttpResponse("Success")
else:
form = RSVPForm(max_adults=invited.allowed_adults, max_children=invited.allowed_children)
context = { 'form':form,
'invited':invited }
return render_to_response('rsvp.html', context,
context_instance=RequestContext(request))

Related

apply a filter to the choices field of my model

Hi I have problems with some filters in django.
I have my own view where I can choose the day of the week which is a select choice field
once chosen it is saved in the db.
I would like to filter those already present so as not to repeat them if I had to choose another day.
Can anyone help me out please?
models.py
class Piano(models.Model):
nome_piano = models.CharField(max_length=100)
data_inizio = models.DateField()
data_fine = models.DateField()
utente_piano = models.ForeignKey(
User,
on_delete = models.CASCADE,
related_name = 'utente_piano'
)
def __str__(self):
return self.nome_piano
class Meta:
verbose_name = "Piano alimentare"
verbose_name_plural = "Piani alimentari"
class PianoSingleDay(models.Model):
giorni_settimana_scelta = [
("1","Lunedì"),
("2","Martedì"),
("3","Mercoledì"),
("4","Giovedì"),
("5","Venerdì"),
("6","Sabato"),
("7","Domenica")
]
giorni_settimana = models.CharField(
choices = giorni_settimana_scelta,
max_length = 300
)
single_piano = models.ForeignKey(
Piano,
on_delete = models.CASCADE,
related_name = 'single_piano'
)
def __str__(self):
return self.giorni_settimana
class Meta:
verbose_name = "Piano singolo"
verbose_name_plural = "Piani singoli"
views.py
#login_required
def PianoSingleView(request, id):
piano = get_object_or_404(models.Piano, id = id, utente_piano = request.user)
if request.method == 'POST':
giorno_form = PianoSingleDayForm(request.POST, prefix = 'giorno')
if giorno_form.is_valid():
day_piano = giorno_form.save(commit = False)
day_piano.single_piano = piano
day_piano.save()
return redirect('gestione-piano', id = piano.id)
else:
giorno_form = PianoSingleDayForm(prefix = 'giorno')
context = {'piano': piano, 'giorno_form': giorno_form}
return render(request, 'crud/create/gestione_piano_single.html', context)
forms.py
class PianoSingleDayForm(forms.ModelForm):
class Meta:
model = models.PianoSingleDay
exclude = ['single_piano']
1
2
You can let the PianoSingleDayForm exclude the days that have already been selected for that Piano with:
class PianoSingleDayForm(forms.ModelForm):
def __init__(self, *args, piano=None, **kwargs):
super().__init__(*args, **kwargs)
if piano is not None:
days = set(PianoDaySingle.objects.filter(
single_piano=piano
).values_list('giorni_settimana', flat=True))
self.fields['giorni_settimana'].choices = [
(k, v)
for k, v in self.fields['giorni_settimana'].choices
if k not in days
]
class Meta:
model = models.PianoSingleDay
exclude = ['single_piano']
We can then use this in the view by passing the Piano object to the form both in the GET and POST codepath:
#login_required
def PianoSingleView(request, id):
piano = get_object_or_404(models.Piano, id=id, utente_piano=request.user)
if request.method == 'POST':
giorno_form = PianoSingleDayForm(request.POST, piano=piano, prefix='giorno')
if giorno_form.is_valid():
giorno_form.instance.single_piano = piano
giorno_form.save()
return redirect('gestione-piano', id=piano.id)
else:
giorno_form = PianoSingleDayForm(piano=piano, prefix='giorno')
context = {'piano': piano, 'giorno_form': giorno_form}
return render(request, 'crud/create/gestione_piano_single.html', context)

How to request object.id in form clean data funtion

Have a models:
class Product(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
name = models.CharField(max_length=50)
variation_1 = models.BooleanField(default=True)
variation_2 = models.BooleanField(default=True)
variation_3 = models.BooleanField(default=True)
class Order(models.Model):
buyer = models.ForeignKey(User, related_name='buyer')
product = models.ForeignKey(Product)
variations_select = models.CharField(max_length=50, choices=VARIATIONS)
in forms.py
class OrderForm(forms.ModelForm):
variations_select = forms.ChoiceField(choices=VARIATIONS)
class Meta:
model = Order
fields = [
'variations_select'
]
i need to create a clean function that will check if variation_1 or variation_2 or variation_3 are availiable in Product. For this a need request Product.id to def clean_variations_select(self): How to do this?
def clean_variations_select(self):
product = Product.object.get(id = product.id)
variations_select = self.cleaned_data.get("variations_select")
if variations_select == "Variation_1" and product.variation_1 == False:
raise forms.ValidationError("variation_1 was sold already")
else:
return variations_select
product = Product.object.get(id = product.id) - don't work cause Order isn't created to database yet(but in rendering view link to new order creation i have that ../product.id/new_order).
You need to define an __init__ method for your class which should accept your product id as an argument.
def __init__(self,*args,**kwargs):
self.product_id = kwargs.pop('product_id')
super(OrderForm,self).__init__(*args,**kwargs)
When you initialize your form, you pass your product_id as a keyword argument.
OrderForm(request.POST, product_id=product_id)
And in clean method you can use self.product_id to get the Product object you want.
def clean_variations_select(self):
product = Product.object.get(id=self.product_id)
variations_select = self.cleaned_data.get("variations_select")
if variations_select == "Variation_1" and product.variation_1 == False:
raise forms.ValidationError("variation_1 was sold already")
else:
return variations_select

how to store modelform data to database

I have searched 20-30 posts and I did not find anything useful. I am to store data to database by selecting values from HTML file or form in view. Please tell me how I can achieve this. what code I am missing. Thanks in advance for Help.
view.py
def blog_list(request):
form = AttendanceForm()
if request.method == "POST":
form1 = AttendanceForm(request.POST)
if form1.is_valid:
form1.save()
return render(request, 'blog/blog_list.html',{
'form1':form1,
})
return render(request, 'blog/blog_list.html',{
'form':form,
})
my forms.py
class AttendanceForm(forms.ModelForm):
action = forms.ModelChoiceField(queryset=Action.objects.all(), empty_label="-----------", required=True)
employee = forms.ModelChoiceField(queryset=Employee.objects.all(), empty_label="-----------", required=True)
class Meta:
model = Action
fields = ['employee','action']
my model.py
class Action(models.Model):
action_name = models.CharField(max_length = 100)
def __str__(self):
return self.action_name
class Employee(models.Model):
employee_id = models.AutoField(primary_key = True)
employee_name = models.CharField(max_length = 100)
def __str__(self):
return self.employee_name
class Attendance(models.Model):
u = models.ForeignKey(Employee)
action = models.ForeignKey(Action)
action_time = models.DateTimeField(default=timezone.now())
In Python you need to call methods by using parentheses.
if form.is_valid():
form.save()
It is working fine after these changes in Model:
class Action(models.Model):
action_name = models.CharField(max_length = 100)
def __str__(self):
return self.action_name
class Employee(models.Model):
employee_id = models.AutoField(primary_key = True)
employee_name = models.CharField(max_length = 100)
def __str__(self):
return self.employee_name
class Attendance(models.Model):
employee = models.ForeignKey(Employee)
action = models.ForeignKey(Action)
action_time = models.DateTimeField(default=timezone.now())

Custom render modelformset in django

I have two models with an OneToMany relationship
models:
class Proveedor(models.Model):
id_proveedor = models.AutoField(primary_key = True)
nombre = models.CharField(max_length=150,blank=False,null=False)
codigo_asignado = models.CharField(max_length=50,blank=False,null=False)
class Meta:
verbose_name_plural = "Proveedor"
def __unicode__(self):
return self.nombre
class Codigo_Corto(models.Model):
id_codigo = models.AutoField(primary_key=True)
id_proveedor = models.ForeignKey(Proveedor,db_column='id_proveedor', verbose_name='Proveedor')
codigo = models.CharField(max_length=15)
tarifa = models.IntegerField()
revenue = models.IntegerField()
moneda = models.CharField(max_length=2)
direccion = models.CharField(max_length=2,blank=True,null=True)
I want to create a template with one only choicefield widget to select the provider (proveedor) and an html where the user type remaining fields from the model "Codigo_Corto"
Forms:
class CodigoCortoForm(forms.ModelForm):
id_proveedor = forms.ModelChoiceField(queryset=Proveedor.objects.all().order_by('nombre'),required=True,label='Proveedor')
codigo = forms.CharField(widget=forms.TextInput(attrs={'style': 'width:80px'}))
tarifa = forms.DecimalField(widget=forms.NumberInput(attrs={'style': 'width:80px'}),required=True)
revenue = forms.DecimalField(widget=forms.NumberInput(attrs={'style': 'width:80px'}),required=True)
moneda = forms.ChoiceField(
choices = (
('$',"$"),('L',"L"),
),
widget = forms.Select(attrs={'style': 'width:50px'})
,required=True )
direccion = forms.ChoiceField(
choices = (
('MT',"MT"),('MO',"MO"),('nn',"Sin Direccion"),
),
widget = forms.Select(attrs={'style': 'width:120px'})
)
def __init__(self,*args,**kwargs):
super(CodigoCortoForm,self).__init__(*args,**kwargs)
self.helper = FormHelper(self)
class Meta:
model = Codigo_Corto
My view:
def CCView(request):
if request.method == 'POST':
form = ccformset(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect('/home/')
else:
ccformset = formset_factory(CodigoCortoForm)
form = ccformset()
return render_to_response("codcorto.html",
{'form':form},
context_instance=RequestContext(request))
This way I get an id_proveedor choifield for every row in the tabe, but I need only one id_proveedor modelchoicefield outside the table.
Or I need to render a modelchoicefield for the id_proveedor separately and pass it to the formset.
Any advice
Thanks in advance

django-select2 not working with inlines in django-admin

Here are my models and admin classes:
---------------------Models-----------------------
from django.contrib.auth.models import User
class PurchaseOrder(models.Model):
buyer = models.ForeignKey(User)
is_debit = models.BooleanField(default = False)
delivery_address = models.ForeignKey('useraccounts.Address')
organisation = models.ForeignKey('useraccounts.AdminOrganisations')
date_time = models.DateTimeField(auto_now_add=True)
total_discount = models.IntegerField()
tds = models.IntegerField()
mode_of_payment = models.ForeignKey(ModeOfPayment)
is_active = models.BooleanField(default = True)
class Meta:
verbose_name_plural = "Purchase Orders"
def __unicode__(self):
return '%s' % (self.id)
----------------------------------Admin----------------------------------------
"""
This class is used to add, edit or delete the details of item purchased
"""
class PurchasedItemInline(admin.StackedInline):
form = ItemSelectForm
model = PurchasedItem
fields = ['parent_category', 'sub_category', 'item', 'qty', ]
extra = 10
class BuyerChoices(AutoModelSelect2Field):
queryset = User.objects.all()
search_fields = ['username__icontains', ]
class BuyerForm(ModelForm):
user_verbose_name = 'Buyer'
buyer = BuyerChoices(
label='Buyer',
widget=AutoHeavySelect2Widget(
select2_options={
'width': '220px',
'placeholder': 'Lookup %s ...' % user_verbose_name
}
)
)
class Meta:
model = PurchaseOrder
fields = '__all__'
"""
This class is used to add, edit or delete the details of items
purchased but buyer has not confirmed the items purchased, this class
inherits the fields of PurchaseOrder derscribing the delivery address of
buyer , is_debit , total discount , tds and mode of payment
"""
class PurchaseOrderAdmin(admin.ModelAdmin):
form = BuyerForm
#list_display = ['id','buyer','delivery_address','date_time','is_active']
inlines = [PurchasedItemInline]
# model = PurchaseOrder
#actions = [mark_active, mark_inactive]
#list_filter = ['date_time']
#search_fields = ['id']
list_per_page = 20
def response_add(self, request, obj, post_url_continue=None):
request.session['old_post'] = request.POST
request.session['purchase_order_id'] = obj.id
return HttpResponseRedirect('/suspense/add_distance/')
I am trying to implement django-select2, but when I use inlines in
PurchaseOrderAdmin it doesn't show the field where I have implemented
django-select2:
But when I remove inlines, it works fine:
Edit
Here is the ItemSelectForm
class ItemSelectForm(forms.ModelForm):
class Media:
js = (
'http://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js',
'js/ajax.js',
)
try:
parent_category = forms.ModelChoiceField(queryset=Category.objects.\
filter(parent__parent__isnull=True).filter(parent__isnull=False))
sub_category_id = Category.objects.values_list('id',flat=True)
sub_category_name = Category.objects.values_list('name',flat=True)
sub_category_choices = [('', '--------')] + [(id, name) for id, name in
itertools.izip(sub_category_id, sub_category_name)]
sub_category = forms.ChoiceField(sub_category_choices)
except:
pass
item = forms.ModelChoiceField(queryset = Product.objects.all())
def __init__(self, *args, **kwargs):
super(ItemSelectForm, self).__init__(*args, **kwargs)
self.fields['parent_category'].widget.attrs={'class': 'parent_category'}
self.fields['sub_category'].widget.attrs={'class': 'sub_category'}
self.fields['item'].widget.attrs={'class': 'item'}
It worked for me by adding the following line in the static/suit/js/suit.js
Add:
(function ($) {
Suit.after_inline.register('init_select2', function(inline_prefix, row){
$(row).find('select').select2();
});