Django run_validation removing MultiValueDict from QueryDict - django

I have a nested serializer field on a serializer which accepts Multipart/form-data (json + images).
The run_validation happens to remove the nested serializer field data from the QueryDict.
Here is the code:
class CreateSerializer(ModelSerializer[Dress]):
dress_sizes = SizeSerializer(many=True, required=False)
def run_validation(self, data: Any = ...) -> Any | None:
return super(CreateSerializer, self).run_validation(data)
def validate(self, data):
return super().validate(data)
The view uses a custom parser:
class MultipartJsonParser(MultiPartParser):
def parse(self, stream, media_type=None, parser_context=None):
result = super().parse(
stream, media_type=media_type, parser_context=parser_context
)
data = {}
for key, value in result.data.items():
if type(value) != str:
data[key] = value
continue
if "{" in value or "[" in value:
try:
data[key] = json.loads(value)
except ValueError:
data[key] = value
else:
data[key] = value
qdict = QueryDict('', mutable=True)
qdict.update(data)
return DataAndFiles(qdict, result.files)
Here is the data that I get in the run_validation method:
< QueryDict: {
'file_name': ['swimsuit.svg'],
'dress_sizes': [
[{
'size': 'xs'
}, {
'size': 's'
}, {
'size': 'm'
}, {
'size': 'l'
}, {
'size': 'xl'
}]
],
'image': [ < TemporaryUploadedFile: swim.svg(image / svg + xml) > ]
} >
After run_validation the validate gets following data:
OrderedDict([('file_name', 'swimsuit.svg'), ('image', <
TemporaryUploadedFile: swim.svg(image / svg + xml) > )])
Here the whole dress_sizes has disappeared. Which is needed to create the list of dress_sizes objects. I have reduced the code to make it readable. Maybe there are some mismatches in the spellings which is not the issue.
Question is how to make the run_validation not remove the list of dress_sizes?
Finally in the create method there is no data for the dress_sizes = []. Here is create:
def create(self, validated_data: Dict[str, Any]) -> Dress:
dress_sizes = validated_data.pop("dress_sizes", [])

Related

How to populate a bespoke Django form MultiWidget

I have created a bespoke form widget which saves an address as a list.
class AddressWidget(MultiWidget):
def __init__(self, base_widget, attrs=None):
widgets = (
forms.TextInput(attrs={'placeholder': 'Address', 'class': 'form-control'}),
forms.TextInput(attrs={'placeholder': 'Address Line 2', 'class': 'form-control'}),
forms.TextInput(attrs={'placeholder': 'City', 'class': 'form-control'}),
forms.TextInput(attrs={'placeholder': 'State', 'class': 'form-control'}),
forms.TextInput(attrs={'placeholder': 'Postcode', 'class': 'form-control'}),
)
super().__init__(widgets, attrs)
def decompress(self, value):
if value:
return (value.address1, value.address2, value.city, value.state, value.postcode)
return (None, None, None, None, None)
Saving the form works as I want, but when re-entering the form in order to change values, it doesn't get prepopulated, although all other regular fields do.
How do I get it to populate the field?
It is used in the form as:
class ResponseForm(forms.ModelForm)
address = AddressField()
...
class Meta:
model = SomeModel
fields = ('address',)
class AddressField(MultiValueField):
"""
Custom field to take user inputs of Address
"""
widget = AddressWidget(base_widget=TextInput)
def __init__(self, *, attrs=None, **kwargs):
fields = (
CharField(label=_('Address Line 1'), max_length=25),
CharField(label=_('Address Line 2'), max_length=25),
CharField(label=_('City'), max_length=25),
CharField(label=_('State'), max_length=25),
CharField(label=_('Country'), max_length=25)
)
super().__init__(fields, required=False)
def clean(self, value, initial=None):
value = super().clean(value)
return value
def compress(self, value_list):
if value_list:
return value_list
return [[],[],[]]
Within the model it is defined as:
class SomeModel(models.Model):
address = models.TextField()
...
A typical value entered might be:
123 Some Street
Example Area
This Town
MYP 0ST
It is saved to the database table like this in a text field.
EDIT
I think my problem is the ResponseForm. I am using an app and response form is initialising the widgets.
class ResponseForm(forms.ModelForm):
FIELDS = {
Question.TINY_TEXT: TinyCharField,
Question.EXTRA_SHORT_TEXT: ExtraShortCharField,
Question.SHORT_TEXT: ShortCharField,
Question.TEXT: forms.CharField,
Question.EXTRA_LONG_TEXT: forms.CharField,
Question.SELECT_MULTIPLE: forms.MultipleChoiceField,
Question.INTEGER: forms.IntegerField,
Question.FLOAT: forms.FloatField,
Question.DATE: forms.DateField,
Question.TIME: forms.TimeField,
Question.CHECK_BOXES: forms.MultipleChoiceField,
Question.ADDRESS: forms.CharField, #AddressField,
Question.DISCLAIMER: forms.BooleanField,
Question.HEIGHT: HeightFormField,
Question.WEIGHT: WeightFormField,
Question.RANGE: IntegerRangeField,
Question.VOLUME: VolumeFormField,
}
WIDGETS = {
Question.TINY_TEXT: forms.TextInput(),
Question.EXTRA_SHORT_TEXT: forms.TextInput(),
Question.SHORT_TEXT: forms.TextInput(),
Question.TEXT: forms.Textarea(attrs={'maxlength':250}),
Question.ADDRESS: forms.Textarea(attrs={'maxlength':250}),
Question.EXTRA_LONG_TEXT: forms.Textarea(attrs={'maxlength':750}),
Question.RADIO: forms.RadioSelect,
Question.SELECT: forms.Select,
Question.SELECT_IMAGE: ImageSelectWidget,
Question.SELECT_MULTIPLE: forms.SelectMultiple,
Question.CHECK_BOXES: forms.CheckboxSelectMultiple,
Question.DATE: DatePickerInput,
Question.DISCLAIMER: forms.CheckboxInput(attrs={'required': True}),
}
class Meta:
model = Response
fields = ()
def __init__(self, *args, **kwargs):
"""Expects a survey object to be passed in initially"""
self.survey = kwargs.pop("survey")
self.user = kwargs.pop("user")
try:
self.step = int(kwargs.pop("step"))
except KeyError:
self.step = None
super().__init__(*args, **kwargs)
self.uuid = uuid.uuid4().hex
self.categories = self.survey.non_empty_categories()
self.qs_with_no_cat = self.survey.questions.filter(category__isnull=True).order_by("order", "id")
if self.survey.display_method == Survey.BY_CATEGORY:
self.steps_count = len(self.categories) + (1 if self.qs_with_no_cat else 0)
else:
self.steps_count = len(self.survey.questions.all())
# will contain prefetched data to avoid multiple db calls
self.response = False
self.answers = False
self.add_questions(kwargs.get("data"))
self._get_preexisting_response()
if not self.survey.editable_answers and self.response is not None:
for name in self.fields.keys():
self.fields[name].widget.attrs["disabled"] = True
def add_questions(self, data):
'''
add a field for each survey question, corresponding to the question
type as appropriate.
'''
if self.survey.display_method == Survey.BY_CATEGORY and self.step is not None:
if self.step == len(self.categories):
qs_for_step = self.survey.questions.filter(category__isnull=True).order_by("order", "id")
else:
qs_for_step = self.survey.questions.filter(category=self.categories[self.step])
for question in qs_for_step:
self.add_question(question, data)
else:
for i, question in enumerate(self.survey.questions.all()):
not_to_keep = i != self.step and self.step is not None
if self.survey.display_method == Survey.BY_QUESTION and not_to_keep:
continue
self.add_question(question, data)
def current_categories(self):
if self.survey.display_method == Survey.BY_CATEGORY:
if self.step is not None and self.step < len(self.categories):
return [self.categories[self.step]]
return [Category(name="No category", description="No cat desc")]
else:
extras = []
if self.qs_with_no_cat:
extras = [Category(name="No category", description="No cat desc")]
return self.categories + extras
def _get_preexisting_response(self):
"""Recover a pre-existing response in database.
The user must be logged. Will store the response retrieved in an attribute
to avoid multiple db calls.
:rtype: Response or None"""
if self.response:
return self.response
if not self.user.is_authenticated:
self.response = None
else:
try:
self.response = Response.objects.prefetch_related("user", "survey").get(
user=self.user, survey=self.survey
)
except Response.DoesNotExist:
LOGGER.debug("No saved response for '%s' for user %s", self.survey, self.user)
self.response = None
return self.response
def _get_preexisting_answers(self):
"""Recover pre-existing answers in database.
The user must be logged. A Response containing the Answer must exists.
Will create an attribute containing the answers retrieved to avoid multiple
db calls.
:rtype: dict of Answer or None"""
if self.answers:
return self.answers
response = self._get_preexisting_response()
if response is None:
self.answers = None
try:
answers = Answer.objects.filter(response=response).prefetch_related("question")
self.answers = {answer.question.id: answer for answer in answers.all()}
except Answer.DoesNotExist:
self.answers = None
return self.answers
def _get_preexisting_answer(self, question):
"""Recover a pre-existing answer in database.
The user must be logged. A Response containing the Answer must exists.
:param Question question: The question we want to recover in the
response.
:rtype: Answer or None"""
answers = self._get_preexisting_answers()
return answers.get(question.id, None)
def get_question_initial(self, question, data):
"""Get the initial value that we should use in the Form
:param Question question: The question
:param dict data: Value from a POST request.
:rtype: String or None"""
initial = None
answer = self._get_preexisting_answer(question)
if answer:
# Initialize the field with values from the database if any
if question.type in [Question.SELECT_MULTIPLE]:
initial = []
if answer.body == "[]":
pass
elif "[" in answer.body and "]" in answer.body:
initial = []
unformated_choices = answer.body[1:-1].strip()
for unformated_choice in unformated_choices.split(settings.CHOICES_SEPARATOR):
choice = unformated_choice.split("'")[1]
initial.append(slugify(choice))
else:
# Only one element
initial.append(slugify(answer.body))
elif question.type == Question.DATE:
initial = datetime.datetime.strptime(answer.body, "%Y-%m-%d").date()
else:
initial = answer.body
if data:
# Initialize the field field from a POST request, if any.
# Replace values from the database
initial = data.get("question_%d" % question.pk)
return initial
def get_question_widget(self, question):
"""Return the widget we should use for a question.
:param Question question: The question
:rtype: django.forms.widget or None"""
try:
return self.WIDGETS[question.type]
except KeyError:
return None
#staticmethod
def get_question_choices(question):
"""Return the choices we should use for a question.
:param Question question: The question
:rtype: List of String or None"""
qchoices = None
if question.type not in [Question.TEXT, Question.SHORT_TEXT, Question.INTEGER, Question.FLOAT, Question.DATE]:
qchoices = question.get_choices()
# add an empty option at the top so that the user has to explicitly
# select one of the options
if question.type in [Question.SELECT, Question.SELECT_IMAGE]:
qchoices = tuple([("", "-------------")]) + qchoices
return qchoices
def get_question_field(self, question, **kwargs):
"""Return the field we should use in our form.
:param Question question: The question
:param **kwargs: A dict of parameter properly initialized in
add_question.
:rtype: django.forms.fields"""
# logging.debug("Args passed to field %s", kwargs)
try:
return self.FIELDS[question.type](**kwargs)
except KeyError:
return forms.ChoiceField(**kwargs)
def add_question(self, question, data):
"""Add a question to the form.
:param Question question: The question to add.
:param dict data: The pre-existing values from a post request."""
kwargs = {"label": question.text, "required": question.required}
initial = self.get_question_initial(question, data)
if initial:
kwargs["initial"] = initial
choices = self.get_question_choices(question)
if choices:
kwargs["choices"] = choices
widget = self.get_question_widget(question)
if widget:
kwargs["widget"] = widget
field = self.get_question_field(question, **kwargs)
field.widget.attrs["category"] = question.category.name if question.category else ""
if question.type == Question.DATE:
field.widget.attrs["class"] = "date"
# logging.debug("Field for %s : %s", question, field.__dict__)
self.fields["question_%d" % question.pk] = field
def has_next_step(self):
if not self.survey.is_all_in_one_page():
if self.step < self.steps_count - 1:
return True
return False
def next_step_url(self):
if self.has_next_step():
context = {"id": self.survey.id, "step": self.step + 1}
return reverse("survey:survey-detail-step", kwargs=context)
def current_step_url(self):
return reverse("survey-detail-step", kwargs={"id": self.survey.id, "step": self.step})
def save(self, commit=True):
"""Save the response object"""
# Recover an existing response from the database if any
# There is only one response by logged user.
response = self._get_preexisting_response()
if not self.survey.editable_answers and response is not None:
return None
if response is None:
response = super().save(commit=False)
response.survey = self.survey
response.interview_uuid = self.uuid
if self.user.is_authenticated:
response.user = self.user
response.save()
# response "raw" data as dict (for signal)
data = {"survey_id": response.survey.id, "interview_uuid": response.interview_uuid, "responses": []}
# create an answer object for each question and associate it with this
# response.
for field_name, field_value in list(self.cleaned_data.items()):
if field_name.startswith("question_"):
# warning: this way of extracting the id is very fragile and
# entirely dependent on the way the question_id is encoded in
# the field name in the __init__ method of this form class.
q_id = int(field_name.split("_")[1])
question = Question.objects.get(pk=q_id)
answer = self._get_preexisting_answer(question)
if answer is None:
answer = Answer(question=question)
if question.type == Question.SELECT_IMAGE:
value, img_src = field_value.split(":", 1)
# TODO Handling of SELECT IMAGE
LOGGER.debug("Question.SELECT_IMAGE not implemented, please use : %s and %s", value, img_src)
answer.body = field_value
data["responses"].append((answer.question.id, answer.body))
LOGGER.debug("Creating answer for question %d of type %s : %s", q_id, answer.question.type, field_value)
answer.response = response
answer.save()
survey_completed.send(sender=Response, instance=response, data=data)
return response
Since address is stored as models.TextField() and retrieved as Python str in the model:
In MultiWidget decompress, load from str:
class AddressWidget(MultiWidget):
...
def decompress(self, value):
if value:
return json.loads(value)
return (None, None, None, None, None)
In MultiValueField compress, dump to str:
class AddressField(MultiValueField):
...
def compress(self, value_list):
if value_list:
return json.dumps(value_list)
return ''

Sorting the django objects based on SerializerMethodField

I am trying to order the user profiles based on the timestamp of the last message in between both the users.
I am using SerializerMethodField to get the timestamp of the last message.
is there any way I can sort the data?
class UserProfileSerializer(serializers.ModelSerializer):
lastmessage = serializers.SerializerMethodField()
class Meta:
model = User
fields = ['id','lastmessage']
def get_lastmessage(self,obj):
k = self.context.get('view').kwargs['sid']
data =( Message.objects.filter(receiver=obj.id,sender=k) | Message.objects.filter(sender=obj.id,receiver=k)).order_by('-timestamp').values('message','timestamp')
if len(data) == 0:
return ""
else:
data = data.first()
data["timestamp"] = str(data["timestamp"])
return str(data)
My view:
class UserChatViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserProfileSerializer
Now my views return:
[{
"id": 4,
"lastmessage": "{'message': 'random', 'timestamp': '2020-06-14 23:49:33.077749+00:00'}"
},
{
"id": 5,
"lastmessage": ""
},
{
"id": 6,
"lastmessage": "{'message': 'sample', 'timestamp': '2020-06-14 11:53:03.880833+00:00'}"
},
{
"id": 7,
"lastmessage": ""
}]
But I want it to sort based on the timestamp of last message
You can overwrite list in order to achieve this:
def list(self, request, *args, **kwargs):
response = super().list(request, args, kwargs)
# sort response.data['results']
return response
Also, lastmessage can be a dict instead of a str, so it's easier to work with.
The order of your response should be handled in the view .
from django.db.models import Subquery, OuterRef
lm = Message.objects.filter(sender=OuterRef("id"), receiver=self.kwargs['sid']).order_by('-timestamp')
data = User.objects.all().annotate(
lastmessage=Subquery(
lm.values('timestamp')[:1]
)
).order_by('-lastmessage__timestamp')

How to add extra attributes to queryset in django rest api using serialiser and listViewAPI?

How do I add additional fields like count, status_code to the queryset in the django rest api?
class SongList(generics.ListAPIView):
"""
API endpoint that allows users to be viewed or edited===1111.
"""
serializer_class = SongSerialier
def get_queryset(self):
queryset = Song.objects.all()
id = self.request.query_params.get('id', None)
test=QuerySet()
return queryset
Above code returns only the content in the SongSerialier in the form of list, for example
[
{
"song_title": "song1",
"file_type": "mp3",
"album": 1,
"test": "1",
"my_field": false
},
{
"song_title": "song1",
"file_type": "mp3",
"album": 2,
"test": "1",
"my_field": false
}
]
I want my output like below format
{
status_code:200,
count:2,
total_count:4,
data:[
{
"song_title": "song1",
"file_type": "mp3",
"album": 1,
"test": "1",
"my_field": false
},
{
"song_title": "song1",
"file_type": "mp3",
"album": 2,
"test": "1",
"my_field": false
}
]
}
GOT THE SOLUTION
*You need to override the list method in the ListAPIView *
class SongList(generics.ListAPIView):
i=0
"""
API endpoint that allows users to be viewed or edited===1111.
"""
serializer_class = SongSerialier
def list(self, request, *args, **kwargs):
response = super(SongList, self).list(request, args, kwargs)
# Add data to response.data Example for your object:
print("Data ::: ",type(response),response,response.data)#,dict(response.data))
print ("datat type: ",type(response.data))
d1 = collections.OrderedDict()
d1['a'] = 'A'
d1['b'] = 'B'
d1['c'] = 'C'
d1['d'] = 'D'
d1['e'] = 'E'
response.data=d1
self.no+=1
print ("no:2 ",self.no)
# response.data["a_status_code"]=200
# response.data["a_status_text"] = "Success"
#response['10_mi_count'] = 10
# a=response.render().content
# print ("a: ",a)
return response
def get_queryset(self):
self.no=1
print ("no:1 ",self.no)
queryset = Song.objects.all().annotate(count_test=Count('id'))
id = self.request.query_params.get('id', None)
test=QuerySet()
#print( "=========111" ,type(queryset),self.serializer_class.data)
# print ("j1: ",j)
# j+=1
return queryset
This will give the result as
Check link
following is my serializer code
class SongSerializer(serializers.ModelSerializer):
test=serializers.SerializerMethodField()
my_field = serializers.SerializerMethodField('is_named_bar')
def is_named_bar(self, foo):
return foo.id == "bar"
def get_test(self, obj):
print ("OBJ, ",obj,type(obj),obj.id)
return "1"
class Meta:
model=Song
fields=('song_title','file_type','album','test','my_field')

Return empty JSON object with Flask-Restful Nested field object for SQLAlchemy association if association is None

The summary might be very confusing but I don't know how to formulate it more concise.
The models I have:
class Movie(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(
imdb_data = db.relationship('IMDBData', uselist=False)
class IMDBData(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(255))
rating = db.Column(db.Float)
movie_id = db.Column(db.Integer, db.ForeignKey('movie.id'))
Using Flask-Restful fields I am marshaling the response like this:
imdb_data_fields = {
'id': fields.Integer,
'title': fields.String,
'rating': fields.Float
}
movie_fields = {
'id': fields.Integer,
'title': fields.String
}
class MovieListAPI(Resource):
def __init__(self):
self.parser = reqparse.RequestParser()
super(MovieListAPI, self).__init__()
def get(self):
self.parser.add_argument('imdb_data', type=str, location='args')
args = self.parser.parse_args()
m_fields = copy.copy(movie_fields)
# TODO: Return empty object if movie.imdb_data = None
if args['imdb_data']:
m_fields['imdb_data'] = fields.Nested(imdb_data_fields)
movies = Movie.query.all()
return {'movies': marshal(movies, m_fields)}
Now if it happens that a movie does not have a corresponding imdb_data record, i.e. Movie.query.filter_by(id=123).first().imdb_data = None that movie's object is marshaled like this:
{
"id": 1302,
"imdb_data": {
"id": 0,
"rating": null,
"title": null
},
"title": "F 63 9 Love Sickness"
}
Instead I want the response to look like this:
{
"id": 1302,
"imdb_data": {},
"title": "F 63 9 Love Sickness"
}
I know how to hack this when I return one movie (by id):
if args['imdb_data']:
if movie.imdb_data:
m_fields['imdb_data'] = fields.Nested(imdb_data_fields)
else:
m_fields['imdb_data'] = fields.Nested({})
But how do I do that for the list of movies? Probably I could go through the array myself and change it by hand but there must be a more efficient way.
This can be achieved by creating a custom field, like this:
class NestedWithEmpty(Nested):
"""
Allows returning an empty dictionary if marshaled value is None
"""
def __init__(self, nested, allow_empty=False, **kwargs):
self.allow_empty = allow_empty
super(NestedWithEmpty, self).__init__(nested, **kwargs)
def output(self, key, obj):
value = get_value(key if self.attribute is None else self.attribute, obj)
if value is None:
if self.allow_null:
return None
elif self.allow_empty:
return {}
return marshal(value, self.nested)
and then using it to marshal objects passing allow_empty=True:
m_fields['imdb_data'] = NestedWithEmpty(imdb_data_fields, allow_empty=True)
I even created a pull request with this feature: https://github.com/twilio/flask-restful/pull/328
After reading the PR #328 (thanks #Andriy), and following it, my fix was to add the default arg
foo['bar'] = fields.Nested(nested_fields, default={})
Wasn't obvious in the docs.
Starting from 0.11.0, you can use the option skip_none=True to return an empty object instead of nulls.
Example with #marshal_with:
from flask_restplus import Model, fields, marshal_with
model = Model('Model', {
'name': fields.String,
'address_1': fields.String,
'address_2': fields.String
})
#marshal_with(model, skip_none=True)
def get():
return {'name': 'John', 'address_1': None}
Specifying on nested field:
from flask_restplus import Model, fields
model = Model('Model', {
'name': fields.String,
'location': fields.Nested(location_model, skip_none=True)
})
source: https://flask-restplus.readthedocs.io/en/0.11.0/marshalling.html#skip-fields-which-value-is-none

Django Form Validation Problem

I have a form that seems to never validate. The form is just three drop-down boxes. When the form is rendered, all of the boxes have values populated and the first is selected, so no matter what, the user cannot submit bad values, yet form.is_valid() always returns false. Please help!
The form
CLUSTER_TYPES = (
('ST', 'State'),
('CNT', 'County'),
('FCD', 'Congressional District'),
('GCC', 'Circle Clustering'),
);
MAP_VIEWS = (
('1', 'Single Map'),
('2', 'Two Maps'),
('4', 'Four Maps'),
);
class ViewDataForm (forms.Form):
def __init__ (self, sets = None, *args, **kwargs):
sets = kwargs.pop ('data_sets')
super (ViewDataForm, self).__init__ (*args, **kwargs)
processed_sets = []
for ds in sets:
processed_sets.append ((ds.id, ds.name))
self.fields['data_sets'] = forms.ChoiceField (label='Data Set', choices = processed_sets)
self.fields['clustering'] = forms.ChoiceField (label = 'Clustering',
choices = CLUSTER_TYPES)
self.fields['map_view'] = forms.ChoiceField (label = 'Map View', choices = MAP_VIEWS)
The view
def main_view (request):
# We will get a list of the data sets for this user
sets = DataSet.objects.filter (owner = request.user)
# Create the GeoJSON string object to potentially populate
json = ''
# Get a default map view
mapView = MapView.objects.filter (state = 'Ohio', mapCount = 1)
mapView = mapView[0]
# Act based on the request type
if request.method == 'POST':
form = ViewDataForm (request.POST, request.FILES, data_sets = sets)
v = form.is_valid ()
if form.is_valid ():
# Get the data set
ds = DataSet.objects.filter (id = int (form.cleaned_data['data_set']))
ds = ds[0]
# Get the county data point classifications
qs_county = DataPointClassification.objects.filter (dataset = ds,
division = form.cleaned_data['clustering'])
# Build the GeoJSON object (a feature collection)
json = ''
json += '{"type": "FeatureCollection", "features": ['
index = 0
for county in qs_county:
if index > 0:
json += ','
json += '{"type": "feature", "geometry" : '
json += county.boundary.geom_poly.geojson
json += ', "properties": {"aggData": "' + str (county.aggData) + '"}'
json += '}'
index += 1
json += ']}'
mapView = MapView.objects.filter (state = 'Ohio', mapCount = 1)
mapView = mv[0]
else:
form = ViewDataForm (data_sets = sets)
# Render the response
c = RequestContext (request,
{
'form': form,
'mapView_longitude': mapView.centerLongitude,
'mapView_latitude': mapView.centerLatitude,
'mapView_zoomLevel': mapView.zoomLevel,
'geojson': json,
'valid_was_it': v
})
return render_to_response ('main.html', c)
You have overridden the signature of the form's __init__ method so that the first positional parameter is sets. However, when you instantiate it, you pass request.POST as the first positional argument - so the form never gets any data, so doesn't validate.
Don't change the signature of __init__. In fact, you have everything set up correctly so you don't need to: just remove the sets=None from the method definition, and it should all work.