English 中文(简体)
Problem with logic in Django template
原标题:

Supose this portion of a Django template. regs is a list of Reg objects. Reg.editable is a BooleanField. I want to render a radio button per element in the list. If r.editable is False, the radio button must be disabled:

{% for r in regs %}
<input type="radio" value="{{ forloop.counter }}"
{% if forloop.first %}checked="checked"{% endif %}
{% if not r.editable %}disabled="disabled"{% endif %}/> 
{% endfor %}

As you can see, I m using forloop.first to check the first radio button, but this has a problem! What about if the first element has editable == False? The first radio button will be rendered disabled and chequed. If then a user submit "the form" I ll receive a value not expected.

Am I clear with the problem here? How can I rewrite this template to render as checked the FIRST ENABLED radio button?

Thanks

最佳回答

The real answer to this question is as follows:

Such logic has no place in the template. You can preprocess the context before passing it to the template, thus eleminating the need to do this using the (intentionally) crippled template engine logic.

In my opinion, what you are doing is wrong. I mean, django has perfectly fine forms api, why render the inputs directly then? Some might argue, that django s forms api is inflexible, but for this specific need it will undoubtely be sufficient.

And to reiterate - this kind of logic does not belong in the presentation layer. So don t put it there, it will bite you. In fact it already did.

问题回答

Djangos templating language doesn t give you a lot in the way of logic in the template (I ve heard positive things about Jinja2 if you want to change that). There s also the "Smart" {% if %} tag which adds some more functionality and incidentally is being proposed for inclusion in Django 1.2.

As for solving this problem I would most likely move the logic over to the view. (Disclaimer: don t have the time to test this code snippet but it should provide the general idea)

def my_view(request, *args, **kwargs):

    # QuerySet is fetched however it s done...
    regs = Regs.objects.all()

    # Wrap regs in display information    
    checked = False
    radio_buttons = []

    for r in regs:
        if r.editable:
            if not checked:
                 radio_buttons.append( {  checked :True,  enabled :True,  object :r } )
                 # Set to true once
                 checked = True
            else:
                 radio_buttons.append( {  checked :False,  enabled :True,  object :r } )
        else:
            radio_buttons.append( {  checked :False,  enabled :False,  object :r } )          

    # Then pass in radio_buttons for the value of regs down here
    render_to_whatever(..., {  regs :radio_buttons } )

In this case we ve wrapped the QuerySet which will give our template some more details about rendering. The template becomes "dumb" now.

{% for r in regs %}
    <input type="radio" value="{{ forloop.counter }}"
    {% if r.checked %}checked="checked"{% endif %}
    {% if not r.enabled %}disabled="disabled"{% endif %}/> 
    {% comment %} To access the original object use: {{ r.object }} {% endcomment %}
{% endfor %}

Just adjust your ifs

{% for r in regs %}
    {% if forloop.first %}
        <input type="radio" value="{{ forloop.counter }}" checked="checked"/>
    {% else %}
        {% if not r.editable %}
            <input type="radio" value="{{ forloop.counter }}" disabled="disabled"/> 
        {% endif %}
    {% endif %}
{% endfor %}

PS: Your question did not clearly explain what you wanted. I made some reasonable assumption. Update the question if what you want is something else.

Similar to T. Stone s answer of doing this logic in the view, you could just add a new template variable that indicated the first checked radio:

def my_view(request, *args, **kwargs):
  regs = Regs.objects.all()
  checked_index = None
  for i, reg in enumerate(regs):
    if reg.enabled:
      checked_index = i
      break
  # pass checked_index into the template...

Template:

{% for r in regs %}
  {% ifequal forloop.counter0 checked_index %}
    <input type="radio" value="{{ forloop.counter }}" checked="checked"/>
  {% else %}
    <input type="radio" value="{{ forloop.counter }}" {% if not r.editable %}disabled="disabled"{% endif %}/> 
  {% endif %}
{% endfor %}

Similar to becomingGuru but solving your problems:

{% for r in regs %}
    {% if not r.editable %}
        <input type="radio" value="{{ forloop.counter }}" disabled="disabled"/>     
    {% else %}
        {% if forloop.first %}
            <input type="radio" value="{{ forloop.counter }}" checked="checked"/>
        {% endif %}
    {% endif %}
{% endfor %}

It first checks if r is editable, and then checks if it is the first. Regards.





相关问题
Can Django models use MySQL functions?

Is there a way to force Django models to pass a field to a MySQL function every time the model data is read or loaded? To clarify what I mean in SQL, I want the Django model to produce something like ...

An enterprise scheduler for python (like quartz)

I am looking for an enterprise tasks scheduler for python, like quartz is for Java. Requirements: Persistent: if the process restarts or the machine restarts, then all the jobs must stay there and ...

How to remove unique, then duplicate dictionaries in a list?

Given the following list that contains some duplicate and some unique dictionaries, what is the best method to remove unique dictionaries first, then reduce the duplicate dictionaries to single ...

What is suggested seed value to use with random.seed()?

Simple enough question: I m using python random module to generate random integers. I want to know what is the suggested value to use with the random.seed() function? Currently I am letting this ...

How can I make the PyDev editor selectively ignore errors?

I m using PyDev under Eclipse to write some Jython code. I ve got numerous instances where I need to do something like this: import com.work.project.component.client.Interface.ISubInterface as ...

How do I profile `paster serve` s startup time?

Python s paster serve app.ini is taking longer than I would like to be ready for the first request. I know how to profile requests with middleware, but how do I profile the initialization time? I ...

Pragmatically adding give-aways/freebies to an online store

Our business currently has an online store and recently we ve been offering free specials to our customers. Right now, we simply display the special and give the buyer a notice stating we will add the ...

Converting Dictionary to List? [duplicate]

I m trying to convert a Python dictionary into a Python list, in order to perform some calculations. #My dictionary dict = {} dict[ Capital ]="London" dict[ Food ]="Fish&Chips" dict[ 2012 ]="...

热门标签