Django GenericRelation recursive import - python

I'm trying to create a system, for a User to worte a comment on an other User. So I create a models with GenericRelation like this:
App1\models.py:
from django.contrib.auth.models import AbstractUser
from django.contrib.contenttypes.fields import GenericRelation
from app2.models import Social
class User(AbstractUser):
"""
Default User model used for authentification system
"""
relation = GenericRelation(Social) # recently added
App2\models.py:
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from app1.models import User
class Social(models.Model):
content_object = GenericForeignKey('content_type', 'object_id')
object_id = models.PositiveIntegerField()
content_type = models.ForeignKey(ContentType,
on_delete=models.CASCADE)
author= models.ForeignKey(User, # Member who wrote the message
on_delete=models.CASCADE,
related_name='wrote')
message= models.TextField()
Before adding the field relation in User. I don't have any problem but I was remake the work of GenericRelation and I want to simplify my cod.
Then the problem appear when i run the server. I'm in a recursive import loop...
file .\app2\models.py
from app2.models import Social
file .\app1\models.py
from app1.models import User
Would there be a possibility of solving this problem by keeping a GenericRelation on Social and GenericRelation for my User?
Because after I want to add an other GenericRelation(Social) on an other model/

Try to reference User model as string in ForeignKey, like so:
author = models.ForeignKey(
'app1.User',
on_delete=models.CASCADE,
related_name='wrote')
)
And, also, remove from app1.models import User.

Related

Inherit a custom user models fields from parent class to a child class between two different applications

Hello kings and queens!
I'm working on a project and got stuck on a (for me) complicated issue. I have one model (generalpage.models) where all the common info about the users is stored. In a different app (profilesettings), I have an app where all profile page related functions will be coded.
I tried to inherit the model fields from the User class in generalpage.models into profilesettings.models by simply writing UserProfile(User). When I did this, a empty forms was created in the admin panel. So basically, the information that was already stored generalpage.models were not inherited into the profilesettings.models, I created an entire new table in the database.
my questions are:
Is it possible to create an abstract class for a custom user model?
Is there a proper way to handle classes and create a method in profilesettings.models that fills the UserProfile form with the data already stored in database created by the User class?
Can someone please explain how the information can be passed from one application to another without creating a new empty form?
Filestructure:
Admin panel:
generalpage.models:
from random import choices
from secrets import choice
from unittest.util import _MAX_LENGTH
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, User, PermissionsMixin
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
from generalpage.managers import CustomUserManager
from django.conf import settings
from generalpage.managers import CustomUserManager
# Create your models here.
sex_choices = ( ("0", "Man"),
("1", "Kvinna"),
("2", "Trans")
)
class User(AbstractBaseUser, PermissionsMixin):
user = models.CharField(settings.AUTH_USER_MODEL, null=True, max_length=50)
username = models.CharField(_("Användarnamn"), max_length=100, null=True, unique=True)
age = models.IntegerField(_("Ålder"),null=True, blank=False)
email = models.EmailField(_("E-mail"), unique=True, null=False)
country = models.CharField(_("Land"),max_length=50, null=True, blank=True)
county = models.CharField(_("Län"),max_length=50, null=True, blank=True)
city = models.CharField(_("Stad"),max_length=50, null=True, blank=True)
sex = models.CharField(_("Kön"), choices=sex_choices, null=True, blank=False, max_length=50)
profile_picture = models.ImageField(_("Profilbild"),null=True, blank=True, default="avatar.svg", upload_to = "static/images/user_profile_pics/")
is_staff = models.BooleanField(default=False)
is_active = models.BooleanField(default=False)
date_joined = models.DateTimeField(default=timezone.now)
USERNAME_FIELD = 'username' # defines the unique identifier for the User model
REQUIRED_FIELDS = ["email"] # A list of the field names that will be prompted for when creating a user via the createsuperuser management command
objects = CustomUserManager()
def __str__(self):
return self.username
profilesettings.models:
from generalpage.models import User, UserInfo, Room, Message, Topic
from django.db import models
class UserProfile(User):
pass
class Settings(UserInfo):
pass
My models after #viktorblindh suggestion are:
for admin.py:
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from profilesettings.models import UserProfile
from generalpage.models import User
class UserProfileInline(admin.StackedInline):
model = UserProfile
min_num = 1
class UserProfileAdmin(BaseUserAdmin):
inlines = [UserProfileInline, ]
admin.site.register(User, UserProfileAdmin)
# admin.site.register(UserProfile)
# admin.site.register(Settings)
and for profilesettings.models:
from generalpage.models import User, UserInfo, Room, Message, Topic
from django.db import models
from django.conf import settings
class UserProfile(User):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
class Settings(UserInfo):
pass
```
The solution suggested in:
https://stackoverflow.com/questions/42424955/how-to-exchange-data-between-apps-in-django-using-the-database
solved my issue.
Maybe i'm misunderstanding the issue at hand but to me it sounds like you would want to have a OneToOne key on your profilesettings.UserProfile to your generalpage.user. I'm assuming every user have their own unique profilesettings.
from django.conf import settings
class UserProfile(User):
user(models.OneToOneField(
settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
Then after that you can use an inlineformset in your generalpage.admin to get all the information displayed in the same form.
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from profilesettings.models import UserProfile
class UserProfileInline(admin.StackedInline):
model = UserProfile
min_num = 1
class UserProfileAdmin(BaseUserAdmin):
inlines = [UserProfileInline, ]
admin.site.register(User, UserProfileAdmin)

Django: use a Foreignkey relationship for custom user model

I am writing a webapp where I want to have a general Person table to uniquely identify any person interacting with the website, e.g. to be able to comply to GDPR requests.
Some Persons will should also be Users in the authentication sense.
I'd like to use Person.email for the username.
However, I cannot manage to make authentication / admin interface work.
Simplified models:
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin
class Person(models.Model):
name = models.CharField(max_length=255, blank=False)
email = models.EmailField(blank=False, unique=True)
class User(AbstractBaseUser, PermissionsMixin):
person = models.OneToOneField(Person, on_delete=models.PROTECT)
USERNAME_FIELD = ...# what to put here?
I found a very old Django issue that seems related:
https://code.djangoproject.com/ticket/21832
Any idea, how to make this work with a foreign key to hold the basic user information?
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin
Here you go for correct way of achieving this
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True)
USERNAME_FIELD = ['email'] # It's mean you can login with your email
class Person(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
Note: If you use AbstractBaseUser models, then you have to write custom model manager.
To avoid writing custom models manager, you should use AbstractUser
class User(AbstractUser):
pass
# here all the required fields like email, name etc item
You can create Person record for the user when a user records creating using django signal:
https://docs.djangoproject.com/en/3.2/topics/signals/

Class relationship in Django model

My project(Django Rest Framework) is blog app where logged in users can Post some texts and any logged in users can add comment to Posts.
What are the changed I need to make in the Post and Comment class to establish the logic ?
from django.db import models
from django.contrib.auth.models import AbstractUser
from django.conf import settings
class User(AbstractUser):
#User model
class Post(models.Model):
postdata = models.CharField(max_length=100)
owner = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE)
class Comment(models.Model):
body = models.TextField()
author = models.ForeignKey(User, on_delete=models.CASCADE)
Add a ForeignKey pointing to your Post model in the Comments model:
post = models.ForeignKey('Post', on_delete=models.CASCADE, related_name='comments')
As a good practice, keep using settings.AUTH_USER_MODEL instead of User directly

django.core.exceptions.FieldError: Unknown field(s) (email) specified for Profile

I am trying to customize djoser's createuser end point. For that I have installed django custom user following this link https://github.com/jcugat/django-custom-user. Here is my models.py
from django.db import models
from custom_user.models import AbstractBaseUser
class Profile(AbstractBaseUser):
account_address = models.CharField(max_length=30, blank=True)
and serializers.py
from djoser.serializers import UserCreateSerializer as BaseUserRegistrationSerializer
class UserRegistrationSerializer(BaseUserRegistrationSerializer):
class Meta(BaseUserRegistrationSerializer.Meta):
fields = ('url', 'id', 'email', 'first_name', 'account_address', 'password')
and in app.admin.py i have registered it in following way.
from django.contrib import admin
from custom_user.admin import UserAdmin
from .models import Profile
class MyCustomEmailUserAdmin(UserAdmin):
"""
You can customize the interface of your model here.
"""
pass
# Register your models here.
admin.site.register(Profile, UserAdmin)
but when I am trying to makemigrations i am running into following error.
any clue what's wrong here?
From the looks of it, you seem to have the following in your settings:
AUTH_USER_MODEL = "your_app.Profile"
And for your profile model, you are inheriting from AbstractBaseUser which is actually from from django.contrib.auth.models import AbstractBaseUser.
I believe you meant to inherit from AbstractEmailUser. Thus, your "Profile" model would actually need be:
from custom_user.models import AbstractEmailUser
class Profile(AbstractEmailUser):
account_address = models.CharField(max_length=30, blank=True)

how to avoid circular django model import?

I have these models below
# user profile models file
from ad.models import FavoriteAd
class UserProfile(models.Model):
def get_user_favorite_ad(self):
return FavoriteAd.objects.filter(fav_user=self)
# ad models file
from user_profile.models import UserProfile
class FavoriteAd(models.Model):
fav_user = models.ForeignKey(UserProfile, blank=False, on_delete=models.CASCADE)
I have tried using these but it give me the NameError UserProfile not found
# ad models files
class FavoriteAd(models.Model):
fav_user = models.ForeignKey('user_profile.UserProfile', blank=False, on_delete=models.CASCADE)
Also tried these as well still got error that model are not ready
# ad models files
from django.apps import apps
UserProfile = apps.get_model('user_profile', 'UserProfile')
class FavoriteAd(models.Model):
fav_user = models.ForeignKey(UserProfile, blank=False, on_delete=models.CASCADE)
You are using FavoriteAd inside get_user_favorite_ad method of
UserProfile model
Thats the reason you are unable to import it in FavoriteAd and this is causing circular import.
For fetching favorite ads of that user, Use favoritead_set to get related objects
# remove that import as well
# from ad.models import FavoriteAd
class UserProfile(models.Model):
def get_user_favorite_ad(self):
return self.favoritead_set.all()

Categories