Any one know how to get the Select Widget choices in a template.
I have done theses. I am overriding admin templates and I could just change the admin form code but I don't want to for app integrity purposes.
{{field.choices}}
Yields nothing.
{%for i in field%}{{i.choices}}{%endfor%}
Yeilds ()
I need to access this var from the template.
I want to change the select field into radios.
If field is a BoundField,
{{ field.field.widget.choices }}
should get you the choices iterable.
Related
Context
I have a model, let's call it Application.
class Application(models.Model):
# various fields here
status = status = models.CharField(
max_length=100,
choices=APPLICATION_STATUSES,
default=PENDING_STATUS[0],
)
assigned_operator = models.OneToOneField(
settings.AUTH_USER_MODEL,
on_delete=models.PROTECT,
editable=True,
null=True,
)
This model has some fields, but the ones we care here are the status, which is simply a choice field, and the assigned_operator field, which defines a 1-1 relationship with a User instance. This model also has its corresponding ApplicationAdmin view defined.
Description
The requirement is that when trying to edit an Application, from the admin view, the default workflow, where you make whatever changes you want and then simply save the form, should be replaced with the following workflow:
The application form is readonly unless the user is the assigned_operator of the application, in which case the application is editable.
When the user is not the application's assigned_operator the actions at the bottom will be 1 button:
"Assign to myself" - When clicked the Application model is updated to reference the current user as its assigned_operator and the page refreshes
When the user is the application's assigned_operator the actions at the bottom will be 3 buttons:
"Save changes" - Does what default "Save" button does
"Reject" - When clicked changes the status field of the application to the appropriate one
"Accept" - When clicked changes the status field of the application to the appropriate one
The problem
Well, the problem is that I am pretty new with django and I am pretty lost here.
What I know:
How to make the fields of the form editable or read only based on the assigned_operator value. I think I just have to set up a get_readonly_fields and do my checks there. Correct me if wrong.
I can replace the current list of form actions with some custom buttons by adding a change_form_template = "path/to/change_form.html" field to the ApplicationAdmin. An example change_form.html that I have now:
{% extends 'admin/change_form.html' %}
{% block submit_buttons_bottom %}
<div>
<input type="submit" value="Assign to me" class="default" name="????">
</div>
{% endblock %}
What I don't know
How to conditionally show either the "Assign to myself" or the group-of-3-buttons, depending on the assigned_operator value of the Application model.
How to connect those new custom buttons to interact with the models and do stuff on them, when they are clicked
In general how the change_form.html part, which is just a template as far as I know, can know things from the currently displayed model instance and the current user.
While code examples are welcome, I do not ask you to give me the implementation. Clear directives/instructions will do just fine, I just need some guidance
Thanks
UPDATE
I figured how to pass info to the template, by using the change_view method of the ModelAdmin. So now I can conditionally display the appropriate buttons.
UPDATE 2
Just figured out how to also do something to a model once a button is clicked. We can use either response_change or change_view for that (not sure which one is the more "correct" option, but both work. Difference is that change_view runs before the view is even rendered, while response_change runs after the form has been saved and the model updated)
How to conditionally show either the "Assign to myself" or the group-of-3-buttons, depending on the assigned_operator value of the Application model.
By overriding the change_view method of the ModelAdmin in our custom Admin view we can pass extra context to our html templates, as showcased in the docs here. So now we can conditionally display the appropriate buttons, by adding an {% if context_value %} in the template.
How to connect those new custom buttons to interact with the models and do stuff on them, when they are clicked
We can use either response_change or change_view for that on our Admin view. In there we can listen for the value of our button's name in the request.POST values (for example _save etc) and act accordingly
(not sure which one is the more "correct" option to use, the response_change or the change_view but both work. Difference is that change_view runs before the view is even rendered, while response_change runs after the form has been saved and the model updated)
In general how the change_form.html part, which is just a template as far as I know, can know things from the currently displayed model instance and the current user.
A combination of passing it context from the Admin view and listening for button names from the template in the request.POST
i am new to django and to this site, so apologies if this has been solved before but i haven't found it
So i have 2 django models
ModelA(Model):
ModelB(Model):
modelA = ForeignKey(ModelA, on_delete=models.CASCADE)
A form for the ModelB
ModelBForm(ModelForm):
class Meta:
model=ModelB
exclude=()
and a view
createModelBView(CreateView):
model = ModelB
form_class = ModelBForm
the template only does
{{form}}
When rendered, there is a dropdown list for the ModelA field so I can choose from existing instances of the ModelA, but what if a new one needs to be created? In the admin there is an option next to edit or create a new ModelA in a popup. Is there an option to do this with CreateView?
Thanks
There is no built-in functionality like that.
However you can build it easily yourself.
You will have to add a link (or a HTML form) in your template which points to the URL corresponding to the view you implemented to create the given model.
Following is a very abstract example.
In your template:
<form>
{{csrf_token}}
{{ form }}
Create model A if you want
<input type="submit" value="Submit">
<\form>
In your urls.py
url(r'^models/createA/$', views.CreateModelAView.as_view(), name="optional")
In your views.py
createModelAView(CreateView):
model = ModelA
form_class = ModelAForm
Then you'll need to create a form called ModelAForm.
On a different note, I'd suggest to start off with functional views if you're new to Django. It is more coding but you get a better feel of what's going on
In the admin there is an option next to edit or create a new ModelA in a popup. Is there an option to do this with CreateView?
No, not built in. That functionality in the admin involves a lot of front-end work involving templates and routing that would have to come from somewhere; since a Form/ModelForm instance can't assume it has access to the admin (which is a contrib module, may not be enabled, and is permission-sensitive), the infrastructure required for that can't be assumed to be available in the general case.
Keep in mind that {{ form }} doesn't even render <form> tags or any kind of submit element. It's intended to be a very, very basic way to render a very, very basic set of fields, while the admin is built specifically to be a (reasonably) powerful, flexible way to put a UI in front of your models.
You could certainly build that functionality yourself, or find a reusable app that does the same thing, but there is no facility distributed with Django to generate it automatically.
I have a Django ListView/FormView combination where each object in the list on the page has a button that toggles a modal form. The form has a hidden field that I'd like to prepopulate with the slug of the object in the list it came from (ie. not the slug of the page, but of the object in the list on that page). One way I could think of that might work would be to have the {{ form }} tag accept the object's slug as an argument somehow - like {{ form object_instance=object.slug }}. How might I do that? And how might I call it in the ListView?
Thank you for any input you might have.
You can create a custom filter for initialising a form like this. Assuming that the hidden input field is named slug in your form, the code should probably be:
from django import template
register = template.Library()
#register.filter
def setslug(form, slugval):
form.initial['slug'] = slugval
return form
Now you can call it from your template as {{ form|setslug:slugfield }}
If you have a form for each line of the list, just make sure the slug exists in the form's context.
If you have just one form and change its contents based on the user's actions, you'll have to resort to JavaScript.
I want to change the shape of some fields showed in the admin site.
I found that the template that manage everything is change_form.html with fieldset.html but I cannot find where the fields are actually transformed in html.
Basically I want to change the field of the foreign key adding a link to another page.
Do you have any idea?
Thanks,
Giovanni
The HTML for a given field is handled by its widget in the render function. If you want to customize the look of a field you could create a custom widget which has the additional HTML you need in the render.
You can check out the render some of the built in widgets in django/forms/widgets.py (links to the Django trunk).
In fieldset.html, the code {{ field.field }} renders the field's HTML representation. to achieve what you want, you'll probably need to define your own widget. you can take a look at admin's widgets.py
I'm wrestling with how to best create HTML pages in Django that can either be used for displaying or editing data. That is, I'd like the field's values to appear as text in display mode, but in their widgets when in edit/add mode. It appears that Django wasn't designed to do this: the fields always appear in their widgets (eg, text input, text area,
etc).
Is there a common technique for handling this, short of using forms for one, and not the other?
I was thinking of a custom templatetag filter that could be used for every form field, like:
{{ form.field_name|render_field:mode }}
where render_field would either return the field's HTML widget, or just the value as text, based on the mode.
Have I missed something, or is this a viable solution?
Answering my own question, apparently. I ended up with a three-part solution:
attach the model to the form, so I'll have the default display widgets for each field
write the form using a template tag, passing it the form.field, user, and action
write a render template tag to handle #2
Step one:
form.model = Model(...)
Step two:
{{form.field1.label}}
{% render form.field1 user action %}
{{form.field2.label}}
{% render form.field2 user action %}
Step three:
Something like:
def render(formfield, user, action, default_text="Private"):
if not user.is_authenticated():
action = "view"
if action == "view":
if user.is_authenticated():
fieldname = formfield.name
retval = str(getattr(formfield.form.model, fieldname))
else:
retval = default_text
else:
retval = formfield.as_widget()
return retval
Since you are saving the data, you must have a model attached to the form somehow, a modelform or not. So you can just use that model directly to get the values and render it in a template like you want.
The above suggestion would be possible, but since forms can be rather complex, it's probably not an easy task or worth the bother. Depends on how often you want to do this. But then it would probably be easier to create a filter for the model instead of the form.
Have I missed something
Forms not only display the field widgets but also handle the post data. A post sent would cause it to process the data cleanup, form and field error handling, etc.
It's kind of breaking the pattern - why create and render a form object only to tweak it not to look like a form?
If you are worried about too much work on templates, try to solve it with template inheritance in a best possible way. If you are very sure you want to change only the field tag, you can make sth like
{% if form %}
{% for error in form.field.errors %}
{{ error|escape }}
{% endfor %}
{{ form.field }}
{% else %}
{{ object.field }}
{% endif %}
for every field, but IMO that's not the point, YMMV.
Also what comes to mind (thinking of your solution) is dynamically attach widgets to form fields, but that'd be overengineering.
I have the same problem. Right now I have separate templates for display and editing; the former renders object fields, the latter form fields (but sometimes also object fields, for things which are not editable). The HTML structure can be quite complex: for example, on some pages I have large tables representing a multi-level hierarchy of objects. As a result, I end up with a large amount of duplicated code in the two templates, which is the opposite of DRY.
I have used template filters with form fields before, to save code when displaying errors together with the field. I think it would be a viable solution in this case. Another possibility may be to use a ModelForm subclass which can be told to render uneditable versions of the fields. This would help keep the templates simple. You could even render both the static and the editable version of a field, and use JavaScript to switch between them, activating and deactivating an editing mode.