Troubleshooting "Related Field has invalid lookup: icontains" - exception

I have the following models in models.py:
class ListinoTraduttore(models.Model):
traduttore = models.ForeignKey('Traduttore', related_name='Traduttore')
linguaDa = models.ForeignKey(Lingua, related_name = "linguaDa")
linguaA = models.ForeignKey(Lingua, related_name = "linguaA")
prezzoParola = models.CharField(max_length=50, blank=True)
prezzoRiga = models.CharField(max_length=50, blank=True)
scontoCat = models.CharField(max_length=50, blank=True)
scontoFuzzy = models.CharField(max_length=50, blank=True)
scontoRipetizioni = models.CharField(max_length=50, blank=True)
class Meta:
verbose_name_plural = "Listini Traduttori"
def __unicode__(self):
return u"%s Da %s A %s Parola=%s Riga=%s ScontoCAT=%s ScontoFuzzy=%s ScontoRipetizioni=%s" % (self.traduttore, self.linguaDa, self.linguaA, self.prezzoParola, self.prezzoRiga, self.scontoCat, self.scontoFuzzy, self.scontoRipetizioni)
class Traduttore(models.Model):
nome = models.CharField(nomeString, max_length=50)
cognome = models.CharField(cognomeString, max_length=50)
nomeAzienda = models.CharField(nomeAziendaString, max_length=50, blank=True)
codiceFiscale = models.CharField(codiceFiscaleString, max_length=50, blank=True)
partitaIva = models.CharField(partitaIvaString, max_length=50, blank=True)
indirizzo = models.CharField(indirizzoString, max_length=50, blank=True)
telefono = models.CharField(telefonoString, max_length=50, blank=True)
fax = models.CharField(faxString, max_length=50, blank=True)
email = models.EmailField(max_length=50, blank=True)
referente = models.CharField(referenteString, max_length=50, blank=True)
valuta = models.ForeignKey(Valuta)
metodoPagamento = models.ForeignKey(MetodoPagamento)
datiBancari = models.CharField(datiBancariString, max_length=50, blank=True)
programmiUtilizzati = models.ManyToManyField(Programma, blank=True)
note = models.CharField(max_length=200, blank=True)
listino = models.ManyToManyField(ListinoTraduttore, related_name='listino', blank=True)
def __unicode__(self):
return u"%s %s %s" % (self.nome, self.cognome, self.nomeAzienda)
class Meta:
verbose_name_plural = "Traduttori"
While in the admin.py I have the following:
class TraduttoreAdmin(admin.ModelAdmin):
list_display = ("nome", "cognome", "nomeAzienda")
search_fields = ["nome", "cognome", "nomeAzienda"]
class ListinoTraduttoreAdmin(admin.ModelAdmin):
list_display = ("traduttore", "linguaDa", "linguaA", "prezzoParola", "prezzoRiga", "scontoCat", "scontoFuzzy", "scontoRipetizioni")
search_fields = ['traduttore__nome", "linguaDa", "linguaA"]
But when I try to make a search in the admin page in the ListinoTraduttore table I have the following error:
TypeError at /admin/itrad/listinotraduttore/
Related Field has invalid lookup: icontains
Request Method: GET
Request URL: http://127.0.0.1:8000/admin/itrad/listinotraduttore/?q=Fenicio
Django Version: 1.4.1
Exception Type: TypeError
Exception Value:
Related Field has invalid lookup: icontains
Exception Location: /Library/Python/2.7/site-packages/django/db/models/fields/related.py in get_prep_lookup, line 142
Python Executable: /usr/bin/python
Python Version: 2.7.2
Python Path:
['/Users/nicolac/Documents/DjangoProjects/mysite',
'/Library/Python/2.7/site-packages/pip-1.1-py2.7.egg',
'/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python27.zip',
'/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7',
'/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-darwin',
'/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-mac',
'/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-mac/lib-scriptpackages',
'/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python',
'/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-tk',
'/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-old',
'/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-dynload',
'/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/PyObjC',
'/Library/Python/2.7/site-packages']

This is to (hopefully) simplify the answer.
Don't filter on a ForeignKey field itself!
Change this
search_fields = ['foreignkeyfield']
to this (notice TWO underscores)
search_fields = ['foreignkeyfield__name']
name represents the field-name from the table that we have a ForeignKey relationship with.

Have you tried adding the __fieldname on those Lingua references in the ListinoTraduttoreAdmin search_fields, like:
class ListinoTraduttoreAdmin(admin.ModelAdmin):
list_display = ("traduttore", "linguaDa", "linguaA", "prezzoParola", "prezzoRiga", "scontoCat", "scontoFuzzy", "scontoRipetizioni")
search_fields = ['traduttore__nome", "linguaDa__field1", "linguaA_field2"]

Use Django's double underscore convention instead. docs
foreignkeyfield__name
Make sure you are not adding any Foreignkey or ManyToManyField to your search_field directly.
class ListinoTraduttoreAdmin(admin.ModelAdmin):
list_display = ("traduttore", "linguaDa", "linguaA", "prezzoParola", "prezzoRiga", "scontoCat", "scontoFuzzy", "scontoRipetizioni")
search_fields = ['traduttore__nome", "linguaDa__field1", "linguaA__field2"]

Double underscore needed
class exampleAdmin(admin.ModelAdmin):
search_field = ('yourforeignkeyname__choosefieldnameinyourforeignkey')

This worked for me.
Search the field of the foreign key using my_related_object__first_attribute:
search_fields = ('author__username', 'title')
from models
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='blog_posts2')

This error, mostly occurs when you try to filter using a ForeignKey. I think the error is in the search_filelds. Check it. search_fields = ['traduttore__nome", "linguaDa", "linguaA"]. This two ForeignKey ("linguaDa", "linguaA") are the problem. Remove them. I think this helps.

This may not answer the original question, but, every so often I run into a similar invalid lookup error because I accidentally used _set in a lookup, e.g. <model_name>_set instead of just <model_name>.
Basically, I tend to confuse the related_query_name with the default_related_name
, which does include _set (also see queries docs and related manager docs).
From the lookups documentation:
It works backwards, too. Whilst it can be customized, by default you refer to a “reverse” relationship in a lookup using the lowercase name of the model.
(my emphasis)
Confusing thing is that the default related_name (i.e. <model_name>_set) is not the same as the default related_query_name (i.e. <model_name>), but if you set a custom related_name (or default_related_name, via model Meta options), that will also be used as the default related_query_name (as mentioned in the docs).

it may be weird
search_fields = ['traduttore__nome']
giving like this , with single quotes will create error.
search_fields = ["traduttore__nome"]
giving with double quotes will fix the issue
foreignkeyfield__lookupfield - this is the format

Please check if the field either exists in the model or not, if not, then remove the search field from the search list.
Then, check if the search field value is either a foreign key or not, if any field is a foreign key, then please add the foreign key's field name like ForeignKey__FieldName (FieldName is the very field you wanna search).

add in admin.py
admin.site.register(Traduttore, TraduttoreAdmin)
admin.site.register(ListinoTraduttore, ListinoTraduttoreAdmin)
see the link https://docs.djangoproject.com/en/dev/intro/tutorial02/

Related

Django model id being overwritten by id of GenericForeignKey

I am trying create a new database entry using a custom Django model I created. However, when I try to create the model and save it, the id does not increment. Instead, the previous database entry is overwritten whose id == 1. I have tried setting force_insert=True inside the save() function, but it results in a runtime error where the primary key already exists. I don't set any primary values in the creation of the object, so I'm not sure why the id is not being incremented. I am running the test code in the manage.py shell. All the models have been migrated properly.
The model:
class RoadWayData(models.Model):
blocked_lanes = models.PositiveIntegerField()
city = models.CharField(max_length=255)
county = models.CharField(max_length=255)
direction = models.CharField(max_length=255, blank=True, null=True, default=None)
eto = models.CharField(max_length=255)
incident_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
incident_object = GenericForeignKey('incident_type', 'id')
injuries = models.PositiveIntegerField()
postmile = models.CharField(max_length=255, blank=True, null=True, default=None)
queue = models.CharField(max_length=255, default="NONE: Freeflow Conditions")
route = models.CharField(max_length=255, blank=True, null=True, default=None)
street = models.CharField(max_length=255, blank=True, null=True, default=None)
timestamp = models.DateTimeField(auto_now=True)
update = models.PositiveIntegerField()
maintenance = models.CharField(max_length=255)
tow = models.CharField(max_length=255)
weather = models.CharField(max_length=255)
vehicles_involved = models.PositiveIntegerField()
The test code:
from incident.models import *
import datetime
x = IncidentIndex.objects.get(id=1)
y = CHPIncident.objects.get(id=x.incident_object.id)
print("ID already exists in DB: {}".format(RoadWayData.objects.get(id=1).id))
z = RoadWayData(
blocked_lanes=0,
city="testCity",
county="testCounty",
direction="NB",
eto="Unknown",
highway_accident=True,
incident_object=y,
injuries=0,
postmile="New Postmile",
route="new Route",
update = 2,
maintenance= "Not Requested",
tow="Not Requested",
weather="Clear Skies",
vehicles_involved=0,
)
z.save()
print("New Data Object ID: {}".format(z.id))
Shell Output:
ID already exists in DB: 1
New Data Object ID: 1
Edit #1:
I am using a mySQL database and have not overridden the save() function. The mySQL console shows only one entry in the table(the model that was most recently saved).
Edit #2
I commented out the RoadWayData model and migrated the changes to wipe the table. Afterwards, I un-commented the model and migrated the changes to add it back to the database. The issue still persists.
Edit #3
I was able to manually insert a new entry into the table using the mySQL console. The ID incremented correctly. Perhaps it is a Django bug?
Edit #4
I've pinpointed the source of the problem. The problem stems from the contenttypes library. More specifically, the GenericForeignKey. For some reason when an the content object is assigned, the model inherits the content object's id.
Code with problem isolated:
x = IncidentIndex.objects.get(id=1)
y = CHPIncident.objects.get(id=x.incident_object.id)
r = RoadWayData(
...
incident_object = None, # Do not assign the generic foreign key
...
)
r.save()
print(r) # Shows <RoadWayData object> with CORRECT id
r.incident_object = y # Assign the general object
print(r) # Shows <RoadWayData object> with the id of y. INCORRECT
The easiest fix would be to create a variable to keep track of the Model's id BEFORE assigning the content_object (incident_object in my case).
FIX:
... initialization from code above ...
r.save()
r_id = r.id # SAVE THE CORRECT ID BEFORE ASSIGNING GENERIC FOREIGN KEY
r.incident_object = y # ASSIGN THE GENERIC FOREIGN OBJECT
r.id = r_id # OVERWRITE THE ID WITH THE CORRECT OLD ID
r.save()
The incident_object field in the RoadWayData model, has the reference id (the second parameter) set to its own id. So, when model assigns incident_object , it overwrites the id of the model.
To fix it, create a new PostiveIntegerField (like incident_id) and replace
incident_object = GenericForeignKey('incident_type', 'id')
with
incident_id = models.PostiveIntegerField(null=True)
incident_object = GenericForeignKey('incident_type', 'incident_id')

Django Query values_list getting last value

Lets say I have a blog and a class user in a model. Furthermore I have a class comment connected with a foreign key.
class User(models.Model):
UserName = models.CharField(max_length=50, blank=True)
UserCountry = models.CharField(max_length=2, blank=True)
class Comment(models.Model):
commentText = models.TextField(max_length=1000)
commentSub = models.ForeignKey(User, related_name='comLink')
created_at = models.DateTimeField(auto_now_add=True)
Now I want to make an csv export in model admin and a I have a queryset with values_list.
I am wondering whether there exists a possibility to get each User once and e.g. only the last comment?
myList = queryset.values_list('UserName', 'UserCountry', 'comLink__commentText')
comLink is the related name. Now I just want the last comment. A timestamp is existing and I have not figured out how to filter or reverse etc.
You can do it with Subquery, I don`t know your model design, so it would be approximately like that:
from django.db.models import OuterRef, Subquery
com = Comment.objects.filter(commentSub=OuterRef('pk')).order_by('-created_at')
myList = queryset.annotate(LastComment=Subquery(com.values('commentText')[:1]))
myList = myList.values_list('UserName', 'UserCountry', 'LastComment')
https://docs.djangoproject.com/en/2.0/ref/models/expressions/#subquery-expressions

Get JSON data (Django)

This my model
Driver Model
class Driver(models.Model):
named = models.CharField(max_length=150)
ident = models.CharField(max_length=100, null=True, blank=True)
def __unicode__(self):
return self.named
manufacture model
class Carlcid(models.Model):
namec = models.CharField(max_length=100)
lc_id = models.CharField(max_length=100, null=True, blank=True)
def __unicode__(self):
return unicode(self.namec)
Car model
class Car(models.Model):
f_idcar = models.ForeignKey(Carlcid, related_name='carlcd')
id_driver = models.ForeignKey(Driver)
def __unicode__(self):
return unicode(self.f_idcar)
This My views
def get_name_driver(request):
name = request.GET.get('name')
query = Car.objects.filter(f_idcar__namec=name)
results=[]
for q in query:
m_json={}
m_json['nama']= q.named
results.append(m_json)
return HttpResponse(results,"application/json")
i get {'nama': <Driver: Michael>}
but i wont get result like this {'nama': "Michael"}, How to get result like that, thanks for help.
You must get the driver name with the following line :
m_json['nama']= q.id_driver.named
Your new view :
def get_name_driver(request):
name = request.GET.get('name')
query = Car.objects.filter(f_idcar__namec=name)
results=[]
for q in query:
m_json={}
m_json['nama']= q.id_driver.named
results.append(m_json)
return HttpResponse(results,"application/json")
In addition to my answer, I want give you an advice :
You should named your foreign key like the model. Yes, in database it will be store the driver id, but when you use Django ORM, you don't get the id of driver but a Driver object.
So I advise you to rename id_driver by driver so you will use
m_json['nama']= q.driver.named
but it's not required, just advise ;)

depth = 1 doesn't work properly and it's saves Null in ManyToManyField and ForeignKey fields in Django Rest Framework

after adding depth = 1 doesn't work properly
=> models.py file
class State(models.Model):
state_name = models.CharField(max_length = 30, unique=True)
def __unicode__(self):
return str(self.state_name)
class City(models.Model):
state = models.ForeignKey(State, related_name='state_city')
city_name = models.CharField(max_length = 30)
def __unicode__(self):
return str(self.city_name)
class Meta:
ordering = ('city_name',)
unique_together = ('state', 'city_name',)
class Snippet(models.Model):
created = models.DateTimeField(auto_now_add=True)
title = models.CharField(max_length=100, blank=True, default='')
code = models.TextField()
linenos = models.BooleanField(default=False)
owner = models.ForeignKey('auth.User', related_name='snippets')
state = models.ForeignKey(State,blank=True,null=True)
city = models.ManyToManyField(City)
=> serializers.py file
class StateSerializer(serializers.ModelSerializer):
class Meta:
model = State
class CitySerializer(serializers.ModelSerializer):
state_name = serializers.CharField(source='state.state_name', read_only=True)
class Meta:
model = City
class SnippetSerializer(serializers.ModelSerializer):
owner = serializers.ReadOnlyField(source='owner.username', read_only=True)
class Meta:
model = Snippet
fields = ('id', 'title', 'code', 'linenos', 'owner', 'state', 'city')
depth = 1
I have added ForeignKey and ManyToManyField fields in state and city respectively. It doesn't save values in SnippetSerializer while added depth = 1 in Meta Class (it saves Null value in state and city fields). When I add depth = 1 JSON showing related fields as it should be but it doesn't work properly while add new Snippet. Without depth = 1 it works fine.
I have complex database where tables has many ManyToMany and ForeignKey related fields. Please give me suggestion so I can get related data in JSON.
I have djangorestframework-3.1.2 version. I have used latest version too but same problem. please give me solution and thanks in advance.
I faced the same problem and managed to solve it. Since the problem is with the depth, I just change the depth value in the init method.
class SnippetSerializer(serializers.ModelSerializer):
owner = serializers.ReadOnlyField(source='owner.username', read_only=True)
class Meta:
model = Snippet
fields = ('id', 'title', 'code', 'linenos', 'owner', 'state', 'city')
depth = 1
def __init__(self, *args, **kwargs):
super(SnippetSerializer, self).__init__(*args, **kwargs)
request = self.context.get('request')
if request and request.method=='POST':
self.Meta.depth = 0
else:
self.Meta.depth = 1
In the code above, I changed the depth dynamically according to what type of request that I made.
But, this is the workaround that I found myself, I'm not sure if this is the best practice but it solve the problem with just little modification.
depth is only for representation (http://www.django-rest-framework.org/api-guide/serializers/#specifying-nested-serialization). If you want to create/update the related fields too you have to overwrite the create/update methods in the serializer (http://www.django-rest-framework.org/api-guide/relations/#writable-nested-serializers).
Greetings.

Two foreign key fields, exactly one is set to a value, the other null in django model with MySQL database

I have a django model with two foreign key fields, one that points to product, the other points to portfolio in the code below. Exatcly one of these should be set for each Lca record. I know I can do this with MySQL triggers, but I was wondering if there was a way to make this conditional save in django
class Lca(models.Model):
product = models.ForeignKey(product, null=True, blank=True)
portfolio = models.ForeignKey(portfolio, null=True, blank=True)
carbon_price = models.DecimalField(max_digits=10, decimal_places=2, blank=True, null=True)
name = models.CharField(max_length=255, blank=True)
total_footprint = models.IntegerField(blank=True, null=True)
calculation_type = models.CharField(max_length=9)
total_cv = models.DecimalField(max_digits=10, decimal_places=0, blank=True, null=True)
source = models.CharField(max_length=255, blank=True)
date_from = models.DateField()
date_to = models.DateField(blank=True, null=True)
def __unicode__(self):
return self.name
# end __unicode__
# end
You can override the model's save method:
def save(self, *args, **kwargs):
if self.product and self.portfolio or not self.product and not self.portfolio:
raise ValueError('Exactly one of [Lca.product, Lca.portfolio] must be set')
super(Lca, self).save(*args, **kwargs)
Note that this method is not applicable to bulk_create.
You can use clean forms validations if you requested your data from a form.
I would recommend adding a model clean() method for any custom validation you want to add. Model clean methods are called automatically by ModelForms, but not by save(), so you may need to call the model full_clean() method yourself and handle ValidationErrors if they occur, depending on your use case.
See the Django documentation for more information on Model.clean().