I have a Django ModelForm containing 3 fields: name, lastname, email. What I want is to adjust the crispy form to have each field along with it's label in one line, so the form will look like this:
Name: <input name>
Lastname: <input lastname>
Email: <input email>
<button Submit>
I tried with FormHelper and Layout and bootstrap inline attribute but all I achieved was having all elements in the form in one line.
I'm really bad at frontend and I'm stuck.
Assuming your settings.py contains:
CRISPY_TEMPLATE_PACK = 'bootstrap4'
you probably want to override the template bootstrap4/field.html which is the one that places the label and the various possible input field together.
to do so, you can copy the templates/bootstrap4/field.html file from the crispy_form package into your templates/bootstrap4/field.html in your application and have it modified as per your needs. When the template engine will render the form fields, it will find your modified field.html before the one in the original template.
you may also want to be refered to the template pack uni_form which, without css, renders the fields almost the way you want. You can use it as is or get yourself inspired by the way it is structured to modify your own field.html.
I managed to achieve my goal by simply changing {{ my_form|crispy }} to {{ my_form.as_p }} in my html code.
Related
I'm using an HTML <select> tag to let the user select the title of a project, where the project is a QuerySet in a Django Model. So I want to use that value to display other data concerned with that project to the user.
The name of the HTML <select> is select_project. In my views.py, I use the request.POST['select_project']and store it in a variable selected_project. In order to get other data in the QuerySet, I used Project.objects.filter(title=selected_project) and stored it in a variable displayed_project which I then used in a View where the user sees all the information about that QuerySet.
enter image description here
But when the user goes to the view, he gets nothing. Only an empty <QuerySet[]>. Please could you help suggest a way around this?
<select class="select_project" name="select_project">
{%for project in projects%}
<option value="" name='select_project'>{{project.title}}</option>
{%endfor%}
Views.py
def overview(request):
if request.method=='POST':
selected_project=request.POST['select_project']
displayed_project=Project.objects.filter(title=selected_project)
return render (request, 'core/overview.html', {
'displayed_project':displayed_project
})
Thank you!
Try to fill the value and name in tag with the value of every project id or title. For example:
<select class="select_project" name="select_project">
{%for project in projects%}
<option value="{{project.id}}" name='{{project.title}}'>{{project.title}}</option>
{%endfor%}
If there will be a problem again, please write here
I've resolved the issue. So I did not know that my View gets the value of the <select> and not actually it's content. So I then added the project.id to the value of the <select> tag. With that done, and after getting the POST data, I filtered the QuerySet using the ID like so:
Project.objects.filter(pk=selected_project)
and at the end, I got the data in the Overview page.
Thanks!
I am new to Django and am using Django's user auth package (django.contrib.auth) for user login, password reset, etc.
Now, while everything works just fine, on the logon form, I'd like to use the html-placeholder property. How can I use / populate this? I did find some answers (e.g. this one) but I do not understand where to place this code, how to extend the view / form or even the model (e.g. adding new fields) as this gets delivered with the standard package.
Right now, I have added the following:
forms.py
from django import forms
from django.contrib.auth.forms import AuthenticationForm
class LoginForm(forms.Form):
username = forms.CharField(label='username')
password = forms.CharField(label='password')
def __init__(self, *args, **kwargs):
super(LoginForm, self).__init__(*args, **kwargs)
self.fields['username'].widget.attrs['placeholder'] = 'Username'
self.fields['password '].widget.attrs['placeholder'] = 'Password'
I am not sure what I need to do in urls.py or models.py or anywhere else for the code to be executed.
I found the following solution:
installed bootstrap4
using the following tag in my html:
{% bootstrap_field form.password field_class="field" placeholder="Password" show_label=False %}
I believe by adding the widgets to your forms init, when you instantiate the form in your template the placeholder should appear like intended. Did you just try rendering your form such as {{form}} in the template and see if it rendered it? I dont think bootstrap4 is necessary but it is a great tool.
I'm not sure if this is even possible, but I would like to grab a user's input, pull it into my views.py, manipulate it, and then use that data in other views.
I do not need this data stored in a database, as I won't be referencing it again, and I want to keep this as lightweight as possible.
Currently, I'm trying to pull data from espn's fantasy football site using the python library espnff. My homepage consists of a textfield box and a submit button (Think of google.com).
I have functions set up that will comb through an espn url such as http://games.espn.com/ffl/clubhouse?leagueId=123456 to grab the leagueID, from there I make use of espnff to grab more info on that league.
My ideal use case is someone comes to my site, copies and pastes their league url like the one above, clicks submit and then brings them to https://example.com/{{ leagueID}/ which will display different info that I gather.
I have not found a way to do this without submitting the user input to a model. Is possible to avoid using the database? If so how?
Not sure I understood it right, but what you are trying to do can easily be done without using any models/database or any other kind of persistent storage.
The user submits that information using the form, you grab the URL from the request object in your view, parse the URL to get the league_id and then redirect the user to /{league_id}.
Then on that view, you gather the league_id parameter (from the url), use the library (espnff) to fetch the data with that id and then render the template with that data.
For example, the implementation would be something in these lines:
Make a form in your html template:
<form method="post" action="/">
{% csrf_token %}
<input type="text" name="league_url"/>
<input type="submit" value="Submit" />
</form>
in urls.py:
url(r'^$', index_view, name="index"),
url(r'^(?P<league_id>[0-9]+)$', league_view, name="league_view")
in views.py:
def index_view(request):
if request.method == 'POST':
league_url = request.POST.get('league_url', None)
# Your code to parse the URL and extract the ID
return HttpResponseRedirect('/{}'.format(league_id))
else:
# render form template
def league_view(request, league_id):
# your code here using the league_id
# and render the page with data
(I didn't tested that code, I just wrote it quickly as an example of the flow)
The django documentation describes quite extensively how to do caching with django. You can find the documentation on how to set that up here
Once it's been set up you simply use the cache in the following way
from django.core.cache import cache
cache.set('my_key', 'my_value', 60) # number is in seconds
value = cache.get('my_key')
You can provide dictionaries and such as values. The caching framework will serialize that for you using pickle.
I have a dropdown in a modelform and the user should not be able to change the selected value.
I found that a disabled does exactly do what I need. However there is an oddness to this:
The first time when the form opens (GET) the value is selected and the user can't change the value. which is great:
But as soon as there is a validation error with an unrelated field and the POST sends the user back to the same form, the previous information is lost. The disabled foreignkey-dropdown no longer contains any value and is very irritating.
I did some research and found something on stackoverflow and seems when a foreignkey-dropdown widget is disabled, no data is sent back at all. While the validation can be overriden to not throw any errors for the dropdown field as the third answer here explains. However if ANY OTHER unrelated field throws an error then the data is lost, because the disabled dropdown had never sent any data to POST in first place.
It is a tricky situation.
Is there a way to pass in the data within the view to the request.POST ? or what do you suggest? I could use a readonly instead ofdisabled and that would work, however the dropdown can be changed by the user, which is also irritating.
Any ideas? Many Thanks
edit:
Small correction: The data is not completely lost. Rather the select is set wrongly to the initial dummy value.
<select id="id_form-0-deal_type" name="form-0-deal_type" disabled="disabled">
<option selected="selected" value="">---------</option>
<option value="1">deal 1</option>
<option value="2">deal 2</option>
</select>
UPDATE:
The solution from Francis looks very promising. So I have tried his second suggestion and added a hidden inputfield in the html and pass in the correct value into the POST.
The problem is now how to proceed. I have tried to add the missing entry in the formset's form's querydict like this (in order to set the correct dropdown value)
formset.forms[0].data['form-0-deal_type'] = formset.forms[0].data['form-0-hiddenfield']
But it says This QueryDict instance is immutable
The only other way to do it is setting it through Initials with regular formsets. Unfortunally I am using modelformsets, which doesn't support initials for existing forms.
If there is no other solution, I start refactoring my modelformset into a regular formset. Still open for ideas...
Final Update + Solution:
There is no need to refactor modelformset into regular fomsets. In fact I highly discourage doing that, since it brings other problems with itself. modelformsets handle everything for you and fill the missing parts.
The actual problem is the fact that QueryDict are immutable, but this can be easily solved by copying them:
formset = deal_formset(request.POST, queryset=formset_query)
if formset.is_valid():
pass
else:
new_post = request.POST.copy()
deal_types = dict()
for k,v in new_post.items():
if k.startswith('hidden'):
deal_types[k[7:]]= v
for k,v in deal_types.iteritems():
new_post[k] = v
formset = deal_formset(new_post, queryset=formset_query)
This plus the solution of Francis:
{{ formset.management_form }}
{% for fs in formset %}
{{ fs.id }}
<input type="hidden" name="hidden-{{ fs.prefix }}-deal_type" value="{{fs.deal_type.value}}" />
{{fs.deal_type}}
{% endfor %}
{% endif %}
just works wonders... enjoy :)
Its not a django thing, its an HTML thing. Disabled form elements are not sent by the form.
[The Element] cannot receive user input nor will its value be submitted with the form.
http://www.w3.org/TR/html401/interact/forms.html#h-17.12.1 & http://www.w3schools.com/tags/att_input_disabled.asp
you could use readonly if its on a text/textarea
http://www.w3schools.com/tags/att_input_readonly.asp
something else you could do, is show the value plaintext, and submit it as a hidden field....
{{ form.field_name.label_tag }}
{{ form.field_name.value }}
<input type="hidden" name="field_name" value="{{form.field_name.value}}" />
its not very elegant, but it could get you there.
You could also take it a step further and write some JS that looks for disabled elements and adds an input with that element's name and value after.
some sample JQuery:
//Untested, but you get the gist
$(':disabled').each(
function()
{
$(this).after('<input type="hidden" name="' + $(this).attr('name') + '" value="' + $(this).val() + '" />');
}
);
Well, you could set the element with hidden property in the template, using formsets in the view to build the form:
{{form.field.as_hidden}}
and inside the view, if the problem is the data loss, you could always set an initial value for the field that suits your model structure, since it's a foreign key. Of course, you will have to validate the form before commiting it, and if the form is not valid, you can render it with initial values on the fields that must be always filled.
I think this is a HTML issue rather than Django, disabled form fields don't post their values back so you're losing the value.
Would it be possible to rebind the value to the field if validation fails? You could try something like
if form.is_valid(): # All validation rules pass
#save form, redirect, etc.
else:
form.disabled_field = my_value
return render(request, 'contact.html', {'form': form,})
Obviously you'll need to replace the field name and value with the correct data from your model.
I don't have an example because I'm not working on anything relevant right now, but am still curious, after reading the docs about formsets:
What is a best practice for having a single view with multiple different model forms that post at the same time (rather 1 combined form, since you can't post multiple forms at the same time, but for lack of a better explanation...), some being single model forms, and others being 1-or-more formsets (e.g. Person, his 1 Address, and his 1 or more Pet objects), like Django does with TabularInline. Inlines have been in Django for some times, so my suspicion is that there are better practices than what I may find by simply copy/pasting what's in admin/options.py, no?
Thanks in advance
You should:
Make sure you're using transactions (so, make sure they're turned on, and that you're using something other than MySQL with MyISAM tables). This is true all the time, really, but it's even more true now. :)
Use multiple forms.Form/forms.ModelForm objects, which are grouped together in a single HTML <form> element, such as...
Python:
from django import forms
class FormA(forms.ModelForm):
[...]
class FormB(forms.ModelForm):
[...]
HTML:
<form method="post" action="/path/to/view/">
{% csrf_token %}
{{ form_a }}
{{ form_b }}
<input type="submit" value="Submit Form" />
</form>
Then, when you're processing your forms, simply process them both and make sure that you're requiring both to be valid to actually complete the view in a success case.
from django.db import transaction
from django.http import HttpResponseRedirect
from django.template.response import TemplateResponse
from myapp.forms import FormA, FormB
#transaction.commit_on_success
def present_forms_to_user(request):
if request.method == 'POST':
form_a = FormA(request.POST)
form_b = FormB(request.POST)
if form_a.is_valid() and form_b.is_valid():
# processing code
return HttpResponseRedirect('/path/to/thank/you/page/')
else:
form_a = FormA()
form_b = FormB()
return TemplateResponse(request, 'templates/eggs.html', {
'form_a': form_a,
'form_b': form_b,
})
As a disclaimer, remember that this is a basic example stub, and not meant to be copied blindly. Your ultimate use case for this may be slightly different, and that's fine.