using initial on django MultipleChoiceField on many-to-many relation - python

In my model, I have:
flowcell = models.ForeignKey("FlowCell", on_delete=models.PROTECT)
lanes = models.ManyToManyField("main.FlowCellLane", related_name='demuxers', blank=True)
in my form, I want these to be selectable, based on available FlowCellLanes. So I pop flowcell to a variable and use it to see which 'Lanes' are there:
class DemuxerForm(forms.ModelForm):
class Meta:
model = Demuxer
exclude = ["owner", "pid", "flowcell"]
lanes = forms.MultipleChoiceField(widget=forms.CheckboxSelectMultiple)
def __init__(self, *args, **kwargs):
self.flowcell = kwargs.pop('flowcell')
super().__init__(*args, **kwargs)
self.fields['lanes'].choices = sorted([(lane.pk, str(lane.lane_number))
for lane in self.flowcell.lanes.all()])
Now I would like to have all available checkboxes checked. But I don't know how I could do that. At the spot where initial= could be, 'self' is off course not available... any ideas?

I figured it out:
choices = self.flowcell.lanes.values_list("pk", lane_number").order_by("lane_number")
self.fields['lanes'].choices = choices
self.fields["lanes"].initial = [pk for pk, _ in choices]

Related

Django Foreign Key Reverse Filtering

I am still relatively new to Django and still struggle somewhat with ForeignKey filtering and I'd appreciate any help with my problem. I have 2 models below and in my PositionUpdateForm I need the 'candidate' field choices to be only the applicants to that position.
class Position(models.Model):
title = models.CharField(max_length=128)
candidate = models.ForeignKey('careers.Applicant',
on_delete=models.SET_NULL,
related_name='candidates',
blank=True,
null=True
)
class Applicant(models.Model):
first_name = models.CharField(max_length=128)
blank=False,
)
position = models.ManyToManyField(Position,
related_name='applicants',
blank=True
)
In my form I was trying each of the following:
class PositionUpdateForm(forms.ModelForm):
candidate = forms.ModelChoiceField(queryset=Applicant.objects.filter(???))
def __init__(self, *args, **kwargs):
super(PositionUpdateForm, self).__init__(*args, **kwargs)
self.fields['candidate'].queryset = Applicant.objects.filter(???)
Thank you for any assistance.
If you want to have the Applicants that have a position to that Position, you can obtain that with:
class PositionUpdateForm(forms.ModelForm):
candidate = forms.ModelChoiceField(queryset=Applicant.objects.empty())
def __init__(self, *args, **kwargs):
super(PositionUpdateForm, self).__init__(*args, **kwargs)
self.fields['candidate'].queryset = Applicant.objects.filter(position=self.instance)
or we can use the relation in reverse:
class PositionUpdateForm(forms.ModelForm):
candidate = forms.ModelChoiceField(queryset=Applicant.objects.empty())
def __init__(self, *args, **kwargs):
super(PositionUpdateForm, self).__init__(*args, **kwargs)
self.fields['candidate'].queryset = self.instance.applicants.all()
Note that you can only use this when you update a Position model, since otherwise there are no related Applicant records of course.

Is there any way to customize the order of multiple fields for forms.Form class with a field initiated by __init__?

When I render the form to a HTML template,
a certain field of form which is initiated by init is ordered always at bottom of table, even though I defined the field at the middle of form class.
Is there any way or method to customize the order of fields in the form where a initiated field exists by init.
I wanna put the field in the middle of form table in HTML template.
A screenshot of the rendered template:
In the screenshot,
the field "category_name" is ordered at the bottom of tag
I wanna change the order to the middle of table.
I am using Django 2.2 and python 3.7 on Windows 10.
Thanks
from django import forms
from .models import Category_name
class MakePurchaseLog(forms.Form):
buy_date = forms.DateField(input_formats=['%Y-%m-%d'])
shop = forms.CharField(max_length=50)
def __init__(self, user, *args, **kwargs):
super(MakePurchaseLog, self).__init__(*args, **kwargs)
self.fields['category_name'] = forms.ChoiceField(
choices = [(item.category_name, item.category_name) \
for item in Category_name.objects. \
filter(owner=user)])
goods_name = forms.CharField(max_length=50)
price = forms.IntegerField(min_value=0)
memo = forms.CharField(max_length=50, required=False)
field_order = ['category_name']
The fact that the __init__ is placed in the middle of the class, will not make any difference, since this is a function, and the evaluation is thus "postponed" until you actually create a MakePurchaseLog form object.
I think the most elegant solution here is to just already define the field in your form, and then in the __init__ function alter the choices, like:
class MakePurchaseLog(forms.Form):
buy_date = forms.DateField(input_formats=['%Y-%m-%d'])
shop = forms.CharField(max_length=50)
category_name = forms.ChoiceField()
goods_name = forms.CharField(max_length=50)
price = forms.IntegerField(min_value=0)
memo = forms.CharField(max_length=50, required=False)
def __init__(self, user, *args, **kwargs):
super(MakePurchaseLog, self).__init__(*args, **kwargs)
self.fields['category_name'].choices = [
(item.category_name, item.category_name)
for item in Category_name.objects.filter(owner=user)
]
We thus populate the choices of the category_name field in the __init__ function, but we define the field already at the class level.

Changing the choices in Django Model according to a field value

If for example, I have a class Summary,
each Instance of the class Summary, can be one subject:
subjects = (
('english', 'אנגלית'),
('bible', 'תנ"ך'),
('history', 'היסטוריה'),
('civics', 'אזרחות'),
('language', 'לשון'),
('literature', 'ספרות'),
)
class Summary(models.Model):
...
subject = models.CharField(max_length=20, choices=subjects)
...
Now I've decided I want to hardcode some topics for each subject, so if Summary.subject = "literature" I want to add a field
subtopic = models.CharField(choices=literature_subtopics)
and make the choices equal to:
literature_subtopics = (
('poems', 'שירה'),
('short_stories', 'סיפורים קצרים'),
('plays', 'מחזות'),
('novels', 'נובלות'),
)
If the subject was English then english_subtopics would be used for the choices field.
I want to hard-code all these divisions because they will not change more than once every few years if at all, storing them in a database makes zero sense.
I need to somehow set up all these divisions for each subject, and make Django set the choices field for the subtopic appropriately.
can I override the init method to accomplish this somehow? I heard that's a bad idea and can break things.
Even if the data doesn't change often, it seems most natural to put data in the database and Python in Python files. Your proposed solution seems like you're fighting the way Django wants to do things.
What do think of a database solution?
class Subject(models.Model):
parent = models.ForeignKey("self")
name = models.CharField(max_length=100)
hebrew_name = models.CharField(max_length=100)
class Summary(models.Model):
...
subject = models.ForeignKey("Subject")
...
class SubjectForm(forms.Form):
subject = forms.ModelChoiceField(queryset=Subject.objects.none())
...
def __init__(self, *args, **kwargs): # see http://stackoverflow.com/a/4880869/1477364
sub = kwargs.pop('parent_subject')
super(SubjectForm, self).__init__(*args, **kwargs)
parent_subject = Subject.objects.get(name=sub)
sub_subjects = Subject.objects.filter(parent=parent_subject)
self.fields['subject'].queryset = forms.ModelChoiceField(queryset=sub_subjects)
Note that the code implies there will always be a parent Subject passed to SubjectForm. (You'll need a "root" Subject.)
You could set the choices dynamically using a function.
# models.py
def get_choices():
choices_tuple_list = []
... # your logic to define choices
return choices_tuple_list
class Summary(models.Model):
... # Summary definition
subject = models.CharField(max_length=20, blank=True)
def __init__(self, *args, **kwargs):
super(Summary, self).__init__(*args, **kwargs)
self._meta.get_field_by_name('subject')[0]._choices = get_choices()
See docs

Django Edit Form Queryset made of Query + Current Selected Option - How to get?

My forms.py
class CreateVesselForm(forms.ModelForm):
class Meta:
model = Vessel
exclude = ['active']
# Filtering Choices
def __init__(self, *args, **kwargs):
super(CreateVesselForm, self).__init__(*args, **kwargs)
# Filtering just Free Slots
self.fields['slot'].queryset = Slot.objects.filter(is_free=True)
# Filtering just Free Storages
self.fields['storage'].queryset = Storage.objects.filter(is_free=True)
The Slot Field is a ForeignKey and the Storage Field is a ManytoMany Field.
In my views.py, by the time I save this form I change the status of "is_free" to False. However when the time to edit this item(Vessel) - getting it from a form instance - the options already selected before, no longer appear in the form fields because my queryset is filtering just by status=True.
The perfect form queryset for me would be:
for ForeignKey
the current selected item "vessel.slot" + Slot.objects.filter(is_free=True) ?
for ManytoMany
the current selected item "vessel.storage" + Storage.objects.filter(is_free=True) ?
Is there a way to get it done ?
You can try like this:
class CreateVesselForm(forms.ModelForm):
class Meta:
model = Vessel
exclude = ['active']
# Filtering Choices
def __init__(self, *args, **kwargs):
super(CreateVesselForm, self).__init__(*args, **kwargs)
if kwargs['instance']:
self.fields['storage'].queryset = kwargs['instance'].storage.all()|Storage.objects.filter(is_free=True)
self.fields['slot'].queryset = Slot.objects.filter(pk=kwargs['instance'].slot.pk)|Slot.objects.filter(is_free=True)

django creating models inside of form for manytomany field

I'm making recipes website and therefore I have recipe model for which I want to create form that looks like this:
class Recipe(models.Model):
....
products = models.ManyToManyField(ProductMeasurement)
....
And I have ProductMeasurement model and form already:
class ProductMeasurement(models.Model):
product = models.ForeignKey(Product)
measurement = models.ForeignKey(Measurement)
value = models.FloatField()
class FridgeForm(forms.Form):
product = forms.ModelChoiceField(queryset=None, widget=forms.Select(attrs={'class': 'form-control'}))
amount = forms.DecimalField(decimal_places=2, widget=forms.NumberInput(attrs={'class': 'form-control'}))
measurement = forms.ModelChoiceField(queryset=None, widget=forms.Select(attrs={'class': 'form-control'}))
def __init__(self, *args, **kwargs):
super(FridgeForm, self).__init__(*args, **kwargs)
self.fields['product'].queryset = Product.objects.all()
self.fields['measurement'].queryset = Measurement.objects.all()
What I want to do is create form for Recipe model. The problem is that there's not going to be already ProductMeasurements that user wants for his recipe. Therefore I need to find a way so that user can create ProductMeasurement inside of Recipe form. What are possible approaches here ?
django formsets was what I was looking for.

Categories