Django application doesn't seem to recognize related name? - django

I have a django app with a User's model that contains a followers field that serves the purpose of containing who follows the user and by using related_name we can get who the User follows. Vice versa type of thing. Printing the User's followers works, but I can't seem to get the followees to work.
views.py
followers = User.objects.get(username='bellfrank2').followers.all()
following = User.objects.get(username='bellfrank2').followees.all()
print(followers)
print(following)
models.py
class User(AbstractUser):
followers = models.ManyToManyField('self', blank=True, related_name="followees")
Error:
AttributeError: 'User' object has no attribute 'followees'

According to documentation all many to many relationships that are recursive are also symmetrical by default.
See here: https://docs.djangoproject.com/en/4.0/ref/models/fields/#django.db.models.ManyToManyField.symmetrical
When Django processes this model, it identifies that it has a ManyToManyField on itself, and as a result, it doesn’t add a person_set attribute to the Person class. Instead, the ManyToManyField is assumed to be symmetrical – that is, if I am your friend, then you are my friend.
So to, make your field actually create the followees attribute you need to set the symmetrical attribute to False.
models.py
class User(AbstractUser):
followers = models.ManyToManyField('self', blank=True, related_name="followees", symmetrical=False)

Related

Filter django query set based on whether a foreign key relationship exists

So I have two models.
class Post(models.Model):
id = models.OidField('object id', unique=True)
class ArchivedFlag(models.Model):
post = models.ForeignKey(post,
on_delete=models.CASCADE,
related_name='archived_flag')
user = models.ForeignKey(User,
on_delete=models.CASCADE,
related_name='archives')
In views.py I have generated a list of all posts by some criteria, 'plist'.
I want to filter the list based on posts that DO NOT have an ArchivedFlag object relationship. Basically the ArchivedFlag model is a tool hide certain posts.
How can I do this? I'm trying to do something along the lines of
plist = plist.exclude(models.ForeignKey.Post exists)
but I'm unsure of the exact syntax.
You can exclude Post objects for which anArchivedFlag exists with:
Post.objects.exclude(archived_flag__isnull=False)
or easier with a simple filter:
Post.objects.filter(archived_flag=None)
Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.

Add a unique "intermediary" model to all my Django ManyToManyField()

Hello Awesome People!
Such a question that I have made a lot of searches for it. I am done building a website two(2) months ago, but today The team decides to track every time an instance has been added to a Model in ManyToManyField() fields.
I was thinking using the through argument to point to the model that will act as an intermediary may work but not at all in my case (70%). Just Because I want to have a unique intermediary model that will record for all ManyToManyField()
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(Person, through='Membership')
class Membership(models.Model):
person = models.ForeignKey(Person, on_delete=models.CASCADE)
group = models.ForeignKey(Group, on_delete=models.CASCADE)
date_joined = models.DateTimeField(auto_now_add=True)
Ah! Something is required. I need to explicitly specify foreign keys to the models that are involved in the many-to-many relationship.
Django ContentType may anticipate for all my models, but it's not working, I wonder why? it also contains ForeignKey (the one required by an intermediary model).
Do I really need to edit all my ManyToManyField fields and create Model as much as ManytoManyField? is there a way to record date_joined without creating an intermediary model for each?
Are you perhaps looking for something like django admin's LogEntry model?
LogEntry contains the ContentType of the model instance that has changed, the id of the instance, the type of change and an abstract change message. With all of that you can retrace changes made to instances.
In django admin, the views take care of adding records to LogEntry via three methods log_change/addition/deletion: click.

Django models: database design for user and follower

In Django model I am making a table 'followers', which has:
user's id. (this is followed by)
user's id (this is follower)
that's simple a user can follow other users.
How should I define the model in Django?
I tried this, but does not work:
user = models.ForeignKey('self')
follower_id = models.ForeignKey('self')
How should this be done?
thanks
The 'self' argument won't work unless you have a model called self.
Assuming that your assignment model is called Following, and you're using the built in User model then you can do:
class Following(models.Model):
target = models.ForeignKey('User', related_name='followers')
follower = models.ForeignKey('User', related_name='targets')
This will likely need some further uniqueness and validation logic.
Note the related_name attribute, see https://docs.djangoproject.com/en/1.10/ref/models/fields/#django.db.models.ForeignKey.related_name. This means that for a given user object you can do user.targets.all() to get users they follow, and user.followers.all() to get users who follow them.
Note also that Django returns target model instances, not IDs, in the ORM. This means that even though the underlying table may be called follower_id, in the python code following.follower will return an actual User object.
Seeing as Following is actually the through table for the many-to-many relationship between Users. I would create a Profile model which extends the Django User model, and then declare the many-to-many relationship (using ManyToManyField).
from django.contrib.auth.models import User
from django.db import models
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
following = models.ManyToManyField(User, related_name='followers')
Use the many to many field.
followers = models.ManyToManyField('self', symmetrical=False)

Django UserProfile slug field

I'm looking to create a url to visit a user profile using a slug. Ie. I want to visit /profile/myname to bring up my user profile. What I am having difficulties with is implementing the slug field for a user model.
Additionally, not sure if this matters or not but I have created a UserProfile model which extends the standard User model as shown below:
from django.contrib.auth.models import User
from autoslug import AutoSlugField
class UserProfile(models.Model):
user = models.ForeignKey(User, related_name='profile_name')
about_me = models.TextField(null=True, blank=True)
slug = AutoSlugField(populate_from='User.username', default='', unique=True)
which gives the error (when trying to migrate):
DETAIL: Key (slug)=() is duplicated.
I believe the urls to be correct but have included it for reference (in an app named profile):
url(r'^(?P<slug>[\w-]+)', views.detail, name='detail')
It means you already have some records in userprofile table with empty/null values in slug field. Because you've marked that field as unique=True it can only have one field with empty value. To avoid this error, delete the records with empty value in slug field, or just assign them a unique slug and you'll be good to go.
And as you can understand from above, having default='' in a field that has unique=True wont work. Unique means unique, even '' as an empty value is considered a unique value and can be used in just one row if you have unique=True. That also means you cannot have any default value in a unique field.

Best Practice for following multiple authentication backends in Django?

I am trying to implement an authentication system for 2 different sets of users in Django. A student(using his username & password), A developer (using his email & password). Currently I have a (common) UserProfile model which will be shared by Student, Developer. Here is my models code:
class UserProfile(models.Model):
user = models.OneToOneField(User)
name = models.CharField(max_length=50, null=True, blank=True)
slug = models.SlugField(max_length=50, db_index=True, unique=True)#this will be used as his unique url identifier
objects = UserProfileManager()
class Meta:
abstract = True
class Student(UserProfile):
''' some student specific fields might go here '''
class Developer(UserProfile):
''' some developer specific fields might go here '''
And in settings.py I gave:
AUTH_PROFILE_MODULE = 'users.UserProfile'
I was getting authentication working with just UserProfile model. But as soon as I introduced Student, Developer the whole thing screwed up. I am getting
UserProfile has no attribute
'DoesNotExist'
(this is from the UserProfileManager exists method) and also
SiteProfileNotAvailable
error. (I am getting these errors even before I started writing email auth backend.). Am I missing anything ? What's the best path to follow to achieve what I wanted.
The problem might be the abstract definition of UserProfile. Things should work when you leave the 'abstract = True' away. But be aware of how this changes your table scheme.