1

Web サイトの場所を管理するアプリケーションに取り組んでいます。このアプリケーション (場所) には、モデル (簡略化) が含まれています。

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 フィールドに関連付けられた一般的な選択を表示する代わりに、緯度、経度、および住所を HiddenInput フィールドに保存する JavaScript によってサポートされる Google マップをレンダリングするウィジェットを定義します (これも簡略化されています)。

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)

アイデアは、場所で動作する必要がある他のモデルには、場所モデルに関連付けられた 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 に入力するだけでなく、通常の選択ウィジェットの代わりに地図をレンダリングします。

私のevents/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 ()' をバイパス)、データベースに保存するときにエラーが発生することです。一方、場所を使用するアプリケーション/モデルごとに ModelForm をサブクラス化する必要があるのは (DRY のため) 適切ではないようです。

カスタム フィールドとカスタム フォーム フィールドを作成する必要がありますか? それをどのように方向付けるかについてのアイデアはありますか?ウィジェットを ForeingKey に使用できますか?

事前に感謝し、私の下手な英語を許してください.

4

0 に答える 0