How to make django association reference to itself - django

I have:
class Direction(models.Model):
left = models.OneToOneField(
'self', on_delete=models.SET_NULL, null=True, related_name='right')
right = models.OneToOneField(
'self', on_delete=models.SET_NULL, null=True, related_name='left')
The error:
ant.Direction.left: (fields.E302) Reverse accessor for 'ant.Direction.left' clashes with field name 'ant.Direction.right'.
HINT: Rename field 'ant.Direction.right', or add/change a related_name argument to the definition for field 'ant.Direction.left'.
How does one make this relationship so that a.left = b and b.right = a?

You can not use as related_name the same as the fields that have been defined. You likely do not want to work with two OneToOneFields anyway, you can define a single OneToOneField, and set the related name to the opposite, so:
class Direction(models.Model):
left = models.OneToOneField(
'self',
on_delete=models.SET_NULL,
null=True,
related_name='right'
)
# no right
So now if a direction a has as .left a direction b, then b has as .right the object a.
If there is no .right, then accessing .right will raise a Direction.DoesNotExist exception, we can however fix this issue by making use of another for the related_name, and work with a property that will wrap it in a try-except:
class Direction(models.Model):
left = models.OneToOneField(
'self',
on_delete=models.SET_NULL,
null=True,
related_name='_right'
)
#property
def right(self):
try:
return self._right
except Direction.DoesNotExist:
return None
#right.setter
def _set_right(self, value):
self._right = value

Related

Django / OnetoMany relation within the same class

Here is my models.py
class Scenes(models.Model):
name = models.SlugField('Scene name', max_length=60,unique=True)
record_date = models.DateTimeField('Scene date')
manager = models.ForeignKey(
settings.AUTH_USER_MODEL,
blank=True,
null=True,
on_delete=models.SET_NULL)
description = models.TextField(blank=True)
previous = models.OneToOneField(
'self',
blank=True,
null=True,
related_name='next',
on_delete=models.SET_NULL
)
I have started with one instance : Scene1
The problem is I want to have on to many choices and not one to one like explained below
Nevertheless, When I change to
previous = models.ManyToManyField(
Then I also get an error about on_delete :
TypeError: init() got an unexpected keyword argument 'on_delete'
What would be the best djangonic way ?
As I understand, your requirements are:
One scene can have only one previous scene
One scene can have many next scenes
You are almost there. Instead of OneToOneField, use ForeignKey with self reference:
previous = models.ForeignKey('self', related_name='next', ...)

'ForwardManyToOneDescriptor' object has no attribute 'pk'

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_name argument required

I've recieved the following error and I'm not sure how to handle this in my model.
HINT: Add or change a related_name argument to the definition for 'UserCart.state_tax' or 'UserCart.fed_tax'.
userorders.UserCart.state_tax: (fields.E304) Reverse accessor for 'UserCart.state_tax' clashes with reverse accessor for 'UserCart.other_tax'.
models.py
class UserCart(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, default=None)
state_tax = models.ForeignKey(Tax, on_delete=models.SET_NULL, null=True)
fed_tax = models.ForeignKey(Tax, on_delete=models.SET_NULL, null=True)
This is here necessary, since you have two references from UserCart to the Tax model. This thus means that the relation in reverse (from Tax to UserCart) can not be usercart_set, since then it is not clear which relation we use in reverse.
We thus should at least give a related name to one of the relations (that is different from usercart_set). For example:
from django.contrib.auth import get_user_model
class UserCart(models.Model):
user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE, default=None)
state_tax = models.ForeignKey(
Tax,
related_name='state_usercarts',
on_delete=models.SET_NULL,
null=True
)
fed_tax = models.ForeignKey(
Tax,
related_name='fed_usercarts',
on_delete=models.SET_NULL,
null=True
)
Note: you might want to make use of get_user_model [Django-doc] over a reference to User itself. If you later change your user model, then the ForeignKey will automatically refer to the new user model.

How to access a field with reverse name = '+' in Django?

How do you define the reverse relation from another object to this one with a '+' as it's related name?
class FeaturedContentPage(Page):
featured_page = models.ForeignKey(
'wagtailcore.Page',
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name='+',
)
The idea of a related_name*ending with a '+' is to disable creating a reverse relation, as is documented:
If youd prefer Django not to create a backwards relation, set related_name to '+' or end it with '+'.
You can of course still query in reverse with:
FeaturedContentPage.objects.filter(featured_page=my_page)
But there is thus no relation constructed in reverse, so my_page.featuredcontentpage_setis not accessible.
the related_name argument is used for reverse relation name . if a model has 2 field referencing the same model
featured_page = models.ForeignKey(
'wagtailcore.Page',
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name='+',
)
regular_page = models.ForeignKey(
'wagtailcore.Page',
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name='+',
)
without related_name='+' django will complain because it use wagtailcore.Page model name for reverse relation. as two attribute in object can not have same name by setting related_name='+' to one or both field will ignore creating reverse relation .

Django ForeignKey TemplateSyntaxError and ProgrammingError

This is are my models i want to relate. i want for collection to appear in the form of occurrence.
class Collection(models.Model):
id = models.AutoField(primary_key=True, null=True)
code = models.CharField(max_length=100, null=True, blank=True)
address = models.CharField(max_length=100, null=True, blank=True)
collection_name = models.CharField(max_length=100)
def __unicode__(self):
return self.collection_name
class Meta:
db_table = u'collection'
ordering = ('collection_name',)
class Occurrence(models.Model):
id = models.AutoField(primary_key=True, null=True)
reference = models.IntegerField(null=True, blank=True, editable=False)
collection = models.ForeignKey(Collection, null=True, blank=True, unique=True),
modified = models.DateTimeField(null=True, blank=True, auto_now=True)
class Meta:
db_table = u'occurrence'
Every time i go to check the Occurrence object i get this error
TemplateSyntaxError at /admin/hotiapp/occurrence/
Caught an exception while rendering: column occurrence.collection_id does not exist
LINE 1: ...LECT "occurrence"."id", "occurrence"."reference", "occurrenc..
And every time i try to add a new occurrence object i get this error
ProgrammingError at /admin/hotiapp/occurrence/add/
column occurrence.collection_id does not exist
LINE 1: SELECT (1) AS "a" FROM "occurrence" WHERE "occurrence"."coll...
What am i doing wrong? or how does ForeignKey works?
The problem is that you have not updated your database table definition since adding the ForeignKey. syncdb doesn't do this for you, as the documentation clearly states. You need to update the SQL manually, or use a tool like South.
Are you sure you mean
collection = models.ForeignKey(Collection, null=True, blank=True, unique=True),
Nullable and Unique? This may not be possible in some databases.
Generally, the unique constraint doesn't seem to make much sense here.
Are you trying to force a 1-to-1 relationship? Use the OneToOneField. http://docs.djangoproject.com/en/1.1/ref/models/fields/#django.db.models.OneToOneField