Django Admin tabularInline very slow request - python

I have Location app in my project. There are list of countries, their states and cities.
model.py
class Country(models.Model):
class Meta:
verbose_name = 'Country'
verbose_name_plural = 'Countries'
unique_together = ['name', 'iso2'],
name = models.CharField(
max_length=255,
verbose_name=_('Country name'),
)
iso2 = models.CharField(
max_length=2,
null=True,
blank=True,
verbose_name=_('iso2'),
)
phone_code = models.CharField(
max_length=15,
null=True,
blank=True,
verbose_name=_('Phone code'),
)
def __str__(self):
return self.name
class State(models.Model):
name = models.CharField(
max_length=100,
verbose_name=_('State'),
)
country = models.ForeignKey(
Country,
on_delete=models.SET_NULL,
verbose_name=_('Country'),
related_name='states',
related_query_name='states',
null=True,
)
state_code = models.CharField(
max_length=20,
null=True,
blank=True,
verbose_name=_('State code'),
)
def __str__(self):
return self.name
class City(models.Model):
name = models.CharField(
max_length=70,
verbose_name=_('City name'),
)
state = models.ForeignKey(
State,
on_delete=models.SET_NULL,
null=True,
verbose_name=_('State'),
related_name='cities',
related_query_name='cities',
)
country = models.ForeignKey(
Country,
on_delete=models.SET_NULL,
verbose_name=_('Country'),
related_name='cities',
related_query_name='cities',
null=True,
)
def __str__(self):
return self.name
I'm trying to get list of country cities in Django admin via Tabular inline, but when I click on any country it loads very slow (about 1 minute). How to optimize it?
When I did it in Shell - Country.objects.get(name='USA').cities.all() it returns results less than 10ms
admin.py
from .models import Country, City
class CountryCitiesAdmin(admin.TabularInline):
model = City
class CountryAdmin(admin.ModelAdmin):
inlines = (CountryCitiesAdmin,)
list_display = ('name', 'iso2', 'phone_code')
search_fields = ('name', 'code', 'phone_code',)
admin.site.register(Country, CountryAdmin)

You may have to use the raw_id_fields property. What's happening is that it's pulling all of the possible values to populate the select html element. Setting raw_id_fields = ['country', 'state'] will make it an input that shows the ID of the instance instead.

Related

TypeError: Field 'id' expected a number but got <django.db.models.fields.related_descriptors

I have a simple view for showing all the current users that are conditionally filtered based on the user type that is requesting the data.
models.py
class User(AbstractBaseUser, PermissionsMixin):
class SEX(models.TextChoices):
MALE = "MALE", "Male"
FEMALE = "FEMALE", "Female"
class TYPES(models.TextChoices):
...
type = models.CharField(
_("User Type"), max_length=50, choices=TYPES.choices, default=None, blank=True, null=True)
sex = models.CharField(
_("Sex Type"), max_length=50, choices=SEX.choices, default=None, blank=True, null=True)
email = models.EmailField(
_("Your Email"), max_length=254, unique=True, default=None, blank=True, null=True)
student_id = models.CharField(
_("student id"), unique=True, max_length=10, blank=True, null=True)
firstname = models.CharField(max_length=250, blank=False, null=True)
middlename = models.CharField(max_length=250, blank=True, null=True)
lastname = models.CharField(max_length=250, blank=False, null=True)
# grade = models.ForeignKey(Grade, verbose_name=_(
# "grade"), on_delete=models.CASCADE, blank=True, null=True)
room = models.ForeignKey(Class, verbose_name=_(
"class"), on_delete=models.CASCADE, blank=True, null=True)
phone = models.CharField(
_("phone number"), max_length=13, blank=True, null=True)
age = IntegerRangeField(min_value=1, max_value=99,
default=25, blank=True, null=True)
owns = models.ManyToManyField(School, verbose_name=_(
"School_owner"), related_name='Schoolowner', blank=True)
workes = models.ForeignKey(School, verbose_name=_(
"School_workes"), related_name='Schoolworkes', on_delete=models.SET_NULL, blank=True, null=True)
learns = models.ForeignKey(School, verbose_name=_(
"School_learns"), related_name='Schoollearns', on_delete=models.SET_NULL, blank=True, null=True)
image = models.ImageField(
_("photo"), upload_to='user/pp', max_length=None, blank=False, null=True)
joined_date = models.DateTimeField(
_("created at"), auto_now=False, auto_now_add=True)
is_active = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
last_login = models.DateTimeField(
_("last login"), auto_now=True, auto_now_add=False)
serializers.py
class MyAccountSerializer(serializers.ModelSerializer):
image = serializers.ImageField()
class Meta:
model = User
fields = ['id', 'sex', 'type', 'phone', 'image', 'email', 'student_id', 'firstname', 'middlename', 'lastname',
'image', 'joined_date', 'is_active', 'is_superuser', 'is_staff', 'last_login']
views.py
class TeacherList(generics.ListAPIView):
permission_classes = [IsAuthenticated, ]
serializer_class = ListUsersSerializer
queryset = User.objects.filter(type=User.TYPES.TEACHER)
A simple filter like this works without any errors but since I need to filter the response based on the requesting user
this is what I want to use
class TeacherList(generics.ListAPIView):
permission_classes = [IsAuthenticated, ]
serializer_class = ListUsersSerializer
# queryset = User.objects.filter(type=User.TYPES.TEACHER)
def get_queryset(self):
request = self.request.user
if request.type == User.TYPES.OWNER:
queryset = User.objects.filter(
type=User.TYPES.TEACHER, workes=request.owns)
elif request.type in [User.TYPES.STAFF, User.TYPES.DIRECTOR, User.TYPES.VICE_DIR]:
queryset = User.objects.filter(
type=User.TYPES.TEACHER, workes=request.workes)
return queryset
however this shows me an error that goes like this:
Field 'id' expected a number but got <django.db.models.fields.related_descriptors.create_forward_many_to_many_manager.<locals>.ManyRelatedManager object at 0x0000019D64AE7D60>.
I suspect it has something to do with a many-to-many field of which I have one named owns which is what I'm using to filter in 1 of the conditions but don't know why it throws error
I think instead of
queryset = User.objects.filter(
type=User.TYPES.TEACHER, workes=request.owns)
You should try something like:
queryset = User.objects.filter(
type=User.TYPES.TEACHER, workes__in=request.owns.all())
or
queryset = User.objects.filter(
type=User.TYPES.TEACHER, workes__in=request.owns.values_list("id", flat=True))
It should match all Users that have all ids from request.owns ids.

Update foreign key of one model based on another model

I have a student model:
class Student(User):
religion = models.ForeignKey(
Religion, on_delete=models.SET_NULL, null=True)
caste = models.ForeignKey(Caste, on_delete=models.SET_NULL, null=True)
date_of_birth = models.DateField(default=timezone.now)
parent_name = models.CharField(max_length=255, default=None)
address = models.CharField(max_length=255, default=None)
phone_number1 = models.CharField(
"Phone Number 1", max_length=10)
phone_number2 = models.CharField(
"Phone Number 2 (optional)", max_length=10, blank=True)
classes = models.ForeignKey(
Class, on_delete=models.SET_NULL, default=None, null=True, blank=True)
def __str__(self):
return self.first_name+" "+self.last_name
# Control model features
class Meta:
verbose_name = 'Student'
verbose_name_plural = 'Students'
And an admission model:
class Admission(models.Model):
admission_date = models.DateField()
classes = models.ForeignKey(
Class, on_delete=models.SET_NULL, null=True)
student = models.ForeignKey(
Student, on_delete=models.SET_NULL, null=True)
Also a class model that takes in all the information of the class the student is in:
class Class(models.Model):
class_name = models.CharField(
max_length=10,
default=None
)
division_name = models.CharField(
max_length=10,
default=None
)
class_teacher = models.ForeignKey(
Teacher, on_delete=models.SET_NULL, default=None, null=True, blank=True)
institute = models.ForeignKey(
Institute, on_delete=models.SET_NULL, default=None, null=True, blank=True)
def __str__(self):
return self.class_name+" "+self.division_name+" "+self.institute.name
# Control model features
class Meta:
verbose_name = 'Class'
verbose_name_plural = 'Classes'
I want to achieve the following: change student info based on the admissions model. When I update the Admission info, it should take the class and update the class in the student model based on the class provided in the admission model. How can this be achieved?
maybe you can try to use signal?
from django.dispatch import receiver
from django.db.models.signals import post_save
#receiver(post_save, sender= Admission) # it works after saving (created or updated)
def update_student_info(sender, instance, **kwargs):
# change student info based on the admissions model
admission_class = instance.classes
admission_student = instance.student
admission_student.classes = admission_class
admission_student.save()

Django search_field

How to solve this error? cause
whenever I search the student user I received an error,
error
admin.py
#admin.register(StudentsEnrollmentRecord)
class StudentsEnrollmentRecordAdmin(admin.ModelAdmin):
#inlines = [InLineSubject]
list_display = ('lrn', 'Student_Users', 'Education_Levels', 'Courses', 'Section', 'Payment_Type', 'Discount_Type' ,'School_Year')
#list_select_related = ('Student_Users')
ordering = ('Education_Levels','Student_Users__lrn')
list_filter = ('Student_Users','Education_Levels','Section','Payment_Type')
search_fields = ('Student_Users',)
def lrn(self, obj):
return obj.Student_Users.lrn
my models.py
class StudentsEnrollmentRecord(models.Model):
Student_Users = models.ForeignKey(StudentProfile, related_name='students', on_delete=models.CASCADE,null=True)
School_Year = models.ForeignKey(SchoolYear, related_name='+', on_delete=models.CASCADE, null=True, blank=True)
Courses = models.ForeignKey(Course, related_name='+', on_delete=models.CASCADE, null=True, blank=True)
Section = models.ForeignKey(Section, related_name='+', on_delete=models.CASCADE, null=True,blank=True)
Payment_Type = models.ForeignKey(PaymentType, related_name='+', on_delete=models.CASCADE, null=True)
Discount_Type = models.ForeignKey(Discount, related_name='+', on_delete=models.CASCADE, null=True,blank=True)
Education_Levels = models.ForeignKey(EducationLevel, related_name='+', on_delete=models.CASCADE,blank=True,null=True)
UPDATE models
class StudentProfile(models.Model):
lrn = models.CharField(max_length=500,null=True)
Firstname = models.CharField(max_length=500,null=True,blank=True)
Middle_Initial = models.CharField(max_length=500,null=True,blank=True)
Lastname = models.CharField(max_length=500,null=True,blank=True)
Education_Levels= models.ForeignKey(EducationLevel, on_delete=models.CASCADE,blank=True,null=True)
You need to provide a specific field from StudentProfile - currently your search field is
search_fields = ('Student_Users',)
which means only the model itself. You didn't post a schema of your StudentProfile, but for example if it contains a Lastname field, you should use it like this:
search_fields = ('Student_Users__Lastname',)
To include multiple fields you can do
search_fields = ('Student_Users__Lastname', 'Student_Users__Firstname',)
You could also do
search_fields = ('=Student_Users__Lastname',)
to match the last name "exactly", previous example checks whether the field contains the query string

nested serialization dont now create a forignkey it requires a new Object instead of 'id'

here is my model, serializer and output but when i want to create a new page it ask me to add a whole new user as its just a foreign-key it need to be a number like 1 (user id) and same in the case of categories how can i solve it.... help me please
serializers.py
class TeamMembersSerializer(serializers.ModelSerializer):
class Meta:
model = TeamMembers
fields = [
'user',
'page',
]
depth = 1
class SocialAccountsSerializer(serializers.ModelSerializer):
social = SocialCatSerializer()
class Meta:
model = SocialAccounts
fields = [
'page',
'social',
'link'
]
depth = 1
class PageImageSerializer(serializers.ModelSerializer):
class Meta:
model = PageImages
fields = [
'page',
'image',
]
depth = 1
class PageSerializer(serializers.ModelSerializer):
owner = UserSerializer()
catagory = BusinessCatSerializers()
business_type = BusinessTypeSerializer()
TeamMembers = TeamMembersSerializer(read_only=True)
social_accounts = SocialAccountsSerializer(read_only=True)
images = PageImageSerializer(read_only=True)
class Meta:
model =Page
fields = [
'id',
'owner',
'catagory',
'name',
'username',
'images',
'start_date',
'business_type',
'contect_number',
'email_address',
'website',
'TeamMembers',
'social_accounts',
'about',
'impression',
'Awards',
'Product',
'privacy_policy',
'is_active',
]
Models.py
class Page(models.Model):
owner = models.ForeignKey(User, on_delete=models.CASCADE)
catagory = models.ForeignKey(BusinessCatagories, on_delete=models.CASCADE, null=True, blank=True, default=None)
name = models.CharField(max_length=254, unique=True ,default=None, blank=True)
username = models.CharField(max_length=254, unique=True, blank=True)
start_date = models.DateTimeField(auto_now_add=True)
business_type = models.ForeignKey(BusinessType, on_delete=models.CASCADE, null=True, blank=True, default=None)
contect_number = models.CharField(max_length=254, default=None, blank=True)
email_address = models.EmailField(default=None, blank=True)
website = models.URLField(default=None, blank=True)
about = models.TextField(default=None, blank=True)
impression = models.TextField(default=None, blank=True)
Awards = models.CharField(max_length=254, default=None, blank=True)
Product = models.CharField(max_length=254, default=None, blank=True)
privacy_policy = models.URLField(default=None, blank=True)
is_active = models.BooleanField(default=True)
def __str__(self):
return self.name
class TeamMembers(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, default=None, blank=True)
page = models.ForeignKey(Page, on_delete=models.CASCADE, default=None, blank=True)
def __str__(self):
return self.user.name
class SocialAccounts(models.Model):
page = models.ForeignKey(Page, on_delete=models.CASCADE, default=None, blank=True)
social = models.ForeignKey(SocialCats, on_delete=models.CASCADE, default=None, blank=True)
link = models.URLField(default=None, blank=True)
def __str__(self):
return self.link
class PageImages(models.Model):
page = models.ForeignKey(Page, on_delete=models.CASCADE, default=None, blank=True)
image = models.ImageField(default=None, blank=True, upload_to=settings.MEDIA_ROOT)
def __str__(self):
return self.page.name
output is this but i need images field TeamMember field in it but its not appearing plus it want me to add a new user instead of asking for Foreignkey "id"
What you want is to use Primary key related field. It helps you to represent the target of the relationship using its primary key.
It should look somewhat like this.
Note: Mind the typo for any name
class PageSerializer(serializers.ModelSerializer):
owner = serializers.PrimaryKeyRelatedField(queryset = User.objects.all())
catagory = serializers.PrimaryKeyRelatedField(queryset = BuisnessCat.objects.all())
business_type = BusinessTypeSerializer()
TeamMembers = TeamMembersSerializer(read_only=True)
social_accounts = SocialAccountsSerializer(read_only=True)
images = PageImageSerializer(read_only=True)
You can read more about PrimaryKeyRelatedField here.
Now whenever creating any Page, all you need to supply are primary key for owner and category.
You are looking for Writable Nested Serializer.
In short you have to override create() method of PageSerializer
class PageSerializer(serializers.ModelSerializer):
....
....
your code
def create(self, validated_data):
# pop data of every related fields like "owner", "cateagory" etc from validated_data
owner = validated_data.pop("owner")
owner = User.objects.create(**owner)
category = validated_data.pop("category")
# create or retrieve category instance ,as above
...
...
...
# finally
return Page.objects.create(**validated_data,owner=owner,category=category, and other related instances)

Make a form from models using ModelForm, Models have many Foreignkeys( one class is the foreign key for the other.)

I wanted to make a form which should be showing all the fields defined in models, wether the fields include a foreign key to some other class in the models. I am using ModelForm to generate forms.
My models look like
class Employee(Person):
nickname = models.CharField(_('nickname'), max_length=25, null=True,
blank=True)
blood_type = models.CharField(_('blood group'), max_length=3, null=True,
blank=True, choices=BLOOD_TYPE_CHOICES)
marital_status = models.CharField(_('marital status'), max_length=1,
null=True, blank=True, choices=MARITAL_STATUS_CHOICES)
nationality = CountryField(_('nationality'), default='IN', null=True,
blank=True)
about = models.TextField(_('about'), blank=True, null=True)
dependent = models.ManyToManyField(Dependent,
through='DependentRelationship')
pan_card_number = models.CharField(_('PAN card number'), max_length=50,
blank=True, null=True)
policy_number = models.CharField(_('policy number'), max_length=50,
null=True, blank=True)
# code specific details
user = models.OneToOneField(User, blank=True, null=True,
verbose_name=_('user'))
date_added = models.DateTimeField(_('date added'), auto_now_add=True)
date_modified = models.DateTimeField(_('last modified'), auto_now=True)
#models.permalink
def get_absolute_url(self):
return ('contacts_employee_detail', [str(self.id)])
class Person(models.Model):
"""Person model"""
title = models.CharField(_('title'), max_length=20, null=True, blank=True)
first_name = models.CharField(_('first name'), max_length=100)
middle_name = models.CharField(_('middle name'), max_length=100, null=True,
blank=True)
last_name = models.CharField(_('last name'), max_length=100, null=True,
blank=True)
suffix = models.CharField(_('suffix'), max_length=20, null=True,
blank=True)
slug = models.SlugField(_('slug'), max_length=50, unique=True)
phone_number = generic.GenericRelation('PhoneNumber')
email_address = generic.GenericRelation('EmailAddress')
address = generic.GenericRelation('Address')
date_of_birth = models.DateField(_('date of birth'), null=True, blank=True)
gender = models.CharField(_('gender'), max_length=1, null=True,
blank=True, choices=GENDER_CHOICES)
class Address(models.Model):
"""Street Address model"""
TYPE_CHOICES = (
('c', _('correspondence address')),
('p', _('present address')),
('m', _('permanent address')),
)
address_type = models.CharField(_('address type'), max_length=1,
choices=TYPE_CHOICES)
content_type = models.ForeignKey(ContentType,
limit_choices_to={'app_label': 'contacts'})
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey()
street = models.TextField(_('street'), blank=True, null=True)
city = models.CharField(_('city'), max_length=200, blank=True, null=True)
province = models.CharField(_('State/UT'), max_length=200, blank=True,
null=True)
post_code = models.CharField(_('postal code'), max_length=15, blank=True,
null=True)
country = CountryField(_('country'), default='IN')
date_added = models.DateTimeField(_('date added'), auto_now_add=True)
date_modified = models.DateTimeField(_('date modified'), auto_now=True)
So please if anyone could help me out, or suggest me some useful links from where i can get some help. Thank You!!!
Here is the documentation...
Basic usage is:
class EmployeeForm(ModelForm):
class Meta:
model = Employee
fields = ('somefield','otherfield')
etc...
fields is a optional argument, used for defining witch fields will be presented on the form... You can also override some fields using the following
class EmployeeForm(ModelForm):
otherfield = forms.CharField(...)
class Meta:
model = Employee
fields = ('somefield','otherfield')
That means, Your form is created from Employee model, "somefield" and "otherfield" will be added as form fields, and somefield will be populated directly from your model, but otherfield will be defined as if you override it in the form class...
EDIT: Overriding is used for small changes, so ,it is not right to change the data type of the field... As far as you gave the field same name, there is no problem, it will match the related model field using the name of the form field... So:
class SomeModel(Model):
somefield = CharField()
class SomeForm(ModelForm):
somefield = Charfield(Widget=...)
class Meta:
model = SomeModel
Since field names are equivalent, there is no problem...
Basic reason for overriding is, you may wish to use a widget to change the appearance of the form field(making a TextField looks like a single line Charfield) or pass some attributes (like defining cols and rows of a text field, or addng a simlpe datepicker to a datetime field. Or you may wish to use choices parameter to populate a field with value-label pairs...
You must aviod any kind of data-based changes, if you do, you might get a database level error.

Categories

Resources