Update Django from 1.6 to 1.8: Invalid field name(s) given in select_related
Asked Answered
B

3

13

I update project from Django 1.6.7 to 1.8.7 and I have got following exception with Django 1.8, although with Django 1.6 it code was right:

In[2]: from apps.route import models
In[3]: models.Trace.objects.select_related("trace_points")
Out[3]: <repr(<django.db.models.query.QuerySet at 0x3b50c10>) failed: django.core.exceptions.FieldError: Invalid field name(s) given in select_related: 'trace_points'. Choices are: user>

My models:

class Trace(SocialMixin, models.Model):
    user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='traces')
    name = models.CharField(u'Название', max_length=255)
    rating = RatingField(range=5, weight=0)
    start_date = models.DateTimeField(u'Дата старта')
    finish_date = models.DateTimeField(u'Дата окончания', null=True, blank=True)
    distance = models.DecimalField(max_digits=15, decimal_places=6, null=True, blank=True)
    created = models.DateTimeField(auto_now_add=True)
    hits = generic.GenericRelation(HitCount, object_id_field='object_pk')
    description = models.TextField(null=True, blank=True)

class TracePoint(models.Model):
    country = models.ForeignKey(Country, null=True, blank=True)
    city = models.ForeignKey(City, null=True, blank=True)
    trace = models.ForeignKey(Trace, related_name="trace_points")

I also have this bug into DetailView on Trace, DetailView uses get_related_selections, and of course I got "FieldError: Invalid field name...", to avoid error I have to use ManyToManyField instead of ForeigenKey?

Boorman answered 5/5, 2016 at 9:0 Comment(4)
The code in [3] makes no sense, since there can be more than one TracePoint associated with a Trace.Feuar
Yes, there is can be more TracePoint than one that associated with a Trace, but in old Django it really worked...Boorman
That would be a bug in the old version then.Feuar
I also have this bug into DetailView, DetailView uses get_related_selections, and of course I got "FieldError: Invalid field name...", to avoid error I have to use ManyToManyField instead of ForeigenKey?Boorman
H
22

Django 1.8 checks that the fields given in select_related are correct. The select_related method can be used for foreign keys and one to one fields. It is not possible to use it for the reverse relationship Trace back to TracePoint.

In previous versions of Django, Trace.objects.select_related("trace_points") would not raise an error, but the select_related() call would have no effect.

You can either remove the select_related() call, or replace it with prefetch_related, which will work.

Trace.objects.prefetch_related('trace_points')
Hyetology answered 5/5, 2016 at 9:15 Comment(2)
However, it's important to note that using prefetch_related() could yield different results compared to those obtained from select_related().Exclave
@Exclave I don’t follow. select_related didn’t have any effect in the code above. In what circumstances could adding prefetch_related return different results?Hyetology
R
7

Django's select_related() doesn't works for backwards foreignkey relations.

You might want to use prefetch_related() for prefetching all trace points at python level.

models.Trace.objects.prefetch_related("trace_points")
Revivalist answered 5/5, 2016 at 9:14 Comment(1)
However, it's important to note that using prefetch_related() could yield different results compared to those obtained from select_related().Exclave
W
0

With Reverse Foreign Key in one-to-many relationship, select_related() doesn't work while prefetch_related() works. *This answer explains what is Reverse Foreign Key and this answer explains more about select_related() and prefetch_related().

So, you need to use prefetch_related() instead of select_related() as shown below:

Trace.objects.prefetch_related('trace_points')
# Trace.objects.select_related("trace_points")
Windom answered 1/2, 2023 at 1:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.