'ManyToOneRel' object has no attribute 'parent_model' error with django chartit
<p>I have django project with 2 models: </p>

<pre><code>class DeviceModel(models.Model):
    name = models.CharField(max_length=255)
    def __unicode__(self):
        return self.name

class Device(models.Model):
    created_at = models.DateTimeField(auto_now_add=True)
    device_model = models.ForeignKey(DeviceModel)
    serial_number = models.CharField(max_length=255)

    def __unicode__(self):
        return self.device_model.name + " - " + self.serial_number
</code></pre>

<p>There many devices in the database and I want to plot chart "amount of devices" per "device model".</p>

<p>I'm trying to do this task with django chartit.</p>

<p>Code in view.py:</p>

<pre><code>ds = PivotDataPool(
    series=[
        {'options': {
            'source':Device.objects.all(),
            'categories':'device_model'
            },
        'terms':{
                u'Amount':Count('device_model'),
            }
        }
    ],
)

pvcht = PivotChart(
    datasource=ds,
    series_options =
          [{'options':{
            'type': 'column',
            'stacking': True
            },
            'terms':[
            u'Amount']
            }],
     chart_options =
          {'title': {
               'text': u'Device amount chart'},
           'xAxis': {
                'title': {
                   'text': u'Device name'}},
           'yAxis': {
                'title': {
                   'text': u'Amount'}}}                    
)


return render(request, 'charts.html', {'my_chart': pvcht})  
</code></pre>

<p>This seems to plot result I need, but instead of device names it plots values of ForeignKey (1,2,3,4...) and I need actual device model names.</p>

<p>I thought that solution is to change 'categories' value to:</p>

<pre><code>'categories':'device_model__name'
</code></pre>

<p>But this gives me error:</p>

<pre><code>'ManyToOneRel' object has no attribute 'parent_model'
</code></pre>

<p>This type of referencing should work accoring to official example <a href="http://chartit.shutupandship.com/demo/pivot/pivot-with-legend/" rel="nofollow">http://chartit.shutupandship.com/demo/pivot/pivot-with-legend/</a></p>

<p>What am I missing here?</p>

<hr>

<pre><code>C:\Anaconda\lib\site-packages\django\core\handlers\base.py in get_response
                    response = middleware_method(request, callback, callback_args, callback_kwargs)
                    if response:
                        break
            if response is None:
                wrapped_callback = self.make_view_atomic(callback)
                try:
                                response = wrapped_callback(request, *callback_args, **callback_kwargs)  ###
                except Exception as e:
                    # If the view raised an exception, run it through exception
                    # middleware, and if the exception middleware returns a
                    # response, use that. Otherwise, reraise the exception.
                    for middleware_method in self._exception_middleware:
                        response = middleware_method(request, e)
</code></pre>

<hr>

<pre><code>D:\django\predator\predator\views.py in charts
        series=[
            {'options': {
                'source':Device.objects.all(),
                'categories':'device_model__name'
                },
                #'legend_by': 'device_model__device_class'},
            'terms':{
                                u'Amount':Count('device_model'), ###
                    }
            }
        ],
        #pareto_term = 'Amount'
    )
</code></pre>

<hr>

<pre><code>C:\Anaconda\lib\site-packages\chartit\chartdata.py in __init__
            'terms': {
              'asia_avg_temp': Avg('temperature')}}]

        # Save user input to a separate dict. Can be used for debugging.
        self.user_input = locals()
        self.user_input['series'] = copy.deepcopy(series)

                    self.series = clean_pdps(series) ###
        self.top_n_term = (top_n_term if top_n_term 
                           in self.series.keys() else None)
        self.top_n = (top_n if (self.top_n_term is not None 
                                and isinstance(top_n, int)) else 0)   
        self.pareto_term = (pareto_term if pareto_term in 
                            self.series.keys() else None)
</code></pre>

<hr>

<pre><code>C:\Anaconda\lib\site-packages\chartit\validation.py in clean_pdps

def clean_pdps(series):
    """Clean the PivotDataPool series input from the user.
    """
    if isinstance(series, list):
        series = _convert_pdps_to_dict(series)
                    clean_pdps(series) ###
    elif isinstance(series, dict):
        if not series:
            raise APIInputError("'series' cannot be empty.")
        for td in series.values():
            # td is not a dict
            if not isinstance(td, dict):
</code></pre>

<hr>

<pre><code>C:\Anaconda\lib\site-packages\chartit\validation.py in clean_pdps
            try:
                _validate_func(td['func'])
            except KeyError:
                raise APIInputError("Missing 'func': %s" % td)
            # categories
            try:
                td['categories'], fa_cat = _clean_categories(td['categories'],
                                                                        td['source']) ###
            except KeyError:
                raise APIInputError("Missing 'categories': %s" % td)
            # legend_by
            try:
                td['legend_by'], fa_lgby = _clean_legend_by(td['legend_by'],
                                                           td['source'])
</code></pre>

<hr>

<pre><code>C:\Anaconda\lib\site-packages\chartit\validation.py in _clean_categories
    else:
        raise APIInputError("'categories' must be one of the following "
                            "types: basestring, tuple or list. Got %s of "
                            "type %s instead."
                            %(categories, type(categories)))
    field_aliases = {}
    for c in categories:
                    field_aliases[c] = _validate_field_lookup_term(source.model, c) ###
    return categories, field_aliases
def _clean_legend_by(legend_by, source):
    if isinstance(legend_by, basestring):
        legend_by = [legend_by]
    elif isinstance(legend_by, (tuple, list)):
</code></pre>

<hr>

<pre><code>C:\Anaconda\lib\site-packages\chartit\validation.py in _validate_field_lookup_term
        #     and m2m is True for many-to-many relations. 
        # When 'direct' is False, 'field_object' is the corresponding 
        # RelatedObject for this field (since the field doesn't have 
        # an instance associated with it).
        field_details = model._meta.get_field_by_name(terms[0])
        # if the field is direct field
        if field_details[2]:
                        m = field_details[0].related.parent_model ###
        else:
            m = field_details[0].model

        return _validate_field_lookup_term(m, '__'.join(terms[1:]))
def _clean_source(source):
</code></pre>