How to write view from ModelChoiceField response? - django

I'm new to Django forms and am getting hung up on something that seems like it should be very simple.
I want to create a dropdown selector that directs users to detail pages, one for each year.
In models.py I have:
class Season(models.Model):
year = models.IntegerField(unique = True, max_length=4, verbose_name = "Season (year)")
…
class season_choice(forms.Form):
choice = forms.ModelChoiceField(queryset=Season.objects.all().order_by('year'), empty_label="Season")
class Meta:
model = Season
In my template:
<form action="/season_detail/{{ choice.year }}" method="get">
{{ season_choice.as_p }}
<input type="submit" value="Go" />
</form>
The dropdown selector shows up fine, producing choices formatted like so:
<select id="id_choice" name="choice">
<option selected="selected" value="">Season</option>
<option value="1">1981</option>
<option value="2">1982</option>
<option value="3">1983</option>
…
Choosing and submitting a year, for instance 1983, now takes me to /season_detail/?choice=3 when what I what is something like /season_detail/?choice=1983
I assume I need to write that into views.py, but after reading through the Django docs and searching through the forum here and trying several approaches I'm more confused than ever.

It looks like you're mixing forms.Form and forms.ModelForm in class season_choice based on your use of forms.Form but also declaring a Meta class.
If you need a different form widget than the model default, you can over ride it in the Meta class if using a ModelForm. When using ModelForms it's best practice to explicitly list the fields to be displayed so that future fields (potentially sensitive ones) are not added by default.
class SeasonForm(forms.ModelForm):
class Meta:
model = Season
fields = ['year']
widgets = {
'year': forms.widgets.Select(),
}
Django models also have a Meta class that will allow you to provide a default ordering:
class Season(models.Model):
year = ...
class Meta:
ordering = ['-year']
If you don't want the entire Model class to have that ordering, you can either change this in your view or create a proxy model, then in your form use model = SeasonYearOrdering.
class SeasonYearOrdering(Season):
class Meta:
ordering = ['-year']
proxy = True
Another item of interest is the hard coded url in your template. You can give the urls in your urls.py names. Then in your template, you can reference these names so that if your urls.py path ever changes, your templates refer to the name and not the hard coded path.
So:
<form action="/season_detail/{{ choice.year }}" method="get">
Becomes (season_detail is the name from urls.py):
<form action="{% url "season_detail" choice.year %}" method="get">

You may change the value of option by adding to_field_name='year' to the choice ModelChoicefield in the form.
So you'll get
<option value="1981">1981</option>
<option value="1982">1982</option>
<option value="1983">1983</option>

Related

How to pass dynamic filtering options in django_filters form instead of all model objects?

I have the following structure of the project (models):
Company (based on Groups) <-- Products (foreignKey to Company) <-- Reviews (foreignKey to Products).
Inside template i want to give a user an opportunity to filter reviews by products, but when using django_filters it shows corrects queryset of reviews (related only to company's products) but in filter form dropdown options i can see all products of all companies (even those which are not presented on the page), for example for Company X i see on my page only Cactus and Dakimakura reviews, but in filter form i can select Sausage (but i shouldnt, because its product from another company).
For now it's all looks like this:
#View
def reviewsView(request):
context = {}
user = request.user
company = user.company
products_qset = ProductModel.objects.filter(company=company)
reviews_objects = ReviewModel.objects.filter(product__in=products_qset)
filter = ReviewFilter(request.GET, queryset=reviews_objects)
context['filter'] = filter
return render(request, 'companies/reviews.html', context)
#Filter
class ReviewFilter(django_filters.FilterSet):
class Meta:
model = ReviewModel
fields = [
'product',
'marketplace',
'operator',
'state'
]
#Template
<form action="" method="get">
{{ filter.form.as_p }}
<input type="submit" name="press me" id="">
</form>
<div class="review-list">
{% for i in filter %}
{{i.product}}, {{i.marketplace}} etc.
{% endfor %}
I've done quite a lot of research on django_filters docs and this question seems like duplicate, but i can't fully understand what and why is happening to init in this answer and how to correctly rewrike class ReviewFilter so filter instance would do something like this (in View):
filter = ReviewFilter(request.GET, queryset_to_dispplay=MyQueryset, queryset_to_display_filtering_options=MyQueryset). For now its surely happening because ReviewFilter Meta points to the all table (ReviewModel) objects, instead of filtered beforehands.
I also trying to apply pagination on this page (i cut this from question code for "shortness") and after i will be able to implement filtering i would like to merge those two somehow, but if what i want is not possible - please point me to the right direction (for example: 'you can do this by writing your very own filtering system using some js, no need to use django_filters' or 'with angular.js/view.js/somethingelse you can have it all from the box').

Django DetailView - display boolean from models as checkboxes

There's a number of snippets to display booleans in Django Forms as checkboxes (i.e. specifying Checkbox as a widget). For instance (assuming a boolean field defined in the model for bar):
class FooForm(forms.ModelForm):
class Meta:
model = Foo
fields = ['bar']
widgets = {
'bar' : CheckboxInput(attrs={'class': 'required checkbox form-control'}),
}
However I also need to display a (disabled) checkbox in DetailView (client says so). But I can't figure out an elegant way to do this, since I don't have a form meta for details view...
My current thinking is something like this (bootstrap checkbox):
<div class="form-check">
<label class="form-check-label">
<input type="checkbox" {% if foo.bar %}checked{% endif %} disabled>Bar
</label>
<\div>
Any way to accomplish this in a fashion closer to the Form's widgets?
in the view get you form and set initial value
get the model object and set bars initial value
form = YourForm(initial={'bar':modelObject.bar })
and then send the form to the template and simply render
like form.bar
you can disable this with many ways
like
class FooForm(forms.ModelForm):
class Meta:
model = Foo
fields = ['bar']
widgets = {
'bar' : CheckboxInput(attrs={'class': 'required checkbox form-control','disabled':'disabled or true'}),
}
or find and use any template filter to add attribute to form field

achieve full customisation with django forms

I have a model with the following fields
class Entry(models.Model):
title = models.CharField(max_length=50)
comments = models.TextField()
start = models.DateField()
end = models.DateField()
remind = models.BooleanField()
and a modelform
class EntryForm(models.Model):
class Meta:
model = Entry
I want to render a form using bootstrap 3. I can render the form using the same kind of form e.g all fields horizontal or divide them by three in a row. How about more customization. Like
<label title>
<input title>
<label comments>
<input comments>
<label start> <label end>
<input start> <input end>
<label remind><input remind>
I guess this should be done manually. How can I know to which field of the form i am refering in the template. And by which field i mean is it title, is it comments? Is this correct (suppose the view has passed a form argument to the template) something like
<label for={{form.title.auto_id}}>Title</label>
{{form.title}}
is that correct? Now i can place what ever div's and arrange form fields as I like correct?Is that the right way?
How powerfull can a form of django be?
Here's a thought... Django has extensive, well-written documentation:
https://docs.djangoproject.com/en/dev/topics/forms/#customizing-the-form-template
Instead of guessing random things you could just read the docs.
Additionally there are a number of Django apps designed to simplify outputting form HTML in a Bootstrap style, such as:
https://github.com/dyve/django-bootstrap3 (recommended)
https://github.com/dyve/django-bootstrap-toolkit
https://github.com/tzangms/django-bootstrap-form

Django 1.5 Class Based Views with custom validation messages from the model

I'm writing a fairly simple bit of CRUD in my django application for project management. I've got the following set up (leaving out the various imports etc for brevity):
#models.py:
class Project(models.Model):
name = models.CharField('Name', max_length=250, error_messages={'required': 'Please enter a name for your project.'})
description = models.TextField()
#views.py
class ProjectUpdateView(UpdateView):
model = Project
#templates/projects/project_form.html
<form action="" method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" />
</form>
When I visit my update page, the form is displayed with my two fields (name and description). If I leave out the name then submitting the form brings back an error of
This field is required
rather than
Please enter a name for your project.
Can I get my custom error message as defined in the model to display instead of the generic "This field is required"?
Here's a Django ticket regarding the issue you're having: https://code.djangoproject.com/ticket/13693
Looks like it's been accepted but hasn't been fixed yet. Your best bet for now is to explicitly handle the validation in your form class.

How do create a multi select options? or add attributes to the models.CharField

I have this
models.CharField(max_length=10,choices=LOCATION_NAME)
However, I want it to render something like this,
<select multiple="multiple">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
</select>
I am trying to add this to the django admin section.
You can render it using the SelectMultiple Widget:
https://docs.djangoproject.com/en/dev/ref/forms/widgets/#django.forms.SelectMultiple
You'll probably be using a MultipleChoiceField in your form:
https://docs.djangoproject.com/en/1.3/ref/forms/fields/#multiplechoicefield
Make a ModelForm for your model and manually set what widget you want the field to show as:
models.py
class Book(models.Model):
publisher = models.CharField(max_length=100)
forms.py
class BookForm(forms.ModelForm):
publisher = forms.MultipleChoiceField(widget=forms.SelectMultiple)
class Meta:
model = Book
This means the HTML used to display the field is a select, the form generates the data as a list of publishers, and your valid choice is saved simply as a character field in the database. You don't actually need to specify widget=forms.SelectMultiple but it's good to see what's happening (and I always confuse the different fields when talking about database/form/widget)