Related
I have a ForeignKey field in my model and in Django admin and Django forms` when I display that field or in Django admin, I get all the field that in that model However, I only want to display selected fields in that dropdown, for example
class Area(models.Model):
area_type_options = (('cc', 'Cost Center'), ('pc', 'Profit Center'),)
name = models.CharField(max_length=100)
area_type = models.CharField(max_length=100, choices=area_type_options)
class Item(models.Model):
name = models.CharField(max_length=150, null=True, unique=True)
profit_center = models.ForeignKey(Area, null=True, blank=True, on_delete=models.CASCADE, related_name='profit_center')
cost_center = models.ForeignKey(Area, null=True, blank=True, on_delete=models.CASCADE, related_name='cost_center')
I get to see all the records in the cost_center and all the records in the profit_center however I only want to see where area_type is cc to cost_center and where area type pc to profit_center
Please Help
You can use ForeignKey.limit_choices_to [Django docs] to do this:
class Item(models.Model):
name = models.CharField(max_length=150, null=True, unique=True)
profit_center = models.ForeignKey(Area, null=True, blank=True, on_delete=models.CASCADE, related_name='profit_center', limit_choices_to={'area_type': 'pc'})
cost_center = models.ForeignKey(Area, null=True, blank=True, on_delete=models.CASCADE, related_name='cost_center', limit_choices_to={'area_type': 'cc')
I am new to both django and python and currently trying to implement a REST api using django-rest-framework. I know there are a lot of alike questions but they are serializing objects using .json, and i am not.
I have 2 models captain and boat as follows:
//models.py
from django.db import models
class Captain(models.Model):
name = models.CharField(max_length=255, blank=False, unique=False)
last_name = models.CharField(max_length=255, blank=False, unique=False)
government_id = models.CharField(max_length=55, blank=False, unique=True)
company_name = models.CharField(max_length=255, blank=False, unique=False)
phone_number = models.CharField(max_length=55, blank=False, unique=False)
tax_id = models.CharField(max_length=55, blank=False, unique=True)
date_created = models.DateTimeField(auto_now_add=True)
date_modified = models.DateTimeField(auto_now=True)
class Boat(models.Model):
captain = models.ForeignKey(Captain, on_delete=models.CASCADE, null=True, blank=True, related_name='boats')
name = models.CharField(max_length=55, blank=False)
journey_type = models.CharField(max_length=55, null=True, blank=True)
category = models.CharField(max_length=55, null=True, blank=True)
passenger_capacity = models.IntegerField()
crew_count = models.IntegerField()
have_ac = models.IntegerField(default=0)
year_built = models.DateField
year_restored = models.DateField(blank=True)
engine = models.CharField(max_length=255, blank=True, null=True)
generator = models.CharField(max_length=255, blank=True, null=True)
width = models.CharField(max_length=255, null=True)
height = models.CharField(max_length=255, null=True)
length = models.CharField(max_length=255, null=True)
wc_count = models.IntegerField(null=True)
master_cabin_count = models.IntegerField(null=True)
standart_cabin_count = models.IntegerField(blank=False, null=False)
date_created = models.DateTimeField(auto_now_add=True)
date_modified = models.DateTimeField(auto_now=True)
As you can see each boat has one captain and one captain can have many boats. So in database there is a captain_id field for Boat table. I have defined two serializers for each model:
//serializers.py
from rest_framework import serializers
from .models import Captain, Boat
class CaptainSerializer(serializers.ModelSerializer):
class Meta:
model = Captain
fields = ('id', 'name', 'last_name', 'government_id', 'company_name', 'phone_number', 'tax_id', 'date_created', 'date_modified','boats')
class BoatSerializer(serializers.ModelSerializer):
captain = serializers.PrimaryKeyRelatedField(many=False, read_only=True)
class Meta:
model = Boat
fields = ('id', 'captain', 'name', 'journey_type', 'category', 'passenger_capacity', 'crew_count', 'have_ac', 'year_built', 'year_restored', 'wc_count', 'standart_cabin_count')
Then i have defined views for each model.
//views.py
from django.shortcuts import render
from rest_framework import generics
from .serializers import CaptainSerializer, BoatSerializer
from .models import Captain, Boat
class CaptainCreateView(generics.ListCreateAPIView):
queryset = Captain.objects.all()
serializer_class = CaptainSerializer
def perform_create(self, serializer):
serializer.save()
class CaptainDetailsView(generics.RetrieveUpdateDestroyAPIView):
lookup_field = 'pk'
serializer_class = CaptainSerializer
queryset = Captain.objects.all()
class BoatCreateView(generics.ListCreateAPIView):
queryset = Boat.objects.all()
serializer_class = BoatSerializer
def perform_create(self, serializer):
serializer.save()
When i go to page localhost:port/captains/ (or /GET/captains from postman) i can have captain models including the boats he has.
But The problem is : when i go to localhost:port/boats (or postman) it gives,
Object of type type is not JSON serializable
Exception Type: TypeError at /boats/
Exception Value: Object of type type is not JSON serializable
Any ideas how can i fix this? Thanks in advance.
I think the year_built field in the Boat model is not well defined (you're assigning the class DateField but not creating an instance of it):
class Boat(models.Model):
year_built = models.DateField # should be models.DateField()
Attached below is the models.py I used for my project,
I've attached the photos of the issue as well.
Issue 1
For some reason, all the contents of the tables are not being displayed.
In the first table, first content goes missing.
In the Second table, First and the second contents go missing
Issue 2
The Inline function doesn't work. I tried going through the documentation and several youtube videos to find out how to handle the situation but it didn't help much.
Issue 3
For the bug table, When I select the project name, How do I ensure that only the people I added to that project table are allowed to be selected?
Issue 4
Is there a way to extract the email ID from the Users page and and when I choose the name of the user in the Project page, the email Id will be automatically filled it?
Same way, In the issues page, when I choose the user, the email Id will be auto entered.
MODELS.py
from django.db import models
# Create your models here.
from django.contrib.auth.models import User
from django.db import models
from django.core.mail import EmailMessage
from django.contrib import admin
# Create your models here.
class Project(models.Model):
STATUS_CHOICE = (
('Project Manager', 'Project Manager'),
('Technician', 'Technician'),
('Tester', 'Tester')
)
STATUS_CHOICE_1 = (
('Work Assigned', 'Work Assigned'),
('Work in Progress', 'Work in Progress'),
('Testing', 'Testing'),
('Completed', 'Completed')
)
Project_Name = models.CharField(max_length=100)
Project_Description = models.CharField(max_length=100)
Admin_Name = models.ForeignKey(User, on_delete=models.CASCADE, related_name='User.Admin_Name_users+')
Admin_Mail_ID = models.EmailField(max_length=50)
Project_Manager_1 = models.ForeignKey(User, on_delete=models.CASCADE, related_name='User.Project_Manager_1_users+')
Project_Manager_1_Mail_ID = models.EmailField(max_length=50)
Project_Manager_2 = models.ForeignKey(User, on_delete=models.CASCADE, related_name='User.Project_Manager_2_users+', blank=True, null=True)
Project_Manager_2_Mail_ID = models.EmailField(max_length=50, blank=True, null=True)
Technician_1 = models.ForeignKey(User, on_delete=models.CASCADE, related_name='User.Technician_1_users+')
Technician_1_Mail_ID = models.EmailField(max_length=50)
Technician_2 = models.ForeignKey(User, on_delete=models.CASCADE, related_name='User.Technician_2_users+', blank=True, null=True)
Technician_2_Mail_ID = models.EmailField(max_length=50, blank=True, null=True)
Technician_3 = models.ForeignKey(User, on_delete=models.CASCADE, related_name='User.Technician_3_users+', blank=True, null=True)
Technician_3_Mail_ID = models.EmailField(max_length=50, blank=True, null=True)
Tester_1 = models.ForeignKey(User, on_delete=models.CASCADE, related_name='User.Tester_1_users+')
Tester_1_Mail_ID = models.EmailField(max_length=50, default='Example#gmail.com')
Additional_User_1 = models.ForeignKey(User, on_delete=models.CASCADE, related_name='User.Ad_1_users+', blank=True, null=True)
Additional_User_1_Type = models.CharField(max_length=18, choices=STATUS_CHOICE, blank=True, null=True)
Additional_User_1_Mail_ID = models.EmailField(max_length=50, blank=True, null=True)
Additional_User_2 = models.ForeignKey(User, on_delete=models.CASCADE, related_name='User.Ad_1_users+', blank=True, null=True)
Additional_User_2_Type = models.CharField(max_length=18, choices=STATUS_CHOICE, blank=True, null=True)
Additional_User_2_Mail_ID = models.EmailField(max_length=50, blank=True, null=True)
Additional_User_3 = models.ForeignKey(User, on_delete=models.CASCADE, related_name='User.Ad_1_users+', blank=True, null=True)
Additional_User_3_Type = models.CharField(max_length=18, choices=STATUS_CHOICE, blank=True, null=True)
Additional_User_3_Mail_ID = models.EmailField(max_length=50, blank=True, null=True)
Status_of_the_project = models.CharField(max_length=18, choices=STATUS_CHOICE_1)
Created = models.DateTimeField(auto_now_add=True, null=True, blank=True)
Finish_Date = models.DateTimeField(null=True, blank=True)
Supporting_Documents = models.FileField(null=True, blank=True)
class FlatPageAdmin(admin.ModelAdmin):
fieldsets = (
(None, {
'fields': ('Project_Name','Project_Description','Admin_Name','Admin_Mail_ID','Project_Manager_1','Project_Manager_1_Mail_ID',
'Technician_1','Technician_1_Mail_ID','Tester_1','Tester_1_Mail_ID','Status_of_the_project','Created','Finish_Date','Supporting_Documents',
)
}),
('Add More Users', {
'classes': ('collapse',),
'fields': ('Project_Manager_2','Project_Manager_2_Mail_ID','Technician_2','Technician_2_Mail_ID',
'Technician_3','Technician_3_Mail_ID','Additional_User_1','Additional_User_1_Type',
'Additional_User_1_Mail_ID','Additional_User_2','Additional_User_2_Type','Additional_User_2_Mail_ID',
'Additional_User_3','Additional_User_3_Type','Additional_User_3_Mail_ID'),
}),
)
def __str__(self):
return self.Project_Name
class Meta:
verbose_name_plural = "List Of Projects"
class Bug(models.Model):
STATUS_CHOICE = (
('Unassigned', 'Unassigned'),
('Assigned', 'Assigned'),
('Testing', 'Testing'),
('Tested', 'tested'),
('Fixed', 'Fixed')
)
STATUS_CHOICE_1 = (
('Bug', 'Bug'),
('Issue', 'Issue'),
('Enhancement', 'Enhancement'),
('Not an issue or bug', 'Not an issue or bug'),
('Fixed', 'Fixed')
)
Project = models.ForeignKey(Project, on_delete=models.CASCADE)
Issue_Title = models.CharField(max_length=50, blank=True, null=True)
Situation_Type = models.CharField(max_length=25, choices=STATUS_CHOICE_1)
Basic_Description = models.CharField(max_length=100)
Detailed_Description = models.TextField(default='The Description, here.')
Status = models.CharField(max_length=18, choices=STATUS_CHOICE)
Assigned_to = models.ForeignKey(User, on_delete=models.CASCADE)
Assigned_to_Mail_ID = models.EmailField(max_length=50, blank=True, null=True)
Admin_Mail_ID = models.EmailField(max_length=50, blank=True, null=True)
Reported_by = models.CharField(max_length=50, blank=True, null=True)
Reporters_Mail_ID = models.EmailField(max_length=50, blank=True, null=True)
Reported_Date = models.DateTimeField(null=True, blank=True)
Created = models.DateTimeField(auto_now_add=True, null=True, blank=True)
Updated = models.DateTimeField(auto_now=True, null=True, blank=True)
Deadline_Date = models.DateTimeField(null=True, blank=True)
Supporting_Documents_By_Reporter = models.FileField(null=True, blank=True)
Project_Managers_Comment = models.TextField(default='The Description, here.')
Supporting_Documents_by_Project_Manager = models.FileField(null=True, blank=True)
Technicians_Comment = models.TextField(default='The Description, here.')
Supporting_Documents_by_Technician = models.FileField(null=True, blank=True)
Testers_Comment = models.TextField(default='The Description, here.')
Supporting_Documents_by_Tester = models.FileField(null=True, blank=True)
def __str__(self):
return '{} ({}) [{}]'.format(self.Project, self.Situation_Type, self.Status, self.Issue_Title)
def save(self, force_insert=False, force_update=False, using=None,
update_fields=None):
if self.id:
user=self.Assigned_to
self.Assigned_to_Mail_ID=user.email
send_mail(self.Admin_Mail_ID, ass=self.Assigned_to_Mail_ID)
super(Bug, self).save()
class Meta:
verbose_name_plural = "Projects Tasks/Issues"
def send_mail(admin,ass):
email=EmailMessage('Changes made to Task','Changes have been made to one of your Task reports and we hereby request you to have a look at it at the earliest.', to=[admin,ass])
email.send()
I've also attached the admin.py file as well.
Admin.py
from django.contrib import admin
from .models import Bug, Project
from django.contrib.admin.models import LogEntry
admin.site.register(LogEntry)
# Register your models here.
class BugDisplay(admin.ModelAdmin):
list_display = ('Project', 'Status', 'Basic_Description', 'Assigned_to', 'Created', 'Updated', 'Issue_Title')
list_filter = ('Status', 'Assigned_to', 'Project')
search_fields = ('Reporters_Mail_ID', 'Reported_by', 'Basic_Description',)
admin.site.register(Bug, BugDisplay)
# Register your models here.
#admin.register(Project)
class ProjectDisplay(admin.ModelAdmin):
list_display = ('Project_Name','Admin_Name', 'Project_Manager_1', 'Status_of_the_project')
list_filter = ('Admin_Name', 'Status_of_the_project')
search_fields = ('Project_Name', 'Project_Description', 'Admin_Name', 'Admin_Mail_ID', 'Project_Manager_1 '
'Project_Manager_1_Mail_ID', 'Project_Manager_2 ', 'Project_Manager_2_Mail_ID',
'Technician_1',
'Technician_1_Mail_ID', 'Technician_2', 'Technician_2_Mail_ID', 'Technician_3',
'Technician_3_Mail_ID', 'Tester_1', 'Tester_1_Mail_ID', 'Additional_User_1', 'Additional_User_1_Type',
'Additional_User_1_Mail_ID', 'Additional_User_2', 'Additional_User_2_Type', 'Additional_User_2_Mail_ID',
'Additional_User_3', 'Additional_User_3_Type', 'Additional_User_3_Mail_ID', 'Status_of_the_project', 'Created',
'Finish_Date', 'Supporting_Documents')
As per your question please provide your admin inline class (referring to issue 2) and please elaborate for issue 1 and provide more details.
Regarding issue 2 you can override appropriate field using this. You can provide your custom queryset(by applying your filter conditions) to the foreign key field.
def formfield_for_foreignkey(self, db_field, request, **kwargs):
if db_field.name == 'your_field_name':
kwargs["queryset"] = your_custom_queryset_based_on_conditions
return super().formfield_for_foreignkey(db_field, request, **kwargs)
For issue 4, you want email Id to be auto filled based on user selection. This can be achieved using custom javascript.
Another way could be that, you do not show email field and while saving the record from project/issue admin you automatically fetch email id from users table and assign it to the object and save it.
You may have a look at this, to customize while saving the object from admin panel.
def save_model(self, request, obj, form, change):
email = your_method_to_find_email_for_user(obj.user_field)
obj.email_field = email
super().save_model(request,obj,form,change)
I am a bit stumped as to how I can add multiple access_token and items_ids in Django Admin. The models and apps involved are as follows. This is my first post so please forgive if it isn't in proper format.
Trans/models.py
class Exchange(models.Model):
created = models.DateTimeField()
owner = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='token', on_delete=models.CASCADE)
access_token = models.CharField(max_length=300, blank=True, default='')
item_id = models.CharField(max_length=300, blank=True, default='')
request_id = models.CharField(max_length=300, blank=True, default='')
class Meta:
ordering = ('item_id',)
I have setup a userprofile section for the admin:
Users/models.py
class UserProfile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, primary_key=True, verbose_name='user', related_name='profile', on_delete=models.CASCADE)
avatar_url = models.CharField(max_length=256, blank=True, null=True)
dob = models.DateField(verbose_name="dob", blank=True, null=True)
public_token = models.CharField(max_length=100, blank=True, null=True, verbose_name='public_token')
access_token = models.CharField(max_length=100, blank=True, null=True, verbose_name='access_token')
item_id = models.CharField(max_length=100, blank=True, null=True, verbose_name='item_ID')
just_signed_up = models.BooleanField(default=True)
def __str__(self):
return force_text(self.user)
class Meta():
db_table = 'user_profile'
users/forms.py
class UserProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
fields = ('user', 'public_token', 'access_token', 'item_id',)
users/admin.py
class UserProfileAdmin(admin.ModelAdmin):
search_fields = ('user', 'dob', 'public_token', 'access_token', 'item_id',)
ordering = ('user',)
list_select_related = ('user',)
admin.site.register(UserProfile, UserProfileAdmin)
class UserProfileAdminInline(admin.TabularInline):
model = UserProfile
I'm really just stumped as I tried making many to many field but couldnt seem to link correctly and or the process broke when testing in a sandbox environment. Any help would be greatly appreciated! In my case I need to record multiple access_tokens and item_ids for each user.
It's a little bit confusing what you are asking...particularly the way that your data model is setup....but I'm going to make a couple of assumptions in my answer (it would be helpful to better understand what you are trying to do at a high level).
I think what you are wanting to do is to be able to configure multiple Exchange objects per user profile...in which case I would set things up this way:
1. The related_name field on the FK to the user profile in the exchange model will be how you access multiple exchanges...so in this case you probably want a pluralized name.
2. To be able to edit multiple in the Django Admin you will need to setup an InlineAdmin object.
3. The CharFields that are actually ON the UserProfile will only ever be single fields...if you want multiple then you need to move them to another related object (like the Exchange model).
4. I don't think what you want here is a ManyToMany as that would imply user's would be sharing these tokens and item ids (or Exchanges?)...but maybe that is what you want...in which case you should change the ForeignKey to UserProfile from the Exchange model to a ManyToManyField. The rest of this post assumes you don't want that.
trans/models.py
from django.db import models
from django.conf import settings
class Exchange(models.Model):
class Meta:
ordering = ('item_id', )
created = models.DateTimeField(auto_now_add=True)
owner = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='exchanges', on_delete=models.CASCADE)
access_token = models.CharField(max_length=300, blank=True)
item_id = models.CharField(max_length=300, blank=True)
request_id = models.CharField(max_length=300, blank=True)
users/models.py
from django.db import models
from django.conf import settings
class UserProfile(models.Model):
class Meta:
db_table = 'user_profile'
user = models.OneToOneField(settings.AUTH_USER_MODEL, primary_key=True, verbose_name='user', related_name='profile', on_delete=models.CASCADE)
avatar_url = models.CharField(max_length=256, blank=True)
dob = models.DateField(verbose_name="dob", blank=True, null=True)
public_token = models.CharField(max_length=100, blank=True, null=True)
access_token = models.CharField(max_length=100, blank=True, null=True)
item_id = models.CharField(max_length=100, blank=True, null=True)
just_signed_up = models.BooleanField(default=True)
def __str__(self):
return force_text(self.user)
users/admin.py
from django.contrib import admin
from trans.models import Exchange
from users.models import UserProfile
class ExchangeAdminInline(admin.TabularInline):
model = Exchange
class UserProfileAdmin(admin.ModelAdmin):
inlines = (ExchangeAdminInline, )
search_fields = ('user', 'dob', 'public_token', 'access_token', 'item_id', )
ordering = ('user', )
list_select_related = ('user', )
admin.site.register(UserProfile, UserProfileAdmin)
There is a lot that you can do to configure the inlines to behave how you want...but that's the basics.
class MemberAdmin(CustomUserAdmin, admin.ModelAdmin):
redirect_model_name = 'memberaccountproxy'
change_form_template = 'loginas/change_form.html'
list_display = ('username', 'email', 'first_name', 'last_name','country', 'gender',
'created_at', 'profile_pic')
search_fields = ('username', 'first_name', 'last_name', 'email',)
add_form = AccountProfileForm
list_filter = (
'gender', 'incomplete', 'email_verified', 'suspended',
'deleted',
)
# profile1 = None
def get_queryset(self, objects):
return Account.objects.filter(usertype=1)
def country(self, obj):
profile1 = Profile.objects.get(account=obj)
if profile1.country:
return profile1.country
return ''
country.admin_order_field = 'country'
What I am trying to achieve is to make my country column on Member list page sortable.(currently its not)
Problem is that I get the 'obj' from method country as an Account object(as defined in the get_queryset()), & later I use that obj to get another object of type Profile (which has a member variable country). But when I try to register the country method to 'admin_order_field', it can only take member variables of obj (of type Account, which doesn't have country variable in it).
Is there a way to sort the country column based on the field from Profile class instead of Account.
class Profile(models.Model):
account = models.OneToOneField(Account)
country = models.ForeignKey('Country', null=True, blank=True, verbose_name='Country Living In', related_name='+')
# name = models.CharField(max_length=40, blank=True)
status = models.ForeignKey('Status', blank=True, null=True, verbose_name='Marital Status', related_name='+')
btype = models.ForeignKey('Btype', blank=True, null=True, verbose_name='Body type', related_name='+')
bheight = models.IntegerField(choices=HEIGHT, blank=True, null=True, verbose_name='Height')
phystatus = models.ForeignKey('EthnicOrigin', blank=True, null=True, verbose_name='Ethnic Origin', related_name='+')
createdby = models.ForeignKey('CreatedBy', blank=True, null=True, verbose_name='Profile Created By',
related_name='+')
...........................
class Account(AbstractBaseUser):
email = models.EmailField(unique=True)
usertype = models.IntegerField(default=1, choices=USER)
username = models.CharField(max_length=40, unique=True)
gender = models.CharField(choices=(('Male', 'Male'), ('Female', 'Female')), max_length=10, blank=True)
phone = models.CharField(max_length=16, blank=True, verbose_name="Mobile No", null=True)
temple = models.ManyToManyField('Account', blank=True, null=True, verbose_name="MatchMaker")
first_name = models.CharField(max_length=40, blank=True, null=True)
last_name = models.CharField(max_length=40, blank=True, null=True)
acc_for = models.ForeignKey('CreatedBy', blank=True, null=True, verbose_name="Profile Created For")
country_code = models.ForeignKey('CountryCode', max_length=40, blank=True, null=True)
............................................
The list_display and admin_order_field option supports double underscore notation to access related models.
Your question isn't clear because you haven't shown your models, but it looks like you can do:
country.admin_order_field = 'profile__country'
However, you can probably replace country with profile__country in your list_display method, and remove your country method entirely.