I have User model and a user can be of type 1 or 2.
Depending on what type of user is created, I want to associate a profile to the model. If type 1, it will be a Person, and type 2 a Company.
I have tried writing the code in models.py and also following the tutorial : https://simpleisbetterthancomplex.com/tutorial/2016/07/28/how-to-create-django-signals.html
signals/apps/entitiesmodels.py
class CompanyModel(AuditedModel):
name = models.CharField(max_length=64, db_index=True, verbose_name='Name', null=True, blank=True)
class PersonModel(AuditedModel):
name = models.CharField(max_length=64, db_index=True, verbose_name='Name', null=True, blank=True)
class Tester(PersonModel,PersistentModel):
# Link with user
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.PROTECT, blank=True, related_name='%(class)s_user')
class Company(CompanyModel,PersistentModel):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.PROTECT, blank=True, related_name='%(class)s_user')
signals/apps/entities/signals.py
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.conf import settings
from . import models as entities_models
#receiver(post_save, sender=settings.AUTH_USER_MODEL)
def user_create_profile(sender, instance, created, **kwargs):
if created:
if instance.user_type == 1:
entities_models.Tester.objects.create(user=instance)
elif instance.user_type == 2:
entities_models.Company.objects.create(user=instance)
else:
pass
signals/apps/entities/app.py
from django.apps import AppConfig
class EntitiesConfig(AppConfig):
name ='entities'
def ready(self):
import entities.signals
signals/apps/entities/api_v1/views.py
from signals.apps.entities import models
from . import serializers
from signals.libs.views import APIViewSet
class PersonViewSet(APIViewSet):
queryset = models.Person.objects.all()
serializer_class = serializers.PersonSerializer
signals/apps/entities/api_v1/urls.py
from rest_framework.routers import DefaultRouter
from signals.apps.entities.api_v1 import views
# Create a router and register our viewsets with it.
app_name='entities'
router = DefaultRouter()
router.register(r'persons', views.PersonViewSet, base_name="entities-persons")
urlpatterns = router.urls
settings.py
LOCAL_APPS = (
'signals.apps.authentication',
'signals.apps.entities.apps.EntitiesConfig',
)
When running server, the error is:
File "/home/gonzalo/Playground/signals3/signals/signals/apps/entities/api_v1/urls.py", line 2, in <module>
from signals.apps.entities.api_v1 import views
File "/home/gonzalo/Playground/signals3/signals/signals/apps/entities/api_v1/views.py", line 1, in <module>
from signals.apps.entities import models
File "/home/gonzalo/Playground/signals3/signals/signals/apps/entities/models.py", line 47, in <module>
class Person(PersonModel):
File "/home/gonzalo/.virtualenvs/signals-test/lib/python3.6/site-packages/django/db/models/base.py", line 108, in __new__
"INSTALLED_APPS." % (module, name)
untimeError: Model class signals.apps.entities.models.Person doesn't declare an explicit app_label and isn't in an application in INSTALLED_APPS
I have the example code on github if someone wants to check it out : https://github.com/gonzaloamadio/django-signals3
Thank for the answer, when using that way of referring an app on settings, then you should use the import like this:
signals/apps/entities/api_v1/views.py
from signals.apps.entities import models
and in urls.py
from entities.api_v1 import views
Related
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)
My models.py
from django.db import models
# Create your models here.
class Result(models.Model):
Id = models.AutoField(primary_key=True, blank=False)
Name = models.CharField(max_length=100)
# Date = models.DateTimeField(auto_now=False, auto_now_add=False)
# Comments = models.TextField(max_length=256)
File = models.FileField(blank=False)
My views.py
from django.shortcuts import render
from contextmapping.Connection import Connection
from rest_framework.response import Response
from rest_framework.decorators import action
from django.shortcuts import render
from rest_framework import viewsets,status
from rest_framework.authentication import TokenAuthentication
from rest_framework.permissions import IsAuthenticated
from result.models import Result
class ResultViewSet(viewsets.ModelViewSet):
queryset = Result.objects.all()
serializer_class = Result
authentication_classes = (TokenAuthentication,)
permission_classes = (IsAuthenticated,)
#action(detail=True,methods=['GET'])
def resultfill(self,request,pk=None):
response={'message':'its working'}
return Response(response,status=status.HTTP_200_OK)
I have a file named data1.py in a folder, I want to run resultfill function in views.py by url, and want to give a path to this file and that file should be automatically upload to File in models.py . How to achieve it ?
You can use default in your file field and give the path of the file. If you have set up all the media and static file URLS in settings then you can just add 'data1.py' as default.
class Result(models.Model):
Id = models.AutoField(primary_key=True, blank=False)
Name = models.CharField(max_length=100)
# Date = models.DateTimeField(auto_now=False, auto_now_add=False)
# Comments = models.TextField(max_length=256)
File = models.FileField(default='data1.py')
This will link your objects to that file imagining that you have 'media/data1.py' as your file location in case you don't upload your own file from frontend or backend.
I’m trying to create an instance of Listing so I can have user populate in the admin.
I’m new to Django and thought I had it but looks like I’m wrong somewhere.
How do I create an instance of Listing to populate in admin?
Any help i gladly appreciated, thanks.
Code Below:
user_profile/models
from django.db import models
from django.urls import reverse
from django.contrib.auth.models import AbstractUser, UserManager
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.conf import settings
from users.forms import CustomUserCreationForm, CustomUserChangeForm
from users.models import CustomUser
class Listing (models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.PROTECT, null=True)
created = models.DateTimeField(auto_now_add=True, null=True)
updated = models.DateTimeField(auto_now=True)
name = models.CharField(max_length=100)
address = models.CharField(max_length=100)
zip_code = models.CharField(max_length=100)
mobile_number = models.CharField(max_length=100)
cc_number = models.CharField(max_length=100)
cc_expiration = models.CharField(max_length=100)
cc_cvv = models.CharField(max_length=100)
def create_profile(sender, **kwargs):
if kwargs['created']:
user_profile = Listing.objects.create(user=kwargs['instance'])
post_save.connect(create_profile, sender=User)
user_profile/admin.py
from django.contrib import admin
from django.contrib.auth import get_user_model
from django.contrib.auth.admin import UserAdmin
from user_profile.forms import HomeForm
from users.forms import CustomUserCreationForm, CustomUserChangeForm
from user_profile.models import Listing
from users.models import CustomUser
# Register models here.
class UserProfileAdmin(admin.ModelAdmin):
list_display = ['name', 'address', 'zip_code', 'mobile_number', 'created', 'updated', 'user']
list_filter = ['name', 'zip_code', 'created', 'updated', 'user']
admin.site.register(Listing, UserProfileAdmin)
I suspect the problem is that you have a custom user model, but your signal is listening to the post_save event from the built-in User. Since you never create instances of that model, the signal never gets triggered.
Change it to:
post_save.connect(create_profile, sender=CustomUser)
I’m trying to get the username of the current logged in user using OneToOneField to populate in the admin once the user submits a form.
The username should go in the user column of admin.py.
I’ve tried various methods and still no luck. I’m new to this and this is my first Django application I’m building so I’m not sure what I’m missing.
I’m stuck and have no idea what I’m doing so any help is gladly appreciated.
Can someone please help? What am I missing?
Thanks!
Code Below:
user_profile/models
from django.db import models
from django.urls import reverse
from django.contrib.auth.models import AbstractUser, UserManager
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.conf import settings
from users.forms import CustomUserCreationForm, CustomUserChangeForm
from users.models import CustomUser
class Listing (models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
name = models.CharField(max_length=100)
address = models.CharField(max_length=100)
zip_code = models.CharField(max_length=100)
mobile_number = models.CharField(max_length=100)
cc_number = models.CharField(max_length=100)
cc_expiration = models.CharField(max_length=100)
cc_cvv = models.CharField(max_length=100)
def create_profile(sender, **kwargs):
if kwargs['created']:
user_profile = Listing.objects.create(user=kwargs['instance'])
post_save.connect(create_profile, sender=User)
user_profile/admin.py
from django.contrib import admin
from django.contrib.auth import get_user_model
from django.contrib.auth.admin import UserAdmin
from user_profile.forms import HomeForm
from user_profile.models import Listing
# Register models here.
class UserProfileAdmin(admin.ModelAdmin):
list_display = ['name', 'address', 'zip_code', 'mobile_number', 'created', 'updated', 'user']
list_filter = ['name', 'zip_code', 'created', 'updated', 'user']
admin.site.register(Listing, UserProfileAdmin)
#admin.site.unregister(Listing)
master_application/settings.py
AUTH_USER_MODEL = 'users.CustomUser'
AUTH_PROFILE_MODULE = 'users.UserProfile'
users/models.py
from django.contrib.auth.models import AbstractUser, UserManager
from django.contrib.auth.models import User
from django.db import models
from django.urls import reverse
class CustomUserManager(UserManager):
def get_by_natural_key(self, username):
case_insensitive_username_field = '{}__iexact'.format(self.model.USERNAME_FIELD)
return self.get(**{case_insensitive_username_field: username})
class CustomUser(AbstractUser):
objects = CustomUserManager()`
Your signal is broken; kwargs will never have a user key so the profile will never be created. What you actually want to do is to check that the signal is being called on creation (rather than on update), add then create an instance of Listing:
if kwargs['created']:
user_profile = Listing.objects.create(user=kwargs['instance'])
Note, the AUTH_PROFILE_MODULE setting has not been used for years, you should remove it.
Problem
I have 2 models, leads and notes. I want a lead to be able to have 1 or more notes. I have used a generic foreign key because I want to plan for the future and a note could be assigned to say a person or a meeting for example.
Following the instructions for django rest framework and Rest Framework Generic Relations I am trying to import one serializer from the other to make a reverse relation possible.
Error
I can't import the serializers in both files(call one serializer from the other) because I get:
File "/Users/james/Documents/UtilityCRM-Server/crm/leads/urls.py", line 2, in <module>
from leads import views
File "/Users/james/Documents/UtilityCRM-Server/crm/leads/views.py", line 11, in <module>
from leads.serializers import LeadSerializer
File "/Users/james/Documents/UtilityCRM-Server/crm/leads/serializers.py", line 4, in <module>
from notes.serializers import NoteSerializer
File "/Users/james/Documents/UtilityCRM-Server/crm/notes/serializers.py", line 6, in <module>
from leads.serializers import LeadSerializer
ImportError: cannot import name LeadSerializer
Its weird because if I open the django shell and run the following it lets me import them all:
from leads.serializers import LeadSerializer
from notes.serializers import NotesSerializer
from callbacks.serializers import CallbackSerializer
Any help would be greatly appreciated!
Code
This is my installed app section of my settings file:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# 3rd Party Apps
'rest_framework',
'generic_relations',
# My Apps
'leads.apps.LeadsConfig',
'callbacks.apps.CallbacksConfig',
'notes.apps.NotesConfig',
]
notes/models.py
from __future__ import unicode_literals
from django.db import models
from django.utils import timezone
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
class Note(models.Model):
author = models.ForeignKey('auth.User')
title = models.CharField(max_length=100)
text = models.TextField()
created_date = models.DateTimeField(default=timezone.now)
# Relations
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
note_object = GenericForeignKey('content_type', 'object_id')
def __str__(self):
return self.title
leads/models.py
from __future__ import unicode_literals
from django.db import models
from django.contrib.contenttypes.fields import GenericRelation
from django.utils import timezone
from notes.models import Note
from callbacks.models import Callback
GAS = 'G'
ELECTRICITY = 'E'
LEAD_TYPE_CHOICES = (
(GAS, 'Gas'),
(ELECTRICITY, 'Electricity'),
)
# Create your models here.
class Lead(models.Model):
author = models.ForeignKey('auth.User')
type = models.CharField(
max_length=1,
choices=LEAD_TYPE_CHOICES,
default=GAS,
)
business_registration_number = models.IntegerField(max_length=20)
business_name = models.CharField(max_length=50)
mpan = models.IntegerField(max_length=21)
supplier = models.CharField(max_length=45)
contract_length = models.IntegerField(max_length=2)
contract_start_date = models.DateField()
contract_end_date = models.DateField()
address_line_1 = models.CharField(max_length=45)
address_line_2 = models.CharField(max_length=45)
address_line_3 = models.CharField(max_length=45)
address_city = models.CharField(max_length=45)
address_county = models.CharField(max_length=45)
address_postcode = models.CharField(max_length=10)
contact_title = models.CharField(max_length=45)
contact_first_name = models.CharField(max_length=45)
contact_middle_name = models.CharField(max_length=45)
contact_last_name = models.CharField(max_length=45)
contact_telephone = models.IntegerField(max_length=11)
contact_email = models.EmailField(max_length=60)
created_date = models.DateTimeField(default=timezone.now)
# Relations
assigned_to = models.ForeignKey('auth.User', related_name='+')
#from_batch = models.ForeignKey('data_batch.DataBatch', related_name='+')
#callbacks = GenericRelation(Callback)
notes = GenericRelation(Note)
class Meta:
ordering = ('contract_end_date', 'business_name',)
def __str__(self):
return self.business_name
I have 2 serializers:
leads/serializers.py
from rest_framework import serializers
from leads.models import Lead, LEAD_TYPE_CHOICES
from notes.serializers import NoteSerializer
class LeadSerializer(serializers.ModelSerializer):
notes = NoteSerializer(many=True, read_only=True)
class Meta:
model = Lead
fields = (
'id',
'business_name',
'business_registration_number',
'supplier',
'contract_length',
'contract_start_date',
'notes'
)
notes/serializers.py
from generic_relations.relations import GenericRelatedField
from rest_framework import serializers
from notes.models import Note
from leads.models import Lead
from leads.serializers import LeadSerializer
from callbacks.models import Callback
from callbacks.serializers import CallbackSerializer
class NoteSerializer(serializers.ModelSerializer):
"""
A `Note` serializer with a `GenericRelatedField` mapping all possible
models to their respective serializers.
"""
note_object = GenericRelatedField({
Lead: LeadSerializer(),
Callback: CallbackSerializer()
})
class Meta:
model = Note
fields = (
'id',
'author',
'title',
'text',
'created_date',
'note_object',
)
As I have mentioned previously in a comment, I believe this happens due to circular (cyclic) imports in Python.
This happens particularly when you are declaring related fields in models, and some models have not been instanced yet.
In this case, when you execute your program, it tries to import LeadSerializer, that requires importing NoteSerializer, that requires importing LeadSerializer, that requires importing NoteSerializer... see where this is going?
Your stacktrace says it all:
from leads.serializers import LeadSerializer
from notes.serializers import NoteSerializer
from leads.serializers import LeadSerializer
Generating ImportError: cannot import name LeadSerializer
What I have done to solve this was declaring all the serializers in a single file. Therefore, you have two options:
Move LeadSerializer to notes/serializers.py
Move NoteSerializer to leads/serializers.py
It is not the most elegant way to solve this, but it has done its trick.
The section below provides no further explanation on how to solve this problem, but an observation regarding this issue.
Perhaps Django & DRF could futurely provide methods to avoid this, such as declaring the serializers as
note_object = GenericRelatedField({
Lead: 'leads.serializers'.LeadSerializer,
Callback: CallbackSerializer()
})
or
notes = 'notes.serializers'.NoteSerializer(many=True, read_only=True)
Faced with this and made this thing:
notes = serializers.SerializerMethodField()
def get_notes(self, obj):
from leads.serializers import LeadSerializer
return LeadSerializer(<your_queryset>, many=True/False, read_only=True/False).data
There is an idea to tackle this before I have also got this same error here I will explain to you how I resolve this.
Put your apps inside the project directory
project
-project
-appname1
-models.py
-serilizer.py
-appname2
-models.py
-serilizer.py
-settings.py
in settings.py
INSTALLED_APPS = ['project.appname1', 'project.appname2']
then try to import appname1 serializers into appname2
like this
from project.appname1.serializers import( ArtistSerializer, ArtisTokenSerilizer, ProfessionSerilizer, FollowersSerializer,
FollowingSerializer, ChatMessageSerializer, SendMessageSerializer, ConversationMessageSerializer,
ProjectTypeSerializer)