I have a form:
class ProjectInfoForm(forms.Form):
module = forms.ModelChoiceField(
queryset=Module.objects.all(),
)
piece = forms.ModelChoiceField(
queryset=Piece.objects.all(),
required=False,
)
The second field is populated with option from the first using ajax. However, instantiating it like this is not very efficient as it means the second field is populated on page load uneccessarily (not to mention populates the field before it should).
So I tried changing it to:
...
piece = forms.ModelChoiceField(
queryset=Piece.objects.none(),
required=False,
)
I get the desired result but of course the form does not validate has it has no choices to check against.
Is there some way I can validate the form without populating it or even better validate the two fields together as related models?
Any help much appreciated.
I think the easier way is just to roll your own. You'll just need:
A ChoiceField. Using coerce will let you transform IDs into objects transparently
A view that you AJAX component can query to retrieve the list of valid Pieces for a given Module.
A server-side validation method that checks that the Module and the Piece correspond
Related
Lets say I have a form with some fields. I was wondering if it is possible to do dynamic query where I could do a string match while the user is typing into a field. Like when typing into google it returns a list of choices when you type into the search bar. Can someone give me an example on how and where to implement it?
If what you're looking to achieve is fields for a ForeignKey then you can provide a Queryset on the form field then use an app like django_select2 which can then provide a widget which will allow a user to search for items in the Queryset for the field. e.g.
city = forms.ModelChoiceField(
queryset=City.objects.all(),
label=u"City",
widget=ModelSelect2Widget(
model=City,
search_fields=['name__icontains'],
dependent_fields={'country': 'country'},
max_results=500,
)
)
Then in the form, as you started to type into the city field it'd start to search on City.name using an icontains lookup. The docs for this are here.
If that's not what you're looking for then you could just write some Javascript which detected input to a field, then sent an ajax request to a view with the contents of your field. That could then return a response which displayed content in the page related to the input.
I have a formset displayed as a table, and I do not want to validate any of the forms that do not have a specific checkbox ticked. However when the formset is submitted they are getting validated.
Do I need to handle this at the clean_field() method level?
If so how do I stop the form at that point, without rendering the whole formset invalid??
class HILISForm(forms.ModelForm):
summary = forms.CharField(
widget=forms.Textarea(attrs={'rows':3, 'cols':70}),
label='',
required=False)
class Meta:
model = Report
fields = ('reported', 'summary', )
def clean_reported(self):
reported = self.cleaned_data['hilis']
if reported:
return(hilis_reported)
else:
raise(forms.ValidationError('Not checked...'))
if I 'pass' instead of raising the error- then this form still appears in my cleaned_dict which I do not want.
I'm sure there is a much easier and cleaner way to do it, but if you get stuck you could do it by creating an id for each input field, and then creating/saving the object with your logic in the view instead. It looks like you have a lot of things to check and wouldn't be ideal, but is one way to do it.
I had a tricky validation scheme for one of my projects and found it easier to just create the form, and then process it in the view on post. You can still add error messages to the form and do all of that from the view also.
I'm looking for a django way to handle some complex forms with a lot of business logic. The issue is many of my forms have dependencies in them.
Some examples:
1. two "select" (choice) fields that are dependent on each other. For example consider two dropdowns one for Country and one for City.
2. A "required-if" rule, i.e set field required if something else in the form was selected. Say if the user select "Other" option in a select field, he need to add an explanation in a textarea.
3. Some way to handle date/datetime fields, i.e rules like max/min date?
What I'm doing now is implementing all of these in the form clean(), __init__(), and write some (tedious) client-side JS.
I wonder if there is a better approach? like defining these rules in a something similar to django Meta classes.
I'm going to necro this thread, because I don't see a good answer yet. If you are trying to validate a field and you want that field's validation to depend on another field in that same form, use the clean(self) method.
Here's an example: Say you have two fields, a "main_image" and "image_2". You want to make sure that if a user uploads a second image, that they also uploaded a main image as well. If they don't upload an image, the default image will be called 'default_ad.jpg'.
In forms.py:
class AdForm(forms.ModelForm):
class Meta:
model = Ad
fields = [
'title',
'main_image',
'image_2',
'item_or_model_names',
'category',
'buying_or_selling',
'condition',
'asking_price',
'location',
]
def clean(self):
# "Call the cleaned form"
cleaned_data = super().clean()
main_image = cleaned_data.get("main_image")
image_2 = cleaned_data.get("image_2")
if "default_ad" not in image_2:
# Check to see if image_2's name contains "default_ad"
if "default_ad" in main_image:
raise forms.ValidationError(
"Oops, you didn't upload a main image."
)
If you want more info, read: https://docs.djangoproject.com/en/2.2/ref/forms/validation/#cleaning-and-validating-fields-that-depend-on-each-other
Good luck!
1.This task is souly related the the html building of the form, not involving django/jinga.
2.Here, you go to dynamic forms. the best and most used way nowdays to do this, is through JS.
3.try building a DB with a "time" type field and then through "admin" watch how they handle it. all of special fields useage is covered here: https://docs.djangoproject.com/en/1.9/ref/forms/fields/
Let's say we have an app called Closet and it has some models:
# closet.models.py
class Outfit(models.Model):
shirt = models.ForeignKey(Shirt)
pants = models.ForeignKey(Trouser)
class Shirt(models.Model):
desc = models.TextField()
class Trouser(models.Model):
desc = models.TextField()
class Footwear(models.Model):
desc = models.TextField
Using generic detail view, it's easy to make the URL conf for details on each of those:
#urls.py
urlpatterns = patterns('',
url(r'^closet/outfit/(?P<pk>\d+)$', DetailView(model=Outfit), name='outfit_detail'),
url(r'^closet/shirt/(?P<pk>\d+)$', DetailView(model=Shirt), name='shirt_detail'),
url(r'^closet/trouser/(?P<pk>\d+)$', DetailView(model=Trouser), name='trouser_detail'),
url(r'^closet/footwear/(?P<pk>\d+)$', DetailView(model=Footwear), name='footwear_detail'),
)
What I'd like to do next is define the views that will create a new object of each type. I would like to do this with an extended version of CreateView which will be able to handle data on pre-populated fields.
Specifically, I want the following behavior:
If I visit /closet/outfit/new I want to get a standard ModelForm for the Outfit model with everything blank and everything editable.
If I visit /closet/outfit/new/?shirt=1 I want to see all the fields I saw in case 1) but I want the shirt field to be pre-populated with the shirt with pk=1. Additionally, I want the shirt field to be displayed as un-editable. If the form is submitted and is deemed to be invalid, when the form is redisplayed I want the shirt field to continue to be un-editable.
If I visit /closet/outfit/new/?shirt=1&trouser=2 I want to see all the fields I saw in case 1) but now both the shirt and trouser fields should be preopoulated and uneditable. (I.e. only the footwear field should be editable.)
In general, is this possible? I.e. can the querystring modify the structure of the displayed form in this way? I want to accomplish this in the DRYest way possible. My gut tells me this should be doable with class based views and perhaps would involve model_form_factory but I can't get the logic straight in my mind. In particular, I wasn't sure whether it was possible to have the class-based-view access the request.REQUEST (i.e. the request.POST or request.GET parameters) at the time that the ModelForm is being constructed.
Perhaps its possible only if I use different querystring keywords for the locked fields. I.e. perhaps the URL's need to be: /closet/outfit/new/?lock_shirt=1 and /closet/outfit/new?lock_shirt=1&lock_trouser=2. Perhaps if its done that way the POST handler would be handed both a list of locked fields (for the purposes of form display in the browser) along with a regular list of all the model fields for the purpose of actually creating the object.
Why do I want this: In the template for the footwear_detail I would want to be able to make a tag like
<a href="{% url outfit_new %}?footwear={{object.pk}}>Click to create a new outfit with this footwear!</a>
In general, it would be really useful to be able to make links to forms whose "structure" (not just values) changes depending on the querystring passed.
Responding to the great suggestion from Berislav Lopac:
So I went ahead and did:
class CreateViewWithPredefined(CreateView):
def get_initial(self):
return self.request.GET
This gets me 90% of what I need. But let me flesh out the situation a bit more. Say I add two fields to the Outfit model: headgear = models.ManyToManyField('headgear') and awesomeness_rating = models.FloatField().
Two problems:
If I visit /closet/outfit/new/?awesomeness_rating=10 then my form pre-fills with [u'10'] instead of just filling with 10. Is there a filter I should use in my template or a bit of processing I can add to my view to make the formatting more appropriate?
If I want to pre-specify a few pieces of headwear, what is the right format to pass what feels like a python list in through a query string? I.e. should I do /closet/outfit/new/?headgear=1,2,3? If so, will Django correctly figure out that I'd like to pre-select the 3 pieces of headgear with those ID's?
Continuing to work on this...
class CreateViewWithPredefined(CreateView):
def get_initial(self):
initial = super(CreateView, self).get_initial()
for k, v in self.request.GET.iterlists():
if len(v) > 1:
initial.update({ k : v })
else:
initial.update({ k : v[0] })
return initial
This seems to kill 2 birds with one stone: numerical data gets coerced from unicode to numerical and it flattens lists when possible (as intended). Need to check if this works on multi-valued fields.
It's self.request, anywhere in a CBV. :-)
OK, let me make this answer more comprehensive. Basically, what you want is the get_initial method, which is contributed by the FormMixin. Override it to populate the initial values for your fields.
I want to be able to seat a party at table. First I need to display the form, so I create the model form with a extra field called open_tables. This has to be every table marked AVAILABLE that has the capacity. The problem is that I don't know how to reference the number_in_party field from the queryset. I've tied self.base_fields, but self doesn't work. I've tried SeatPartyForm.model.number_in_party, that doesn't work. This is happening on the get, and number_in_party is filled at this point. Is there any way to do this query?
class SeatPartyForm( ModelForm):
open_tables = forms.ModelChoiceField(queryset=Table.objects.filter(status__exact=Table.AVAILABLE).exclude(max_capacity__lt = model.base_fields['number_in_party']))
class Meta:
model = Party
fields = ('name', 'number_in_party')`
You don't know the actual number_in_party before user fills in one. The server-side Django form cannot do the limitation automatically for you.
Thus you need to either change open_tables after number_in_party is available, via javascript; or split the form to two parts, in the first part user fills in number_in_party, in the second part, in server side you could filter open_tables according to the ready value of number_in_party.