Error in the line as below:
'ForwardManyToOneDescriptor' object has no attribute 'pk'
friend_user = User.objects.get(pk=Friend.to_user.id)
Thanking you in advance,
models.py
class Friend(models.Model):
status = models.CharField(max_length=10)
from_user = models.ForeignKey(AUTH_USER_MODEL, on_delete=models.CASCADE, related_name = 'from_user')
to_user = models.ForeignKey(AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="to_user")
date_modified = models.DateTimeField(auto_now=True, blank=True)
date_created = models.DateTimeField(auto_now_add=True, null=True)
def __str__(self):
return self.to_user.email
Use 'id' instead of 'pk', If Friend is your another model, then need to get an instance of Friend class. So that you can access the attributes
friend_user = User.objects.get(id=Friend.to_user.id)
The related_name specifies the name of the relation at the target model, so your
to_user = models.ForeignKey(
AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name="to_user" # <-- confusing relation name
)
adds a relation User.to_user. This is a confusing name because this to_user actually relates to a Friend. And because a foreign key technically allows multiple friends refer to the same user, it should be a plural.
So a better name would be to_friends, which adds Friend.to_user and User.to_friends:
to_user = models.ForeignKey(
AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name="to_friends" # <-- better relation name
)
Provided you changed the name of the relation, you can find the friend for a given user using:
friend = User.to_friends.get(id=...)
assuming the user actually has this friend. If not, you get a Friend.DoesNotExist exception. If you want to avoid that and get a None friend instead, use:
friend = User.to_friends.filter(id=...).first()
if friend is not None:
... # Do something with friend.
Related
Basically I have two models, one for Icons and another for Types which have 3 icons (business rule). In my models.py file I have the following:
class Icon(models.Model):
name = models.CharField(max_length=60)
image_URL = models.CharField(max_length=255)
modified_date = models.DateTimeField(auto_now=True)
creation_date = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.name
class Type(models.Model):
name = models.CharField(max_length=60)
modified_date = models.DateTimeField(auto_now=True)
creation_date = models.DateTimeField(auto_now_add=True)
icon1 = models.ForeignKey(Icon, null=True, blank=True, on_delete=models.SET_NULL, related_name="icon1")
icon2 = models.ForeignKey(Icon, null=True, blank=True, on_delete=models.SET_NULL, related_name="icon2")
icon3 = models.ForeignKey(Icon, null=True, blank=True, on_delete=models.SET_NULL, related_name="icon3")
def __str__(self):
return self.name
In my admin.py file I have the following:
class TypeAdmin(admin.ModelAdmin):
list_display = (
'name',
'icon1__name',
'modified_date',
'creation_date',
'id'
)
...
admin.site.register(models.Type, TypeAdmin)
Everything works fine but I can't get it to display the icon's name. This works for other classes which have a single Foreign Key attribute of the same model, however here since there's three Foreign Key attributes of the same model, I get an error:
<class 'app.admin.TypeAdmin'>: (admin.E108) The value of 'list_display[1]' refers to 'icon1__name', which is not a callable, an attribute of 'TypeAdmin', or an attribute or method on 'app.Type'.
What is causing this error? How may I fix it? The FK is allowed to be null (or blank) because some types are allowed to not have icons (not be required).
Solved: thanks to Iain's answer, should not call attribute and only leave it as icon1 instead of icon1__name since it calls the __str__ method which returns the name anyway.
These are my two models, when I try to open City page on Django I get an error: "column city.country_id_id does not exist". I don't know why python adds extra _id there.
class Country(models.Model):
country_id = models.CharField(primary_key=True,max_length=3)
country_name = models.CharField(max_length=30, blank=True, null=True)
class Meta:
managed = False
db_table = 'country'
class City(models.Model):
city_id=models.CharField(primary_key=True,max_length=3)
city_name=models.CharField(max_length=30, blank=True, null=True)
country_id = models.ForeignKey(Country, on_delete=models.CASCADE)
class Meta:
managed = False
db_table = 'city'
Because if you construct a foreign key, Django will construct a "twin field" that stores the primary key of the object. The foreign key itself is thus more a "proxy" field that fetches the object.
Therefore you normally do not add an _id suffix to the ForeignKey:
class City(models.Model):
city_id = models.CharField(primary_key=True,max_length=3)
city_name = models.CharField(max_length=30, blank=True, null=True)
country = models.ForeignKey(Country, on_delete=models.CASCADE)
class Meta:
managed = False
db_table = 'city'
It however might be better for unmanaged tables, to specify a db_column=… parameter [Djang-doc] in the ForeignKey:
class City(models.Model):
city_id = models.CharField(primary_key=True,max_length=3)
city_name = models.CharField(max_length=30, blank=True, null=True)
country = models.ForeignKey(Country, db_column='country_id', on_delete=models.CASCADE)
class Meta:
managed = False
db_table = 'city'
With this parameter you make it explicit how the column is named at the database side.
this is due to Django's behind the scenes magic.
The fields documentation is very clear about that and I highly recommend you read the Foreign Key section in the link below:
https://docs.djangoproject.com/en/3.0/ref/models/fields/#django.db.models.ForeignKey
Basically, when you want to access the Country reference in the if a City instance, you would do it like this:
city.country_id
I also recommend another naming convention for your Foreign Key fields. Instead of <modelname>_id = models.ForeignKey... just call it <modelname> = models.ForeignKey...
Hope this helps, happy coding
I have the following models:
class Color(models.Model):
name = models.CharField(max_length=50, null=False, blank=False)
def __str__(self):
return self.name
class Flower(models.Model):
flower_number = models.PositiveSmallIntegerField(
default=1,blank=True, null=True)
petal_color = models.ManyToManyField(Color,blank=True, related_name="%(app_label)s_%(class)s_petal",
related_query_name="%(app_label)s_%(class)s")
petal_outer_color = models.ManyToManyField(Color,blank=True, related_name="%(app_label)s_%(class)s_petal_outer",
related_query_name="%(app_label)s_%(class)s")
class Meta:
abstract = True
class Plant(Flower):
name = models.CharField(max_length=50, null=False, blank=False, unique=True)
On the Admin I just have:
admin.site.register(Plant)
When I go into the Django admin and fill out either of the manytomany petal_color or petal_outer_color with data the other manytomany field automatically gets filled when it saves. How do I stop this from happening? Nothing shows up as an error and I tried going back and deleting and re-entering data but it still happens
Try using symmetrical=False in the ManyToManyField, that might be causing the issue here as you have two M2M fields going to the same model.
Read up on symmetrical in the Django docs.
Do something like this
class Flower(models.Model):
flower_number = models.PositiveSmallIntegerField(
default=1,blank=True, null=True)
petal_color = models.ManyToManyField(Color,blank=True, symmetrical=False related_name="%(app_label)s_%(class)s_petal",
related_query_name="%(app_label)s_%(class)s")
petal_outer_color = models.ManyToManyField(Color,blank=True, symmetrical=False, related_name="%(app_label)s_%(class)s_petal_outer",
related_query_name="%(app_label)s_%(class)s")
class Meta:
abstract = True
By default, the value of symmetrical is True for Many to Many Field which is a bi-directional relationship.
The ManyToManyField is assumed to be symmetrical – that is, if I am your friend, then you are my friend.
I'd like to have a reference field (normally it is a foreignkey field)
parent field is the reference field.
Following is the simplified models to show what I'm trying to do.
For a given class Foo, I'd like to create another class FooCopy that can hold many copies of Foo.
(FooCopy.id, FooCopy.user_edit) pair is unique.
class Foo(Base):
parent = models.ForeignKey(
'self',
null=True, blank=True
)
class FooCopy(models.Model):
_id = models.AutoField(primary_key=True)
id = models.IntegerField(blank=True, null=True, db_index=True)
user_edit = models.ForeignKey(settings.AUTH_USER_MODEL)
parent = models.ForeignKey(
'self',
null=True, blank=True,
to_field='id',
db_constraint=False,
)
foo = Foo.objects.create()
foo_data = model_to_dict(foo)
foo_copy1 = Foo.objects.create(user_edit=user1, **foo_data)
foo_copy2 = Foo.objects.create(user_edit=user2, **foo_data)
def model_to_dict(obj, exclude=[]):
data = {}
for f in obj.__class__._meta.get_fields():
if f.name in exclude:
continue
if f.one_to_many:
continue
if isinstance(f, ForeignKey):
field_name = "{}_id".format(f.name)
else:
field_name = f.name
data[field_name] = getattr(obj, field_name)
return data
I'm getting an error saying Foo.id needs to be unique.
(FooCopy.id must set unique=True because it is referenced by a foreign key.)
Is there a relational field I could use to reference another django model instance without the restriction above? (Or could I get away with it somehow?)
All I need is the ability to use foo and foo_id, I don't need the referential integrity of ForeignKey.
-- edit
After reading Daniel Roseman's comments I think I can have
parent_id = models.IntegerField()
#property
def parent(self):
return self._default_manager.get(id=parent_id, user_edit=self.user_edit)
Although I will probably miss some of stuff that django provides for foreignkey such as parent__name etc, I'm not sure if there's a better way of doing this.
In a Django, given a Person model:
class Person(models.Model):
person_id = models.AutoField(primary_key=True, blank=False, null=False)
name = models.CharField(max_length=256, blank=False, default="")
and a Member model which has a person as a Foreign Key:
class Member(models.Model):
member_id = models.AutoField(primary_key=True, blank=False, null=False)
person = models.ForeignKey(Person)
I'm looking to be able to add a field to the Member model which contains the name of the person.
I've tried:
name = person.name and
name = self.person.name
with no luck.
I could define a function:
def name(self):
return self.person.name
...but then I would need to reference it with parens: member.name()
And, of course, I could always just reference it via member.person.name, but that's so verbose.
Is there a way to define this attribute?
You can use the #property as a decorator.
#property
def name(self):
return self.person.name
Now, you can just reference it as
member.name
instead of member.name()
Now, name is treated as a property on Member class, instead of a class method.