2012-10-11 104 views
0

我需要从相关模型(如管理员的过滤器属性来使用)访问属性,但我得到这个错误:'EventTimeAdmin.list_filter[1]' refers to field 'event__sites' that is missing from model 'EventTime'.不能从其他模型访问模型属性在Django

这里是从models.py相关类:

class Event(models.Model): 
    title = models.CharField(max_length=100) 
    short_description = models.CharField(max_length=250, blank=True) 
    long_description = models.TextField(blank=True) 
    place = models.ForeignKey(Place, related_name="events", default=0, blank=True, null=True) 
    one_off_place = models.CharField('one-off place', max_length=100, blank=True) 
    phone = models.CharField(max_length=40) 
    cost_low = models.DecimalField('cost (low)', max_digits=7, decimal_places=2, blank=True, null=True) 
    cost_high = models.DecimalField('cost (high)', max_digits=7, decimal_places=2, blank=True, null=True) 
    age_lowest = models.PositiveSmallIntegerField('lowest age', blank=True, null=True, help_text='Use 0 for "all ages". Leave blank if no age information is available') # Not every event submits info about age limits 
    priority = models.ForeignKey(EventPriority) 
    ticket_website = models.URLField('ticket Web site', blank=True) 
    posted_date = models.DateTimeField('date entered', default=datetime.datetime.now()) 
    updated_date = models.DateTimeField('date updated', editable=False, blank=True) 
    small_photo = models.ImageField(upload_to='img/events/%Y', blank=True) 
    teaser_text = models.TextField(max_length=1000, blank=True) 
    is_ongoing_indefinitely = models.BooleanField(db_index=True, help_text="If this box is checked, the event won't be displayed by default in the event search. Users will have to manually select \"Display ongoing events\" in order to display it.") 
    is_national_act = models.BooleanField('is a national marquee touring act') 
    categories = models.ManyToManyField(EventCategory, related_name="events") 
    bands = models.ManyToManyField(Band, related_name="events", blank=True) 
    sites = models.ManyToManyField(Site) 
    related_links = generic.GenericRelation(RelatedLink) 
    generic_galleries = generic.GenericRelation(GalleryRelationsPiece) 
    staff_photographer_attending = models.BooleanField('Staff Photographer will be attending') 

    index = EventIndex() 

    class Meta: 
     ordering = ('title',) 

    def __unicode__(self): 
     return self.title 

    def save(self, *args, **kwargs): 
     self.updated_date = datetime.datetime.now() 
     super(Event, self).save(*args, **kwargs) 

    def get_absolute_url(self): 
     if self.is_recurring(): 
      return reverse('ellington_events_ongoing_detail', args=[self.id]) 
     else: 
      next = self.get_next_time() 
      if next: 
       return next.get_absolute_url() 
      else: 
       try: 
        last = self.event_times.order_by("-event_date", "start_time")[0] 
        return last.get_absolute_url() 
       except IndexError: 
        return reverse('ellington_events_todays_events', args=[]) 

    @property 
    def _sites(self): 
     """A property used for indexing which sites this object belongs to.""" 
     return [s.id for s in self.sites.all()] 

    # def start_time(self): 
    #  return self.event_times.start_time 

    # TODO: Redundant 
    def get_absolute_url_recurring(self): 
     "Returns the absolute URL for this event's recurring-event page" 
     return reverse('ellington_events_ongoing_detail', args=[self.id]) 

    def is_recurring(self): 
     """Returns ``True`` if this event is a recurring event.""" 
     return bool(self.recurring_event_times.count()) 

    def get_cost(self): 
     "Returns this event's cost as a pretty formatted string such as '$3 - $5'" 
     if self.cost_low == self.cost_high == 0: 
      return 'Free' 
     if self.cost_low == self.cost_high == None: 
      return '' 
     if self.cost_low == 0 and self.cost_high == None: 
      return 'Free' 
     elif self.cost_low == None and self.cost_high == 0: 
      return 'Free' 

     if self.cost_low == self.cost_high: 
      cost = '$%.2f' % self.cost_low 
     elif self.cost_low == 0 or self.cost_low == None: 
      cost = 'Free - $%.2f' % self.cost_high 
     elif self.cost_high == 0 or self.cost_high == None: 
      cost = '$%.2f' % self.cost_low 
     else: 
      cost = '$%.2f - $%.2f' % (self.cost_low, self.cost_high) 
     return cost.replace('.00', '') 

    def get_age_limit(self): 
     "Returns this event's age limit as a pretty formatted string such as '21+'" 
     if self.age_lowest is None: 
      return 'Not available' 
     if self.age_lowest == 0: 
      return 'All ages' 
     return '%s+' % self.age_lowest 

    def get_place_name(self): 
     "Returns this event's venue, taking into account the one_off_place field." 
     if self.one_off_place: 
      return self.one_off_place 
     if self.place is not None: 
      return self.place.name 
     else: 
      return "" 

    def get_next_time(self): 
     """ 
     Return the next (in the future) ``EventTime`` for this ``Event``. 
     Assumes the event is not recurring. Returns ``None`` if no next time is 
     available. 
     """ 
     now = datetime.datetime.now() 
     for et in self.event_times.filter(event_date__gte=now.date()).order_by("event_date", "start_time"): 
      try: 
       dt = datetime.datetime.combine(et.event_date, et.start_time) 
      except TypeError: 
       return None 
      if dt >= now: 
       return et 
     return None 
     # TODO: proprietary 
    def get_lj_category(self): 
     """ 
     Returns either 'Nightlife', 'Music', 'Theater', 'Misc.' or 
     'Museums and Galleries' for this event. 
     """ 
     MAPPING = (
      ('Activities', 'Misc.'), 
      ('Art', 'Museums and Galleries'), 
      ('Children', 'Misc.'), 
      ('Community', 'Misc.'), 
      ('Culinary', 'Misc.'), 
      ('KU calendar', 'Misc.'), 
      ('Lectures', 'Misc.'), 
      ('Museums', 'Museums and Galleries'), 
      ('Performance', 'Misc.'), 
     ) 
     # "Performance | Theater" is a special case. 
     for c in self.categories.all(): 
      if str(c) == "Performance | Theater": 
       return 'Theater' 

     parent_categories = [c.parent_category for c in self.categories.all()] 
     for parent_category, lj_category in MAPPING: 
      if parent_category in parent_categories: 
       return lj_category 

     # Failing that, we must be in either 'Music', which can be either 
     # 'Music' or 'Nightlife', depending on the venue. 
     if self.one_off_place: 
      return 'Music' 

     # If it's downtown, it's 'Nightlife'. Otherwise, it's 'Music'. 
     if "downtown" in self.place.neighborhood.lower(): 
      return 'Nightlife' 

     return 'Music' 

class EventTime(models.Model): 
    event = models.ForeignKey(Event, related_name="event_times") 
    event_date = models.DateField('date') 
    start_time = models.TimeField(blank=True, null=True) 
    finish_time = models.TimeField(blank=True, null=True) 

    objects = EventTimeManager() 

    def long_desc(self): 
     return self.event.long_description 

    # def sites(self): 
    #  return self.event._sites 

    # def sites(self): 
    #  return self.event.sites 

    # @property 
    # def _sites(self): 
    #  """A property used for indexing which sites this object belongs to.""" 
    #  return [s.id for s in self.event.sites.all()] 

    # def _sites(self): 
    #  """A property used for indexing which sites this object belongs to.""" 
    #  return [s.id for s in self.event.sites.all()] 

    # def _sites(self): 
    #  """A property used for indexing which sites this object belongs to.""" 
    #  return [s.id for s in event.sites.all()] 

    class Meta: 
     ordering = ('event_date', 'start_time') 

    def __unicode__(self): 
     return u"%s -- %s at %s" % (self.event.title, self.event_date.strftime("%m/%d/%y"), self.event.get_place_name()) 

    def get_absolute_url(self): 
     year = self.event_date.strftime("%Y") 
     month = self.event_date.strftime("%b").lower() 
     day = self.event_date.strftime("%d") 
     return reverse('ellington_events_event_detail', args=[year, month, day, self.event.id]) 

    def get_time(self): 
     "Returns this event's time as a pretty formatted string such as '3 p.m. to 5 p.m.'" 
     if self.start_time is not None and self.finish_time is not None: 
      return '%s to %s' % (dateformat.time_format(self.start_time, 'P'), dateformat.time_format(self.finish_time, 'P')) 
     elif self.start_time is not None: 
      return dateformat.time_format(self.start_time, 'P') 
     return 'time TBA' 

    def get_part_of_day(self): 
     """ 
     Returns a string describing the part of day this event time is taking 
     place -- either 'Morning', 'Afternoon', 'Evening' or 'Night'. 
     """ 
     if self.start_time is None: 
      return 'Time not available' 
     if 3 < self.start_time.hour < 12: 
      return 'Morning' 
     elif 12 <= self.start_time.hour < 18: 
      return 'Afternoon' 
     elif 18 <= self.start_time.hour < 21: 
      return 'Evening' 
     return 'Night' 

    def is_in_the_past(self): 
     return self.event_date < datetime.date.today() 

    def happens_this_year(self): 
     return datetime.date.today().year == self.event_date.year 

    def get_other_event_times(self): 
     "Returns a list of all other EventTimes for this EventTime's Event" 
     if not hasattr(self, "_other_event_times_cache"): 
      self._other_event_times_cache = [et for et in self.event.event_times.order_by("event_date", "start_time") if et.id != self.id] 
     return self._other_event_times_cache 

    # TODO: proprietary 
    def get_weather_forecast(self): 
     "Returns a weather.forecast.DayForecast object for this EventTime" 
     try: 
      from ellington.weather.models import DayForecast 
     except ImportError: 
      return None 
     if not self.event.place.is_outdoors: 
      raise DayForecast.DoesNotExist 
     if not hasattr(self, "_weather_forecast_cache"): 
      self._weather_forecast_cache = DayForecast.objects.get(full_date=self.event_date) 
     return self._weather_forecast_cache 

DAY_OF_WEEK_CHOICES = (
    (0, 'Sunday'), 
    (1, 'Monday'), 
    (2, 'Tuesday'), 
    (3, 'Wednesday'), 
    (4, 'Thursday'), 
    (5, 'Friday'), 
    (6, 'Saturday'), 
) 

的事情是,event__titleEventTimeAdmin访问:

class EventTimeAdmin(admin.ModelAdmin): 
     list_display = ('event', 'event_date', 'start_time', 'finish_time','long_desc') 
     list_filter = ('event_date','event__sites') 
     search_fields = ('event__title', 'event_date') 
     ordering = ('-event_date',) 

     class Meta: 
      model = EventTime 

event__sites不可访问...为什么是这样?

编辑:你可以看到我的企图(注释掉)在models.py中定义sites。这些都没有奏效。

回答

0

event__sitesManyToManyField

你可以尝试以下方法:

admin.py

def get_sites(self): 
    sites = self.event.sites.all() 
    result = u'' 
    for site in sites: 
     result = u'%s - %s' % (result, site.name) # unsure about NAME - is it a valid field of Sites Model? 
    return result 

get_sites.short_description = u'Sites' 


class EventTimeAdmin(admin.ModelAdmin): 
    list_filter = ('event_date', get_sites) 

admin.site.register(EventTime, EventTimeAdmin) 

希望它能帮助。

+0

嗯...... 'list_filter =( 'EVENT_DATE',get_sites)'得到这个错误:'名 'get_sites' 不是defined' 如果我单引号添加到它,我仍然得到''EventTimeAdmin。 list_filter [1]'是指模型'EventTime'中缺少的字段'get_sites'。' 我将get_sites方法的定义添加到models.py,因为将它放在admin.py中是没有意义的,在一个类之外...... – user898763452

+0

如果你把它放在'models.py'中,你必须将它导入到管理员中,这样你就可以在没有**单引号的情况下使用它**。 – Thomas

+0

'来自ellington.events.models导入EventCategory,Event,EventTime,RecurringEventTime,UserSubmittedEvent,EventPriority '应导入EventTime及其所有已定义的类方法,对吗? – user898763452