Django - Restrict a drop down options depending on another drop down - python

I have 2 drop downs.
First drop down asks for the type.
I have a second drop down that shows values from another Model.
What I need is that, if the first drop down as a type: qualif, I only want to show the pk=1 of the second drop down.
This is what I have so far:
name = models.CharField(max_length=40,verbose_name="nom")
type = models.CharField(max_length=6,choices=TYPE_CHOICES)
division = models.ForeignKey(Division,verbose_name="division")
class TournamentForm(forms.ModelForm):
def clean(self):
super(TournamentForm, self).clean() #if necessary
if 'division' in self._errors:
"""
reset the value (something like this i
think to set the value b/c it doesnt get set
b/c the field fails validation initially)
"""
if self.data['type'] == 'qualif':
division = Division.objects.get(pk=1)
self.division = division
# remove the error
del self._errors['division']
return self.cleaned_data
# Register your models here.
class TournamentAdmin(reversion.VersionAdmin):
form = TournamentForm
list_display = ('name', 'date', 'division', 'gender')
ordering = ('date', 'name')
list_filter = ['date', 'season', 'division', 'gender']
admin.site.register(Tournament, TournamentAdmin)
I read from another stack question to use clean...but sadly it's not working...
EDIT:
After looking at #Mardo's link, I tried loading up a static file.
Here is my folder setup:
myproject/static/admin/js/myfile.js
And this in my settings.py
STATIC_URL = '/static/'
But it keeps saying file not found...
Thanks,
Ara

Make two forms. First have only first dropdown, second is disabled. On selecting value commit form and render full version based on first.

Related

Django add dynamic fields with dynamic name attributes to front end and then insert it to Model

I have a Model which consists of almost 500+ fields. I want to take data through the front-end Form. But the issue is I can’t display all the 500 fields.
what I want is I will add the fields which I need. like on day-1 I will add 3 fields. food = 230 , petrol = 500, rent = 700. on the second day, fields may vary. I can add 20 fields on the second day. on the third day data may be of different fields. like petrol = 200, cement= 5000 , steel = 100 etc etc and so on!
Simple Solution is: I displayed all fields in HTML and submitted it to view and received in View function through Post Request! and then save() . But i want it to be dynamic!
if request.method == 'POST':
print("this is post")
# print()
food_expense=request.POST['food']
petrol_expense=request.POST['petrol']
easyload_expense=request.POST['easyload']
labour_expense = request.POST['labour']
equipments_expense = request.POST['equipments']
rent_expense = request.POST['rent']
cement_expense = request.POST['cement']
steel_expense = request.POST['steel']
other1_expense = request.POST['other1']
other2_expense = request.POST['other2']
other3_expense = request.POST['other3']
..... .... fields upto 500+
# expense_paidby = request.POST['paid_by']
expense_paidby_id = request.POST['paid_by']
paidby= PaidBy.objects.get(id=expense_paidby_id)
# expense_paidby = PaidBy.objects.get(name__icontains = request.POST['paid_by'])
projectname_id= request.POST['pname']
project_in_which_expenses_made=ProjectName.objects.get(id=projectname_id)
# project_in_which_expenses_made = request.POST['project_name']
date = request.POST['date']
# total = food_expense+petrol_expense+easyload_expense+labour_expense+equipments_expense+rent_expense
# print(petrol_expense, projectname_id , project_in_which_expenses_made)
inst= ProjectExpenses(food=food_expense,petrol=petrol_expense,easyload=easyload_expense ,labour=labour_expense ,
equipments=equipments_expense ,rent=rent_expense,cement=cement_expense,steel=steel_expense,
other1=other1_expense, other2=other2_expense, other3=other3_expense, date_of_expense=date, PaidByName=paidby,
expenses_in_project = project_in_which_expenses_made)
#in query i will have 500 fields.
inst.save()
what I want is how I can create dynamic input fields with name attributes as I have in the database.
how should I create these fields dynamically in the front end and then how I will handle it in view function instead of writing all 500+ fields through “value = request. post[“500+ fields line by line”]” means how I can handle it dynamically only those fields which come to view function. and then save it to DB.
data will only insert in selected fields all remaining will be zero by default.
I will appreciate forum Help.
I am not sure if I understood your question right. Perhaps a more minimal working example would clarify.
But, have you tried using model forms, such as CreateView?
You can dynamically create input forms and handling based on your model definition by adding a CreateView to your urlpatterns.
from django.views.generic.edit import CreateView
from .models import ProjectExpenses
urlpatterns += [path("new-project-expense", CreateView.as_view(model=ProjectExpenses, fields="__all__"))]
You can configure the "fields" argument to be a selection of your 500 model fields.

Associate classes with django-filters

Bonjour, I have a question regarding django-filters. My problem is:
I have two classes defined in my models.py that are:
class Volcano(models.Model):
vd_id = models.AutoField("ID, Volcano Identifier (Index)",
primary_key=True)
[...]
class VolcanoInformation(models.Model):
# Primary key
vd_inf_id = models.AutoField("ID, volcano information identifier (index)",
primary_key=True)
# Other attributes
vd_inf_numcal = models.IntegerField("Number of calderas")
[...]
# Foreign key(s)
vd_id = models.ForeignKey(Volcano, null=True, related_name='vd_inf_vd_id',
on_delete=models.CASCADE)
The two of them are linked throught the vd_id attribute.
I want to develop a search tool that allows the user to search a volcano by its number of calderas (vd_inf_numcal).
I am using django-filters and for now here's my filters.py:
from .models import *
import django_filters
class VolcanoFilter(django_filters.FilterSet):
vd_name = django_filters.ModelChoiceFilter(
queryset=Volcano.objects.values_list('vd_name', flat=True),
widget=forms.Select, label='Volcano name',
to_field_name='vd_name',
)
vd_inf_numcal = django_filters.ModelChoiceFilter(
queryset=VolcanoInformation.objects.values_list('vd_inf_numcal', flat=True),
widget=forms.Select, label='Number of calderas',
)
class Meta:
model = Volcano
fields = ['vd_name', 'vd_inf_numcal']
My views.py is:
def search(request):
feature_list = Volcano.objects.all()
feature_filter = VolcanoFilter(request.GET, queryset = feature_list)
return render(request, 'app/search_list.html', {'filter' : feature_filter, 'feature_type': feature_type})
In my application, a dropdown list of the possible number of calderas appears but the search returns no result which is normal because there is no relation between VolcanoInformation.vd_inf_numcal, VolcanoInformation.vd_id and Volcano.vd_id.
It even says "Select a valid choice. That choice is not one of the available choices."
My question is how could I make this link using django_filters ?
I guess I should write some method within the class but I have absolutely no idea on how to do it.
If anyone had the answer, I would be more than thankful !
In general, you need to answer two questions:
What field are we querying against & what query/lookup expressions need to be generated.
What kinds of values should we be filtering with.
These answers are essentially the left hand and right hand side of your .filter() call.
In this case, you're filtering across the reverse side of the Volcano-Volcano Information relationship (vd_inf_vd_id), against the number of calderas (vd_inf_numcal) for a Volcano. Additionally, you want an exact match.
For the values, you'll need a set of choices containing integers.
AllValuesFilter will look at the DB column and generate the choices from the column values. However, the downside is that the choices will not include any missing values, which look weird when rendered. You could either adapt this field, or use a plain ChoiceFilter, generating the values yourself.
def num_calderas_choices():
# Get the maximum number of calderas
max_count = VolcanoInformation.objects.aggregate(result=Max('vd_inf_numcal'))['result']
# Generate a list of two-tuples for the select dropdown, from 0 to max_count
# e.g, [(0, 0), (1, 1), (2, 2), ...]
return zip(range(max_count), range(max_count))
class VolcanoFilter(django_filters.FilterSet):
name = ...
num_calderas = django_filters.ChoiceFilter(
# related field traversal (note the connecting '__')
field_name='vd_inf_vd_id__vd_inf_numcal',
label='Number of calderas',
choices=num_calderas_choices
)
class Meta:
model = Volcano
fields = ['name', 'num_calderas']
Note that I haven't tested the above code myself, but it should be close enough to get you started.
Thanks a lot ! That's exactly what I was looking for ! I didn't understand how the .filter() works.
What I did, for other attributes is to generate the choices but in a different way. For instance if I just wanted to display a list of the available locations I would use:
# Location attribute
loc = VolcanoInformation.objects.values_list('vd_inf_loc', flat=True)
vd_inf_loc = django_filters.ChoiceFilter(
field_name='vd_inf_vd_id__vd_inf_loc',
label='Geographic location',
choices=zip(loc, loc),
)

How to prevent field value repetition on already assigned date in Odoo?

I am working with Odoo 10.
I have a one2many field with two columns in the hr.employee model. If the field "Bonus" (many2one field) is assigned to a particular date, it should not be saved or repeated once again on the same date.
How to achieve this?
Take a look at this below code, this is one possible solution, not the best.
from odoo import models, fields, api
from odoo.exceptions import ValidationError
class HrEmployee(models.Model):
_inherit = 'hr.employee'
prod_details_ids = fields.One2many(
string=u'Product details',
comodel_name='prod.details',
inverse_name='employee_id',
)
class ProdDetails(models.Model):
_name = 'prod.details'
employee_id = fields.Many2one(
string=u'Employee',
comodel_name='hr.employee',
)
date = fields.Date(
string=u'Date',
default=fields.Date.context_today,
)
bonus_id = fields.Many2one(
string=u'Bonus',
comodel_name='res.partner', # just an example
)
And then you need to add the constrains:
Solution 1
_sql_constraints = [
('bonus_unique', 'unique(employee_id, date, bonus_id)',
_('Date + Bonus cannot be repeated in one employee!')),
]
Solution 2
#api.one
#api.constrains('date', 'bonus_id')
def _check_unique_date(self):
# you have more freedom here if you want to check more things
rest = self.employee_id.prod_details_ids - self
for record in rest:
if record.date == self.date and record.bonus_id.id == self.bonus_id.id:
raise ValidationError("Date + Bonus already exists and violates unique field constraint")
Note: If you have date already in your database make sure that the constrains can be added with this data, because if not the constraint cannot be added to the database. This happens with the _sql_constraints at least
Use constrains to stop creating another record with the same name, so duplication of records doesnot occur.
you can use constraints and the search_count() method to check if there is a record. like below
#api.constraints('date')
def validate_date(self):
result = self.search_count([your_domain])
if result:
raise ValidationError(_('Your Text'))

Django-datatable-view throwing error after decorating url

I am using django-datable-view for rendering data from django models.
Everything works fine before decorating the url, after i added login_required to the url, it threw weird error.
According to the doc, it states that i can add login_required to the url.
Below is my code
from django_datatables_view.base_datatable_view import BaseDatatableView
class OrderListJson(BaseDatatableView):
# The model we're going to show
model = MyModel
# define the columns that will be returned
columns = ['number', 'user', 'state', 'created', 'modified']
# define column names that will be used in sorting
# order is important and should be same as order of columns
# displayed by datatables. For non sortable columns use empty
# value like ''
order_columns = ['number', 'user', 'state', '', '']
# set max limit of records returned, this is used to protect our site if someone tries to attack our site
# and make it return huge amount of data
max_display_length = 500
def render_column(self, row, column):
# We want to render user as a custom column
if column == 'user':
return '{0} {1}'.format(row.customer_firstname, row.customer_lastname)
else:
return super(OrderListJson, self).render_column(row, column)
def filter_queryset(self, qs):
# use parameters passed in GET request to filter queryset
# simple example:
search = self.request.GET.get(u'search[value]', None)
if search:
qs = qs.filter(name__istartswith=search)
# more advanced example using extra parameters
filter_customer = self.request.GET.get(u'customer', None)
if filter_customer:
customer_parts = filter_customer.split(' ')
qs_params = None
for part in customer_parts:
q = Q(customer_firstname__istartswith=part)|Q(customer_lastname__istartswith=part)
qs_params = qs_params | q if qs_params else q
qs = qs.filter(qs_params)
return qs
url
url(_(r'^users/all/?$'),
login_required(dashboard.v1.views.OrderListJson.as_view()),
name='all_users'),
i keep getting error 500, if i remove the login_required, everything works well. If i can get suggestions on how to decorate the class view, i will be glad since that is what am trying to achieve

Multiple Validators for a single field

I have a table nsksystem which is getting value for its two field nskmachinename and nskreleaseid from another table nskrelease.
The requirement is nsksystem.nskreleaseid + nsksystem.nskmachinename should be unique and nsksystem.nskreleaseid is from nskrlease database. I am not enforcing any constraints in table.
db.define_table('nsksystem',
Field('nskuserid',length=512,requires=IS_EMAIL(error_message='invalid email!'),default = auth.user.email if auth.user else None, label=T('Email ID'),writable=False),
Field('nskmachinename', length=128, requires = IS_IN_DB(db,'nskrelease.nskname','%(nskname)s',error_message='Machine not registerd for release.'), label = T('Machine Name')),
Field('nskpassword', 'password', length=512,readable=False, label=T('Machine Password')),
Field('nskreleaseid',length=128, default='',label = T('Release'))
)
db.nsksystem.nskreleaseid.requires = [IS_IN_DB(db,'nskrelease.releaseid'), IS_NOT_IN_DB(db(db.nsksystem.nskmachinename == request.vars.nskmachinename), 'nsksystem.releaseid', error_message='Machine is already registered to the specified release.')]
In the above code the first require is enforced but I dont see a drop down for
IS_IN_DB(db,'nskrelease.releaseid')
And for the second require, when i try to give a conflicting input instead of giving me the desired error, a ticket is issued.
If you put the IS_IN_DB validator in a list, it will no longer generate the select widget. Instead of putting the validators in a list, you can use the _and argument:
db.nsksystem.nskreleaseid.requires = IS_IN_DB(db, 'nskrelease.releaseid',
_and=IS_NOT_IN_DB(db(db.nsksystem.nskmachinename == request.vars.nskmachinename),
'nsksystem.releaseid',
error_message='Machine is already registered to the specified release.'))

Categories