Question

Please, I have a similar case I'll introduce them and wish you could help me understand and handle this case properly.

I have the simple model case:

# -*- coding: utf-8 -*-
from django.db import models

class City(models.Model):
    name = models.CharField("City", max_length=100, blank=False, null=False)
    state = models.CharField("State", max_length=2, blank=False, null=False)

class Neighborhood(models.Model):
    name = models.CharField("Name", max_length=100, blank=False, null=False)
    city = models.ForeignKey(City, blank=False, null=False)

The model forms:

from django import forms
from app.models import *

class CityForm(forms.ModelForm):
    class Meta:
        model = City

class NeighborhoodForm(forms.ModelForm):
    class Meta:
        model = Neighborhood
    state = forms.CharField("State", max_length=2, required=True)

Theirs views:

City View:

from django.http import HttpResponseRedirect
from django.shortcuts import render_to_response
from django.template import RequestContext

from app.forms import CityForm
from app.models import City

STATES = ["AC", "AL", "AP", "AM", "BA", "CE", "DF", "ES", "GO", "MA", "MT", "MS", "MG", "PR",
          "PB", "PA", "PE", "PI", "RJ", "RN", "RS", "RO", "RR", "SC", "SE", "SP", "TO"]

def index(request):
    if "submit" in request.POST:
        form = CityForm(request.POST, request.FILES)
        if form.is_valid():
            form.save(commit=True)

    elif "cancel" in request.POST:
        return HttpResponseRedirect("/")

    else:
        form = CityForm()

    cities = City.objects.all()
    data = {
        "form": form,
        "states": STATES,
        "cities": cities
    }
    return render_to_response("city/index.html", data, context_instance=RequestContext(request))

And the Neighborhood view:

from django.http import HttpResponseRedirect
from django.shortcuts import render_to_response
from django.template import RequestContext
from app.forms import NeighborhoodForm
from app.models import Neighborhood, City
from app.city.views import STATES


def index(request):
    if "submit" in request.POST:
        form = NeighborhoodForm(request.POST, request.FILES)
        if form.is_valid():
            form.save(commit=True)

    elif "cancel" in request.POST:
        return HttpResponseRedirect("/")
    else:
        form = NeighborhoodForm()

    neighborhoods = Neighborhood.objects.all()
    cities = City.objects.all()
    data = {
        "form": form,
        "states": STATES,
        "cities": cities,
        "neighborhoods": neighborhoods
    }
    return render_to_response("neighborhood/inserir.html", data, context_instance=RequestContext(request))

And finally, the template of Neighborhood:

{% extends "base.html" %}

{% block content %}
    <form action="" method="post" id="neighborhoodForm" name="neighborhoodForm">
        {% csrf_token %}
        <div>
            <label>State:</label>
            <select id="state" name="state" autofocus="autofocus">
                <option value=""></option>
                {% for item in states %}
                    <option value="{{ item }}"
                            {% if item == form.state.value %}
                            selected="selected"
                            {% endif %}>{{ item }}</option>
                {% endfor %}
            </select>
        </div>

        <div>
            <label>City:</label>
            <select id="city" name="city">
                <option value=""></option>
                {% for item in cities %}
                    <option value="{{ item.id }}"
                            {% if item.id == form.city.value|add:0 %}
                            selected="selected"
                            {% endif %}>{{ item.name }}</option>
                {% endfor %}
            </select>
        </div>
        <div>
            <label>Neighborhood Name:</label>
            <input type="text" id="name" name="name" value="{{ form.name.value|default_if_none:"" }}"/>
        </div>
        <div>
            <button type="submit" id="submit" name="submit" value="submit">Submit</button>
            <button type="submit" id="cancel" name="cancel" value="cancel">Cancel</button>
        </div>
    </form>

    <br/>

    <table border="1">
        <tr>
            <th>Neighborhood Name</th>
            <th>City</th>
            <th>State</th>
        </tr>
        {% for item in neighborhoods %}
        <tr>
            <td>{{ item.name }}</td>
            <td>{{ item.city.name }}</td>
            <td>{{ item.city.state }}</td>
        </tr>
        {% endfor %}
    </table>
{% endblock %}

My difficulty on in view of neighborhoods. I have the City and State fields, which are in the neighborhood template for filters.

To add a record I have no problem, but a simple post does not return the value in the "state" of NeighborhoodForm to the template again. That's because the value that was sent in the post does not find the "state" field of the form.

When you open a record for editing happen the same thing, ie, the "state" field will not be filled.

So this is my problem. Can you help me? How should I do or what I'm doing wrong? Thanks all for the assistance given.

Was it helpful?

Solution

What you really want here is to assign and save custom values to fields. To do this, you have to provide initial values and save method of form.

If you have a object to load data from, then you must pass it the form, for example:

neighbor = Neighborhood.objects.get(pk=1)
form = NeighborhoodForm(instance=neighbor)

The above code initialize the form with the object and fields related to it. But it still misses out on state field. To initialize it, you must pass initial value for it:

neighbor = Neighborhood.objects.get(pk=1)
state = neighbor.city.state
form = NeighborhoodForm(instance=neighbor, initial={'state': state})

OR you could override form's __init__ method to extract value:

def __init__(self, *args, **kwargs):
    super(NeighborhoodForm, self).__init__(*args, **kwargs)
    if 'instance' in kwargs:
        state = self.instance.city.state
        self.fields['state'].initial = state

And you can save data similarly by overriding save method:

def save(self, *args, **kwargs):
    new_neighbor = super(NeighborhoodForm, self).save(*args, **kwargs)
    city = City.objects.create(state=self.cleaned_data['state'])
    new_neighbor.city = city
    new_neighbor.save()
    return new_neighbor
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top