I have 2 tables "Client" and "Location".
class Client(models.Model):
name = models.CharField(max_length=50)
class Location(models.Model):
name = models.CharField(max_length=50)
A Client can be in many Locations and a Location can have many Clients.
I created a third table to hold this relationship:
class Client_Location(models.Model):
client = models.ForeignKey(Client, on_delete=models.CASCADE)
location = models.ForeignKey(Location, on_delete=models.CASCADE)
I created a form to test whether i can make the dropdownlist dynamic, so if i were to pick a client, any location linked to that client would only appear.
class ClientLocationForm(forms.ModelForm):
class Meta:
model = Client_Location
fields = '__all__'
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['location'].queryset = Location.objects.none()
So far i was only able to make the location field blank. Not sure where to go next as examples i've seen aren't exactly like mine.
With minimal changes to your code, you may add the existing Client_Location model as through model for a new explicit ManyToMany relationship. To do so, add the following field to your Client model:
locations = models.ManyToManyField('Location', through='Client_Location', related_name='clients')
If you need fully dynamic updates, you need to write a view which provides a list of locations for a specified client (client.locations.all()) and then show them on your page.
Related
I need to create a model form in Django and have the following arbitrary scenario.
Real Estates
============
ID
...some extra fields...
CityID
Cities
======
ID
Name
Region
======
ID
Name
Country
=======
ID
Name
What I would like to do is to let user choose the Country first, then Region and lastly the City. (Populate the child category with javascript after user selects the parent category.) However, I don't want to add the 'Region' and 'Country' fields to the 'Real Estate' table. The order of the fields are also important, that is, 1) Country, 2) Region and 3) City.
Can you suggest any approach to this? Thanks!
I'm assuming you are trying to show the user a limited set of options for "Region" after he selected a country and a limited set of options for "City" after he selected the region so as to provide a way to sensibly select a city for the real estate instead of having to pick something from a long list of random cities?
You could specify additional fields on the RealEstate ModelForm that aren't actual fields on the RealEstate model and provide logic in the form's .__init__() and if needed also in .clean() and .save() methods to take care of the additional fields. Perhaps something like this:
class Country(models.Model):
name = models.CharField(...)
class Region(models.Model):
name = models.CharField(...)
country = models.ForeignKey(Country, on_delete=models.CASCADE)
class City(models.Model):
name = models.CharField(...)
region = models.ForeignKey(Region, on_delete=models.CASCADE)
class RealEstate(models.Model):
name = models.CharField(...)
city = models.ForeignKey(City, on_delete=models.CASCADE)
class RealEstateForm(forms.ModelForm):
country = forms.ChoiceField(required=False)
region = forms.ChoiceField(required=False)
class Meta:
model = RealEstate
fields = ['name', 'city', 'country', 'region']
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['country'].choices = Country.objects.all().values('id', 'name)
self.fields['region'].choices = Region.objects.all().values('id', 'name', 'country__id')
self.fields['city'].choices = City.objects.all().values('id', 'name', 'region__id', 'region__country__id')
Providing choices that include the referenced region ID and country ID for each city will allow you to filter these in the front end if you manage to use these choices as the user is selecting country and region without having to make a separate backend request to get the filtered list. Of course, you would end up with a larger response being sent this way in one go - if your data set size is very large (how many countries, how many regions, how many cities) this may not be wanted.
This has got to be a common requirement but nothing I've found on SO or in Django docs that works for me. I'm really new to Django. My problem: I need to change the list of Areas that are presented in a form dropdown list according to the company that has Area ownership.
In my app:
Accounts (i.e Users) are members of Company. A Company manages an Area. Within the Area are a number of Routes. Routes can be added/updated/removed or assigned to different Areas by the Company.
So on my forms I want to make sure that only Areas that belong to a Company are displayed in the dropdown list. Essentially a user would select an Area, then CRUD routes associated with the Area.
class Company(models.Model):
name = models.CharField(...
account_number = models.CharField(...
...
class Account(models.Model):
name = models.OneToOneField(User...
company = models.ForeignKey(Company)
...
class Area(models.Model):
owner = models.ForeignKey(Company)
number = modes.PositiveIntegerField(...
class Route(models.Model):
owner = models.ForeignKey(Company)
area = models.ForeignKey(Area)
In forms.py
class RouteCreateForm(forms.ModelForm):
class Meta:
model= Route
fields= [
'area',
'route_number',
...
]
Adding:
self.fields['area'].queryset = Area.objects.filter(owner_id = 2)
provides the correct filtering but of course is not dynamic.
I've a lot of variations on :
def __init__(self, *args, **kwargs):
??how to pass in user to ultimately get to owner_id??
self.fields['area'].queryset = Area.objects.filter(owner_id = owner_id)
but can't get the middle right. I've also tried passing in 'user' but the only results in a TypeError at /account/setup/route/create
init() missing 1 required positional argument: 'user'
If you are using generic CreateView, you can modify your form per request by overriding get_form() on your view. That would look like this:
class RouteCreateView(generic.CreateView):
form_class = RouteCreateForm
def get_form(self):
form = super(RouteCreateView, self).get_form()
form.fields['area'].queryset = Area.objects.filter(owner=self.request.user)
return form
I have two models, one that loads the other model it's titles in a choice field dynamically. I fixed it so far that if I add a new object to the model which the titles are used from by updating the choice list in the init method, the choice list gets updated immediately. However when I decide to choose it as option and save it I get: Select a valid choice. example is not one of the available choices. When I restart the server it does work, what I did:
model:
class Assessment(models.Model):
title = models.CharField(max_length=200)
SPECIFIC_REQUIREMENTS_CHOICES = ()
SPECIFIC_REQUIREMENTS_CHOICES_LIST = []
for sRequirement in SpecificRequirements.objects.all():
SPECIFIC_REQUIREMENTS_CHOICES_LIST.append((sRequirement.title, sRequirement.title))
SPECIFIC_REQUIREMENTS_CHOICES = SPECIFIC_REQUIREMENTS_CHOICES_LIST
sRequirementChoice = models.CharField(max_length=200, choices=SPECIFIC_REQUIREMENTS_CHOICES,
default='')
forms:
class AssessmentForm(forms.ModelForm):
class Meta:
model = Assessment
fields = ['title', 'sRequirementChoice']
def __init__(self, *args, **kwargs):
super(AssessmentForm, self).__init__(*args, **kwargs)
SPECIFIC_REQUIREMENTS_CHOICES_LIST = []
for sRequirement in SpecificRequirements.objects.all():
SPECIFIC_REQUIREMENTS_CHOICES_LIST.append((sRequirement.title, sRequirement.title))
SPECIFIC_REQUIREMENTS_CHOICES = SPECIFIC_REQUIREMENTS_CHOICES_LIST
self.fields['sRequirementChoice'].choices = SPECIFIC_REQUIREMENTS_CHOICES
That's not how Model choices work. You are not supposed to populate choices dynamically in models.
You should consider using a ForeignKey relation with SpecificRequirements in your model.
I have an object structure that looks like so:
Customer -- one to many -- Locations
Locations -- many to many -- Departments
Departments -- one to many -- Objects
here is my models.py (my admin.py is standard):
class Customer(models.Model):
customerName = models.CharField(max_length=64)
class Department(models.Model):
departmentName = models.CharField(max_length=64)
class Location(models.Model):
customer = models.ForeignKey(Customer)
departments = models.ManyToManyField(Department)
class Object(models.Model):
location = models.ForeignKey(Location)
department = models.ForeignKey(Department)
The problem is that when I want to set the department for objects I get every department in the django admin drop down. I even get the departments that are associate with locations of different customers.
Also, when I am setting the department of an object, I get the same list of all available departments, even those associated with different customers.
How can I have the drop down only show me the departments that a customer supports?
A quick one line solution to filter down a many to many relationship is put this line in your admin object:
filter_horizontal = ('departments',)
You can provide your own form with filtered queryset
class DepartmentAdminForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(DepartmentAdminForm, self).__init__(*args, **kwargs)
self.fields['customers'].queryset = Customer.objects.filter(...)
class Meta:
model = Department
class DepartmentAdmin(admin.ModelAdmin):
form = DepartmentAdminForm
I believe the answer is to use the formfield_for_manytomany
https://docs.djangoproject.com/en/1.4/ref/contrib/admin/#django.contrib.admin.ModelAdmin.formfield_for_foreignkey
I have four models in my models.py which are:
models.py
class Course(models.Model):
course_code = models.CharField(max_length=100,unique=True)
title = models.CharField(max_length=200)
short = models.CharField(max_length=50)
elective_group = models.CharField(max_length=100)
class Unit(models.Model):
title = models.CharField(max_length=100)
short = models.CharField(max_length=50)
course = models.ForeignKey(Course)
class Pattern(models.Model):
pattern_name = models.CharField(max_length=200)
class ExamSchedule(models.Model):
exam_date = models.DateTimeField()
course = models.ForeignKey(Course)
pattern = models.ForeignKey(Pattern)
units = models.ManyToManyField(Units)
I have all these models register with admin site, so that i can use admin functionality for these models.
My problem is when a user creates or edits a ExamSchedule object , i want the units(field) multivalue widget should contains only those values that are associated with a course as every course can have multiple units. So if user creates an Examschedule object and after selecting a course from dropdown the unit widget should only contains those units that related to the course selected.
Django-Smart-Select could have been useful but it only supports foreign key chained and grouped selects nor ManyToManyField chained select.
Thanks
You can send the selected course with a Ajax request and do this to get the related units.
Lets say you select communication networks (cn) as the course you can get the related units like so:
cn_units = Unit.object.filter(course = 'cn').values_list('id',flat=True)
This will return a single list of all the related units to that course.
You can send this list as a response to your ajax request, iterate over this list and populate the select box for unit in ExamSchedule form. I consider plain ajax because its very flexible.