Django - How to create dependent selects - python

My task is to implement a form in which the choice of the value of the second field depends on the value of the first field. (For example, if the value of the first field is Cars, then the second field should show sedan/SUV, etc., if the value of the first field is Commercial vehicles, then the second box should show truck/bus, etc.)
Code models.py:
class TypeTransport(models.Model):
transport_name = models.CharField(max_length=100, verbose_name='kind of transport')
class TypeBodyTransport(models.Model):
transport = models.ForeignKey(TypeTransport, on_delete=models.CASCADE, blank=True, null=True,
verbose_name='kind of transport')
body_name = models.CharField(max_length=100, verbose_name='transport body type')
class Advertisement(models.Model):
transport = models.ForeignKey(TypeTransport, on_delete=models.SET_NULL, blank=True, null=True,
verbose_name='kind of transport')
body = models.ForeignKey(TypeBodyTransport, on_delete=models.SET_NULL, blank=True, null=True,
verbose_name='transport body type ')
Code forms.py:
class CreateAdvertisementForm(forms.ModelForm):
transport = forms.ModelChoiceField(queryset=TypeTransport.objects.all(), to_field_name="transport_name")
body = forms.ModelChoiceField(queryset=TypeBodyTransport.objects.filter(transport=transport),
to_field_name="body_name")
class Meta:
model = Advertisement
fields = ('transport', 'body')
I thought it could be done with filter(transport=transport), but this error is returned: TypeError: Field 'id' expected a number but got <django.forms.models.ModelChoiceField object at 0x7f40d7af5ac0>.
Can you please tell me how to implement the feature I need?

have you tried:
class CreateAdvertisementForm(forms.ModelForm):
transport = forms.ModelChoiceField(queryset=TypeTransport.objects.all(), to_field_name="transport_name")
body = forms.ModelChoiceField(queryset=TypeBodyTransport.objects.filter(transport=transport.id),
to_field_name="body_name")
class Meta:
model = Advertisement
fields = ('transport', 'body')
instead of transport = transport, try transport = transport.id

I solved this problem using the django-smart-selects library. Additionally I can say that in the forms it is necessary to remove field which references to the ModelChoiceField, because it interferes with its queryset parameter. I'm still a beginner, so I didn't immediately guess that the problem was in chained selects (I edited the question).

Related

In Django Tables2, how do you make a column show text from a table referenced by a foreign key?

After reading all the docs and answers I can find, and burning a whole day, I still can't make this work. Using Django Tables2, I want to show a list of instruments; the instruments table includes a foreign key to an instrumentsType table. When I list the instruments and their attributes, I want to use the foreign key to substitute the textual instrument type description from the other table. I have tried every combination of double underscores and other accessor techniques, but so far all I get is the dreaded -- in the column. (Displaying just the record ID works).
from .models import Instrument
from django_tables2 import A
from instrumenttypes.models import InstrumentType
class InstrumentTable(tables.Table):
id = tables.LinkColumn('instrument_details', args=[A('station_id')])
class Meta:
model = Instrument
template_name = "django_tables2/bootstrap.html"
fields = ("id", "instrument", "nickname", "serialNo",
"instrument__instrumenttype_id__instrumenttypes__id_instrumentType" )
The models involved are:
Instruments model.py
from django.db import models
from instrumenttypes.models import InstrumentType
from stations.models import Station
# Create your models here.
class Instrument(models.Model):
instrument = models.CharField(max_length=40)
instrumenttype = models.ForeignKey(InstrumentType, on_delete=models.CASCADE, null=True)
station = models.ForeignKey(Station, on_delete=models.CASCADE, default=1)
serialNo = models.CharField(max_length=60, null=True, blank=True)
dateAdded = models.DateTimeField("Date Added", null=True, blank=True)
dateRemoved = models.DateTimeField("Date Removed", null=True, blank=True)
status = models.CharField(max_length=10, null=True, blank=True)
nickname = models.CharField(max_length=40, null=True, blank=True)
InstrumentTypes model.py
from django.db import models
class InstrumentType(models.Model):
instrumentType = models.CharField(max_length=40)
Resulting output:
ID Instrument Nickname SerialNo Instrumenttype
4 instr2 nock2 123 —
The most relevant online references I have found are here and here; but having tried the suggestions, no luck. What am I missing?
I've been struggling to get something working too (but I finally did), and I found the examples too brief.
I think you want to get rid of this stuff in the Meta class
"instrument__instrumenttype_id__instrumenttypes__id_instrumentType"
I think Meta.fields should just be a list of field names, and that you refer to the attribute in the other table from the point of view of the type of object you will later pass in to the IntrumentTable constructor (and that is named in the Meta.model attribute:
from django_tables2.utils import Accessor
class InstrumentTable(tables.Table):
instrument_type = tables.Column(accessor=Accessor('instrumenttype.name'))
class Meta:
model = Instrument
template_name = "django_tables2/bootstrap.html"
fields = ("id", "instrument", "nickname", "serialNo", "insrument_type")
Then, in view, make an instance of InstrumentTable
def myview(request):
table_to_render = InstrumentTable(Instrument.objects)
return render(request, sometemplate, {table: table_to_render})
You didn't show your view, and I know there may be a different way. If you have the whole thing in a repo somewhere, leave a link.

How to create form field for multiple models in Django?

Tried to figure this out on my own but stumped -
I'm working on a crm project to learn Django and have gotten stuck trying to incorporate activities between a user and client. Specifically, I'm trying to make it possible to record an email interaction and to have the from/to fields reference either a user or client model. So essentially an email can be recorded as either from a user to client or vice versa. The next part would be to allow for multiple clients or users to be tagged in the correct fields of this interaction.
I've tried incorporating the to and from fields as models so that they can use the GenericForeignKey class like so:
class Activity(models.Model):
owner = models.ForeignKey(User, on_delete=models.DO_NOTHING)
date = models.DateTimeField()
class EmailTo(models.Model):
content_type = models.ForeignKey(ContentType, on_delete=models.DO_NOTHING)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type')
class EmailFrom(models.Model):
content_type = models.ForeignKey(ContentType, on_delete=models.DO_NOTHING)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type')
class EmailActivity(Activity):
emailto = models.ForeignKey(EmailTo, on_delete=models.DO_NOTHING)
emailfrom = models.ForeignKey(EmailFrom, on_delete=models.DO_NOTHING)
body = models.TextField(blank=True)
but now I'm stuck trying to figure out how to represent that on a form. I thought maybe I could use a union to combine two queries into one field using a ModelMultipleChoiceField:
class EmailActivityForm(forms.ModelForm):
emailto = forms.ModelMultipleChoiceField(
queryset=Client.objects.all().union(User.objects.all()),
label="To")
emailfrom = forms.ModelMultipleChoiceField(
queryset= Client.objects.all().union(User.objects.all()),
label="From")
body = forms.CharField(widget=forms.Textarea)
class Meta:
model = EmailActivity
exclude = '__all__'
but see now that this is not possible since the queries are not the same size.
I'm starting to think I need to go back to my user models and make users and clients inherit from one "Person" model or something similar. Wanted to check here first though to see if I was possibly missing something.
you better write your own manual form
class EmailActivityForm(forms.Form):
emailto = forms.ModelMultipleChoiceField(queryset=Client.objects.all().union(User.objects.all()), label="To")
emailfrom = forms.ModelMultipleChoiceField(queryset= Client.objects.all().union(User.objects.all()), label="From")
body = forms.CharField(widget=forms.Textarea)
and keep going with all the other fields left.
by the way, the forms.ModelForms is made for a single model, not multiple

How can i perform the right reverse query in ManytoMany in Django

I'm trying to perform a reversed query for a manytomany fields in Django, but it keeps gives me nothing, here is my code
models.py
class Product(models.Model):
category = models.ForeignKey(Category, on_delete=models.CASCADE)
name = models.CharField(max_length=120)
image = models.ImageField(upload_to='products')
branch = models.ManyToManyField(Branch, related_name='branches')
class Branch(models.Model):
area = models.ForeignKey(Area, on_delete=CASCADE)
name = models.CharField(max_length=1200)
phone = models.CharField(max_length=30, null=True, blank=True)
address = models.CharField(max_length=1200, null=True, blank=True)
tax_value = models.DecimalField(decimal_places=2, max_digits=4)
views.py
for branch in product_object.branches.all():
print(branch)
The branch is always nothing !!
For some reason, the related name is not calling it anymore. I called it using the model name (lower cased).
This is how it worked
for branch in product_object.branch.all():
Just to complete your answer above, I think the way you have your model set up is a little misleading and confusing. I think this would improve clarity:
class Product(models.Model):
category = models.ForeignKey(Category, on_delete=models.CASCADE)
name = models.CharField(max_length=120)
image = models.ImageField(upload_to='products')
branches = models.ManyToManyField(Branch, related_name='products')
Since you have a many to many field, a product can have multiple branches, the attribute name should reflect that
When you use the related_name, this would be if you are going from the m2m object. For example, if you have a branch, you could get all it's products by doing branch.products

Having trouble wrapping my head around follower/target models in Models.py

I have just started with making a similar site to Pinterest and the site has follower/target system that I have barely any understanding of. So far, my models.py code is below:
from django.db import models
class User(models.Model):
username = models.CharField(max_length=45, null=True)
email = models.CharField(max_length=200, null=True)
password = models.CharField(max_length=200)
nickname = models.CharField(max_length=45, null=True)
target = models.ManyToManyField(self, through='Follow')
follower = models.ManyToManyField(self, through='Follow')
class Meta:
db_table = 'users'
class Follow(models.Model):
follower = models.ForeignKey(User, on_delete=models.CASCADE, related_name='targets')
target = models.ForeignKey(User, on_delete=models.CASCADE, related_name='followers')
class Meta:
db_table = 'follows'
This code was made with reference to another StackOverflow thread
Django models: database design for user and follower
However, I am having trouble understanding how using "related_name='targets' in 'follower' and "related_name='followers'" in 'target' where I can't see any 'targets'(plural) or 'followers'(plural) in other areas of models.py
Should I get rid of that related_name, since there is no such table called "followers" or "targets"? And if you spot major errors in my code or logic, can you tell me? Thanks!
Should I get rid of that related_name, since there is no such table called followers or targets.
There is never a table named followers or targets. The related_name [Django-doc] is a conceptual relation Django makes to the other model (in this case User). It means that for a User object myuser, you can access the Follow objects that refer to that user through target for example with myuser.followers.all(), so:
Follow.objects.filter(target=myuser)
is equivalent to:
myuser.followers.all()
The default of a related_name is modelname_set, so here that would be follow_set. But if you remove both related_names, then that would result in a name conflict, since one can not add two relations follow_set to the User model (and each having a different semantical value).
if you spot major errors in my code or logic, can you tell me?
The problem is that since ManyToManyFields refer to 'self' (it should be 'self' as string literal), it is ambigous what the "source" and what the target will be, furthermore Django will assume that the relation is symmetrical [Django-doc], which is not the case. You should specify what the source and target foreign keys are, you can do that with the through_fields=… parameter [Django-doc]. It furthermore is better to simply define the related_name of the ManyToManyField in reverse, to avoid duplicated logic.
from django.db import models
class User(models.Model):
username = models.CharField(max_length=45, unique=True)
email = models.CharField(max_length=200)
password = models.CharField(max_length=200)
nickname = models.CharField(max_length=45)
follows = models.ManyToManyField(
'self',
through='Follow',
symmetrical=False,
related_name='followed_by',
through_fields=('follower', 'target')
)
class Meta:
db_table = 'users'
class Follow(models.Model):
follower = models.ForeignKey(
User,
on_delete=models.CASCADE,
related_name='targets'
)
target = models.ForeignKey(
User,
on_delete=models.CASCADE,
related_name='followers'
)
class Meta:
db_table = 'follows'
Here a User object myuser can thus access myuser.follows.all() to access all the users that they follow, myuser.followed_by.all() is the set of Users that follow myuser. myuser.targets.all() is the set of Follow objects that he is following, and myuser.followers.all() is the set of Follow objects that are following that user.

Using Model.objects.all() as a blueprint for a secondary table entry

I am having a bit of trouble with the logic of how this should work so I am hoping it is possible.
I figured out 1 possible solution that is written as an answer below, I will accept it in a few days, but if someone comes up with a better solution, I will negate any answer I post.
Overall I am working on an Apartment Move-Out/Move-In Inspection Application in Django, and in both portions I have universal Locations that must be inspected for each report. I have allowed the InspectionLocations objects to be updated/submitted by clients, which is presenting an issue in how submitted reports should be stored in my Database.
What I want is to use the InspectionLocations table as a blueprint to build an Inspection Report for Move-Ins where the form-fields are generated based on the InspectionLocations objects' location, status, and information attributes/fields.
My issue is right at this point, how do I reference those values as a blueprint to build a report submission when the number of fields in the InspectionLocations can change?
from django.db import models
from apps.units.models import Unit
class Inspections(models.Model):
class Meta:
abstract = True
id = models.AutoField(primary_key=True)
inspection_date = models.DateField()
submitted_by = models.ForeignKey(
'users.CustomUser',
default=None,
null=True,
on_delete=models.SET_NULL,
db_column='submitted_by')
last_update = models.DateTimeField(auto_now=True)
date_added = models.DateTimeField(auto_now_add=True, editable=False)
class MoveInInspections(Inspections):
unit = models.ForeignKey(Unit, on_delete=models.CASCADE, db_column='unit_id')
# should have reference to all InspectionLocation items as reference for submission, how?
class MoveOutInspections(Inspections):
unit = models.ForeignKey(Unit, on_delete=models.CASCADE, db_column='unit_id')
date_notice_given = models.DateField(blank=True, null=True, default=None)
date_vacated = models.DateField(blank=True, null=True, default=None)
# should have reference to all InspectionLocation items as reference for submission, how?
class InspectionLocations(models.Model):
'''
Defualt Inspection Locations are created when a
client is created using code like this:
InspectionLocation.objects.get_or_create(location='Living Room')
InspectionLocation.objects.get_or_create(location='Dining Room')
InspectionLocation.objects.get_or_create(location='Kitchen')
InspectionLocation.objects.get_or_create(location='Bedroom')
InspectionLocation.objects.get_or_create(location='Bathroom')
InspectionLocation.objects.get_or_create(location='Other')
'''
id = models.AutoField(primary_key=True)
location = models.CharField(max_length=50)
status = models.BooleanField(default=None)
information = models.TextField(default=None, blank=True)
I have tried ManyToMany fields and FKs but I cannot seem to get the logic working as anytime an object references an InspectionLocations object it is universally changing data for every report, which is leading be to the idea that I somehow need to use it as a blueprint.
I didn't post this in my question because it was getting long, but my best option so far seems to be to use a Django JSONField (as I am using Postgres), like so:
from django.contrib.postgres.fields import JSONField
class MoveInInspections(Inspections):
unit = models.ForeignKey(Unit, on_delete=models.CASCADE, db_column='unit_id')
data = JSONField()
class MoveOutInspections(Inspections):
unit = models.ForeignKey(Unit, on_delete=models.CASCADE, db_column='unit_id')
date_notice_given = models.DateField(blank=True, null=True, default=None)
date_vacated = models.DateField(blank=True, null=True, default=None)
data = JSONField()
To where I store the values of the InspectionLocations object's in a Dictionary

Categories

Resources