我正在开发一个管理网站位置的应用程序。此应用程序(位置)包含模型(简化):
class Location(models.Model):
""" Model for storing locations, places and addresses """
address = models.CharField(_('address'), max_length=100, blank=True)
""" Location address """
latitude = models.FloatField(_('latitude'), blank = True)
""" Latitude info point """
longitude = models.FloatField(_('longitude'), blank = True)
""" Longitude info point """
因此,想要存储位置的其他应用程序和模型实际上包含此模型的 ForeignKey。此外,位置应用程序定义了一个小部件,它不显示与 ForeignKey 字段关联的典型选择,而是呈现由 javascript 支持的 google 地图,该地图将纬度、经度和地址保存在 HiddenInput 字段中(也简化了):
class LocationEditWidget(HiddenInput):
def __init__(self, attrs=None):
default_attrs = {}
if attrs:
default_attrs.update(attrs)
super(LocationEditWidget, self).__init__(default_attrs)
class Media:
js = (
'http://maps.google.com/maps/api/js?sensor=true',
'js/gmaps.js',
'js/location-select.js',
)
def render(self, name, value, attrs=None):
self.attrs['id'] = self.attrs.get('id', 'unique')
self.attrs['latitude'] = self.attrs.get('latitude', 'auto')
self.attrs['longitude'] = self.attrs.get('longitude', 'auto')
self.attrs['geocoding'] = self.attrs.get('geocoding', 'True')
self.attrs['geolocation'] = self.attrs.get('geolocation', 'True')
self.attrs['width'] = self.attrs.get('width', '400')
self.attrs['height'] = self.attrs.get('height', '400')
output = super(LocationEditWidget, self).render(name, '%s,%s,%s' % (value.latitude, value.longitude, value.address), attrs)
map_html = render_to_string('./select_location.html',
{
"id" : self.attrs['id'],
"geocoding_button" : self.attrs['geocoding'],
"geolocation_button": self.attrs['geolocation'],
"latitude" : self.attrs['latitude'],
"longitude" : self.attrs['longitude'],
"width" : self.attrs['width'],
"height" : self.attrs['height']
})
return mark_safe(output+map_html)
这个想法是任何其他需要处理位置的模型都有一个与 Location 模型关联的 ForeignKey 字段,例如:
class Event(models.Model):
"""
`Events` main model.
"""
title = models.CharField(_('title'), max_length=100, blank=True)
""" Title. """
place = models.ForeignKey(Location, verbose_name=_('place'), related_name="place", blank=True)
""" Location. """
meeting_point = models.ForeignKey(Location, verbose_name=_('place'), related_name="meeting_point", blank=True)
""" Meeting Point """
duration = models.PositiveIntegerField(_('duration days'), blank=True)
""" Duration, specified in days. """
price = models.DecimalField(_('price'), max_digits=7, decimal_places=2, blank=True)
""" Price. """
因此,当您发送表单时(除了按惯例保存所有其他模型字段),将使用提供的位置信息(纬度、经度和地址)创建一个新的 Location 对象,并将其存储在数据库中。最后使用这个新的 Location 对象建立与 ForeignKey 字段(之前模型中的“地点”)的关系。
目前,除了用纬度、经度和方向填充 HiddenInput 之外,该小部件可以正常工作并呈现地图而不是典型的选择小部件。
在我的事件/forms.py 中:
class NewEventForm(forms.ModelForm):
def save(self):
value = self.data['place'].split(',');
location = Location(latitude=value[0], longitude=value[1], address=value[2:])
self.instance.place = location
new_event = super(NewEventForm, self).save(commit=False)
new_event.save()
return new_offer
class Meta:
model = Event
fields = ('title', 'duration', 'price', 'place')
widgets = {
'place': LocationEditWidget(),
}
在我的 events/views.py 中:
@login_required
def event_new(request):
new_event = Event(price=0, owner=request.user)
if request.method == 'POST':
# Form submited
Event_form = NewEventForm(request.POST, instance=new_event)
if event_form.is_valid():
# Form succesfully validated
event_form.save()
return HttpResponseRedirect('/Event/%s/edit' % new_event.id)
else:
# Initial form
event_form = NewEventForm(instance=new_event)
return render_to_response( 'events/event_new.html',
{'event_form':event_form},
context_instance=RequestContext(request))
但我是 Django 新手,在理解小部件、表单、字段和表单字段之间的关系时遇到了一些问题。问题是表单无法正确验证,如果我强制验证(通过'event_form.is_valid()')保存到数据库时会出错。另一方面,似乎不太正确(因为 DRY)必须为每个使用位置的应用程序/模型子类化 ModelForm。
我需要创建自定义字段和自定义表单字段吗?关于如何定位它的任何想法?我可以将小部件用于 ForeingKey 吗?
预先感谢,请原谅我的英语不好。