access to another model fields with foreign key in django admin - django

I have a contact us class in django model,that using "user_id" foreign key,in admin.py file,i want using userprofile data with user_id key,such as "name" filed,in userprofile model "user_id" is foreign_key too,how can do it?
in models.py :
class Ticket(models.Model):
user_id = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, editable=False, verbose_name="user")
replier_id = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, related_name="replier")
guest_name = models.CharField(max_length=50, blank=True, null=True, editable=False)
guest_email = models.CharField(max_length=255, blank=True, null=True, editable=False)
user_phone = models.CharField(max_length=13, blank=True, null=True, editable=False)
subject = models.CharField(max_length=255, blank=True, null=True, editable=False)
message = models.TextField(editable=False)
reply = models.TextField(blank=True, null=True)
date = models.DateTimeField(auto_now=True, editable=False)
reply_date = models.DateTimeField(blank=True, null=True)
user_ip = models.GenericIPAddressField(editable=False)
in admin.py
class ContactUsAdmin(admin.ModelAdmin):
actions = None
fields = ('user_name', 'user_email', 'subject', 'date', 'message', 'user_phone', 'reply')
list_display = ('user_name', 'user_email', 'subject', 'date', 'is_replied')
list_filter = ('date',)
search_fields = ['user_id__first_name', 'user_id__email', 'guest_name', 'guest_email', 'subject', 'message']
readonly_fields = ('user_name', 'user_email', 'subject', 'date', 'message', 'user_phone', 'reply_date')
i want show name from UserProfile class in admin.py fields

By the question title of your query. I am giving an incentive how to do that in django:
class Album(models.Model):
AlbumName = models.CharField(max_length=250)
AlbumSinger = models.CharField(max_length=250)
AlbumGenre = models.CharField(max_length=250)
AlbumImage = models.FileField(null=True)
SingerImage = models.FileField(null=True)
class Musics(models.Model):
album = models.ForeignKey(Album, related_name='music')
MusicName = models.CharField(max_length=250)
MusicLength = models.CharField(max_length=250)
MusicFile = models.FileField(null=True)
Using foreignkey album in Musics. you can access to all the music according to their album. And to access them in admin, just import class name and do the following:
admin.site.register(Album)
admin.site.register(Musics)
I hope it will clear your confusion.

finally i resolve it,when in userprofile model,user_id has "profile" related_name,in every where,with user_id foreign key we have all related field from every model that user_id is foreign key in it
you can see those with using dir("you user_id instance").
so,with user_id.profile.name i get the profile name of user,without any importing or change!

Related

Serializing specific fields from another model

I was trying to serialize policy_length, coverage_amount from Policy model and use it in a serializer that was using Insuree model.
I'm using Policy and Insuree models:
Policy model
class Policy(TimeStampedModel):
policy_length = models.FloatField(max_length=2, blank=True, null=True)
coverage_amount = models.FloatField(max_length=256, blank=True, null=True)
Insuree model
class Insuree(TimeStampedModel):
user = models.OneToOneField(
'User', related_name='insuree', null=False, on_delete=models.CASCADE,
primary_key=True)
coverage_amount = models.ForeignKey(Policy, on_delete=models.CASCADE, max_length=256, blank=True, null=True)
policy_length = models.ForeignKey(Policy, on_delete=models.CASCADE, max_length=2, blank=True, null=True)
class PolicySelectionSerializer(serializers.ModelSerializer):
class Meta:
model = Insuree
fields = ('age', 'gender', 'disposable_income') #Current fields
fields = ('age','gender',disposable_income', 'policy_length', 'coverage_amount') #The field I need and want to do
You may use Nested Serializer.
PolicySerializer(ModelSerializer)
class Meta:
model = Policy
fields = ( 'policy_length', 'coverage_amount')
InsureeSerializer(ModelSerializer)
class Meta:
policy = PolicySerializer(many = True)
model = Insuree
fields = ('age', 'gender', 'disposable_income', 'policy',)

Django admin page autocomplete on reverse ForeignKey

Disclamer:
This is an edit question because I got some answers until now.
I would like to create an autocomplete field in InlineModelAdmin, with similar behavior as autocomplete_fields. I know, Django natively supports this only on ForeignKey, but I need it on the reverse side.
Is there a way - or a library that could do this?
I look into :
https://django-autocomplete-light.readthedocs.io/en/master/tutorial.html
https://django-grappelli.readthedocs.io/en/latest/customization.html
https://django-admin-autocomplete-all.readthedocs.io/en/latest/readme.html
But I didn't found this functionality...
Past question code:
I have models like this:
Models
class Customer(models.Model):
customer_ref = models.CharField(unique=True, max_length=50)
name = models.CharField(null=False, max_length=80)
country = models.CharField(null=True, max_length=50)
class Assortment(models.Model):
name = models.CharField(null=False, max_length=50)
customers = models.ManyToManyField(Customer, related_name='assortments', blank=True)
products = models.ManyToManyField(Product, related_name='assortments', blank=True)
class Subsidiary(models.Model):
subsidiary_ref = models.CharField(unique=True, max_length=50)
name = models.CharField(null=False, max_length=80)
address = models.TextField(null=True)
city = models.CharField(null=True, max_length=50)
coordinates_x = models.DecimalField(null=True, decimal_places=2, max_digits=6)
coordinates_y = models.DecimalField(null=True, decimal_places=2, max_digits=6)
phone_number = models.CharField(null=True, max_length=50)
frequency = models.ForeignKey(Frequency, on_delete=models.SET_NULL, null=True)
channel = models.CharField(null=True, blank=True, max_length=50)
subchannel = models.CharField(null=True, blank=True, max_length=50)
user = models.ForeignKey(User, related_name='subsidiaries', on_delete=models.SET_NULL, null=True)
day_planned = models.BooleanField(default=False)
customer = models.ForeignKey(Customer, on_delete=models.CASCADE, related_name='subsidiaries')
class Asset(models.Model):
identification = models.CharField(unique=True, max_length=50)
serial = models.CharField(max_length=50)
name = models.CharField(null=True, max_length=50)
subsidiary = models.ForeignKey(Subsidiary, related_name='assets', null=True, blank=True, on_delete=models.DO_NOTHING)
Admin
#admin.register(Customer)
class CustomerAdmin(admin.ModelAdmin):
list_display = ['customer_ref', 'name', 'country']
list_filter = ['country']
autocomplete_fields = ['assortments']
#admin.register(Subsidiary)
class SubsidiaryAdmin(admin.ModelAdmin):
exclude = ['day_planned']
list_display = ['subsidiary_ref', 'customer', 'name', 'address', 'phone_number', 'frequency', 'user']
list_editable = ['frequency', 'user']
list_filter = ['frequency', 'user']
search_fields = ['subsidiary_ref', 'customer__name', 'name']
autocomplete_fields = ['assets']
CustomerAdmin is 'working' without error but field 'assortments' is not visible.
SubsidiaryAdmin throws error :
<class 'mobileapp.admin.SubsidiaryAdmin'>: (admin.E038) The value of 'autocomplete_fields[0]' must be a foreign key or a many-to-many field.
witch is weird because I don't see any difference from the first example.
How to fix this?
assortments is not visible in the list page as you have set list_display to
list_display = ['customer_ref', 'name', 'country']
Since assortments is a many-to-many relationship, you have to write a custom ModelAdmin to display them.
As mentioned in the django docs, autocomplete_fields works only for FK & M2M fields of that model. In the AssetAdmin, you can set autocomplete for Subsidiary field.
#admin.register(Asset)
class AssetAdmin(admin.ModelAdmin):
autocomplete_fields = ['subsidiary']

How to allow blank field on OneToOne serializer field for Django REST Framework API?

When POSTing to my API endpoint I get a field is required error on a OneToOne field, but I create the OneToOne Field in the save() method of the model I'm POSTing.
I've tried setting default=None, null=True, and blank=True
Device Model
class Device(models.Model):
name = models.CharField(max_length=50)
created = models.DateTimeField(auto_now_add=True, editable=False)
last_updated = models.DateTimeField(auto_now=True, editable=False)
brand = models.TextField(max_length=50)
year_purchased = models.IntegerField()
serial_number = models.TextField(max_length=100)
info = models.TextField(max_length=100)
qrcode = models.ImageField(upload_to='', blank=True, null=True)
def save(self, **kwargs):
super(Device, self).save(**kwargs)
if not self.qrcode:
self.generate_qrcode()
if not self.checkouts.exists():
checkout = Checkout(item=self)
checkout.save()
Checkout Model
class Checkout(models.Model):
status_choices = (...)
# Fields
slug = extension_fields.AutoSlugField(populate_from='item', blank=True)
created = models.DateTimeField(auto_now_add=True, editable=False)
last_updated = models.DateTimeField(auto_now=True, editable=False)
due_back = models.DateField(null=True, blank=True)
checked_out = models.DateTimeField(blank=True, null=True)
status = models.CharField(max_length=2, choices=status_choices, default=in_stock)
# Relationship Fields
user = models.OneToOneField(
DeviceUser,
on_delete=models.CASCADE,
related_name="checkouts",
blank=True,
null=True,
default=None,
)
item = models.OneToOneField(
Device,
on_delete=models.CASCADE,
related_name="checkouts",
primary_key=True,
blank=True,
default=None,
)
Device Serializer
class DeviceSerializer(serializers.ModelSerializer):
class Meta:
model = models.Device
fields = (
'pk',
'name',
'created',
'last_updated',
'brand',
'year_purchased',
'serial_number',
'info',
'checkouts',
)
When POSTing http POST http://localhost:8000/main/api/device/ brand=test2 info=123213123 name=test2 serial_number=12321321 year_purchased=12 'Authorization: Token .....'
I expect to get a confirmation that a device was created, instead I get
"checkouts": [ "This field is required." ]
Specify checkouts field to your DeviceSerializer serializer as,
checkouts = serializers.DateTimeField(default=None, source='checkouts.checked_out', read_only=True)
# code sample
class DeviceSerializer(serializers.ModelSerializer):
checkouts = serializers.DateTimeField(default=None, source='checkouts.checked_out', read_only=True)
class Meta:
model = models.Device
fields = (
'pk',
'name',
'created',
'last_updated',
'brand',
'year_purchased',
'serial_number',
'info',
'checkouts',
)

Django rest nested serializer not displaying fields

I have a model Workflow and WorkflowLevel. Each workflow has many WOrkflow levels .Im trying to use nested serializer :
class WorkflowLevelSerializer
(serializers.ModelSerializer):
class Meta:
model = WorkflowLevel
fields = '__all__'
class
WorkflowSerializer
(serializers.ModelSerializer):
levels = WorkflowLevelSerializer(many=True)
class Meta:
model = Workflow
fields = ('id', 'name', 'description',
'tenant', 'levels')
models.py:
class Workflow(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
name = models.CharField(max_length=32, default=None, null=True)
description = models.CharField(max_length=100, default=None, null=True)
tenant = models.ForeignKey(Tenant, on_delete=models.CASCADE, default=None,
null=False)
class Meta:
unique_together = ('name', 'tenant',)
class WorkflowLevel(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
workflow = models.ForeignKey(Workflow, on_delete=models.CASCADE,
default=None, null=False)
level = models.IntegerField(default=None, null=False)
operation = models.CharField(max_length=32, default=None, null=False)
class Meta:
unique_together = ('workflow', 'level',)
The levels field is not displaying in the workflow listAPI view .
Getting error:
Got AttributeError when attempting to get a value
for field `levels` on serializer
`WorkflowSerializer`.
The serializer field might be named incorrectly
and not match any attribute or key on the
`Workflow` instance.
Original exception text was: 'Workflow' object
has no attribute 'levels'.
You can define related_name in the Model like this:
workflow = models.ForeignKey(Workflow, on_delete=models.CASCADE, related_name="levels", default=None, null=False)
I am using related_name='levels', so that in Serializer, it will use that reverse relationship name to fetch WorkflowLevel data from db.

Django Rest Framework foreign key multiple data

I have a model call Schedule, it is like reminder function. I also have another model called Family which user can add family member in it.
So in schedule, i create a foreign key to link family inside so that it will include the family member id in it.
Here is the how my API for schedule looks like: https://imgur.com/a/bwYDn
And here are my questions.
As you can see based on the image in above link, the userId is a drop down. is it possible to make it userId = self.request.user.userId ?
In the schedule api, the familyId is a drop down that consist of all family member(basically, even other people who added their family), is there a way to filter it so that it will only shows a dropdown of only the current user familyId appear ?
When creating a schedule, user can only insert 1 familyId. Is there a way to choose more than 1 familyId ? For eg, user can insert familyId 1 and 2
Here is my code
models.py
class MyUser(AbstractUser):
userId = models.AutoField(primary_key=True)
gender = models.CharField(max_length=6, blank=True, null=True)
nric = models.CharField(max_length=40, blank=True, null=True)
birthday = models.DateField(blank=True, null=True)
birthTime = models.TimeField(blank=True, null=True)
class Family(models.Model):
userId = models.ForeignKey(MyUser)
relationship = models.CharField(max_length=100)
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
gender = models.CharField(max_length=6, blank=True, null=True)
nric = models.CharField(max_length=40, blank=True, null=True)
class Schedule2(models.Model):
userId = models.ForeignKey(MyUser, on_delete=models.CASCADE)
familyId = models.ForeignKey(Family, on_delete=models.CASCADE)
date = models.DateField()
time = models.TimeField()
location = models.CharField(max_length=255, blank=True, null=True)
title = models.Charfield(max_length=100, blank=True, null=True)
desc = models.CharField(max_length=300, blank=True, null=True)
serializer.py
class FamilySerializer(serializers.ModelSerializer):
class Meta:
model = Family
fields = ('id', 'userId', 'first_name', 'last_name', 'gender', 'nric', 'relationship')
class Schedule2Serializer(serializers.ModelSerializer):
valid_time_formats = ['%H:%M', '%I:%M%p', '%I:%M %p']
time = serializers.TimeField(format='%I:%M %p', input_formats=valid_time_formats)
class Meta:
model = Schedule2
fields = ('id', 'userId', 'familyId', 'title', 'desc', 'date', 'time', 'location')
views
class FamilyViewSet(viewsets.ModelViewSet):
permission_classes = [AllowAny]
queryset = Family.objects.all()
serializer_class = FamilySerializer
# this is to allow current user to see their own family only
def get_queryset(self):
user = self.request.user
return Family.objects.filter(userId=user)
class ScheduleViewSet2(viewsets.ModelViewSet):
permission_classes = [AllowAny]
queryset = Schedule2.objects.all()
serializer_class = Schedule2Serializer
The answer for the first question is "yes", you can set the user_id in the model to the id of the person logged in (self.request.user). To do this you will have to overwrite the create method.