Django. How to get fields from child model in views.py? - python

How to get fields from child model in views.py? For example, I've parent model BasicOrder and child model (who extends BasicOrder) TouristVisa.
I'm using Django 2.0.2 and Python 3.6.1. My models.py is:
class BasicOrder(models.Model):
user = models.ForeignKey(User, verbose_name=_('User'), on_delete=models.CASCADE)
status = models.PositiveIntegerField(_('Status'), choices=ORDER_STATUS, default=0)
def __str__(self):
return 'Order #{}'.format(self.id)
class TouristVisa(BasicOrder, models.Model):
citizenship = models.ForeignKey(
Citizenship, verbose_name=_('Citizenship'), on_delete=models.PROTECT
)
invitation_entry = models.PositiveSmallIntegerField(
_('Invitation entry'), choices=INVITATION_ENTRY
)
class Meta:
ordering = ['id']
Would be great to have access to field invitation_entry from child model (TouristVisa). I try this way in views.py:
order = BasicOrder.objects.get(user=request.user.id)
print(order.invitation_entry)
But it's show error:
AttributeError: 'BasicOrder' object has no attribute 'invitation_entry'

It's wrong, when TouristVisa inherits from BasicOrder it means it gets the fields user ans status as well, not the other way around. So, you can access the invitation_entry field but calling TouristVisa also because it's the only model where it exists.
Now, access to it like this:
order = BasicOrder.objects.get(user=request.user.id)
print(order.touristvisa.invitation_entry)

Related

How to get child model field value from parent model serializer in Django Rest Framework?

I am trying to access child model value from parent model serializer.
Parent Models
class Course(models.Model):
name = models.CharField(max_length=100)
Child Models
class CourseStaff(models.Model):
course = models.ForeignKey(Course, on_delete=models.CASCADE,
related_name='course_staff_course')
staff = models.ForeignKey(User, on_delete=models.CASCADE,
related_name='course_staff_user')
enable = models.BooleanField()
Serializer Class
class TeacherCourseSerializer(serializers.ModelSerializer):
class Meta:
model = Course
fields = '__all__'
Expected Result
[
{
id: 1,
name: "",
staff_id: 5, #<---- It will come from the child model.
is_enabled: true #<---- It will come from the child model.
}
]
I tried with this
Serializer
class TeacherCourseSerializer(serializers.ModelSerializer):
enable = serializers.CharField(source='course_staff_course.enable')
class Meta:
model = Course
fields = '__all__'
But getting error
Got AttributeError when attempting to get a value for field `enable` on serializer `TeacherCourseSerializer`.
The serializer field might be named incorrectly and not match any attribute or key on the `Course` instance.
Original exception text was: 'RelatedManager' object has no attribute 'enable'.
How can I achieve this?
Thanks
Course to course staff is one to many relationship. The related manager will not return a single object instead multiple objects. Instead you can try different approach if course is going to have only one staff use OneToOneField and continue in same way.
Other way is to create a nested serializer for staff and the use in the course serializer.
class CourseStaffSerializer(serializers.ModelSerializer):
class Meta:
model = CourseStaff
fields = '__all__'
class TeacherCourseSerializer(serializers.ModelSerializer):
teachers = CourseStaffSerializer(many=True, read_only=True)
class Meta:
model = Course
fields = '__all__'

Django admin inheritance, referencing child model id in parent model

I have a base model and 2 child models inheriting from base model
class Module(models.Model):
name = models.CharField(max_length=200, null=False)
def __str__(self):
return self.name
class A(Module):
title = models.CharField(max_length=300, null=False, verbose_name='Title')
image = models.FileField(upload_to='uploads/', null=True)
class B(Module):
title = models.CharField(max_length=300, null=False, verbose_name='Title')
sub_title = models.CharField(max_length=300, null=False, verbose_name='Title')
image = models.FileField(upload_to='uploads/', null=True)
This is working fine, Django creates table inside child model table that references to parent.
Now, where I struggle is that there is an additional app with its own model that needs to query related parent model with its all child models. Lets assume this is my app referencing to module class
class Page(models.Model):
title = models.CharField(max_length=300, null=False)
slug = models.SlugField(max_length=300, null=False, db_index = True)
modules = models.ManyToManyField('modules.module')
By this current setup, Django stores parent model id in child model table, I'm not using django on client side hence in my sql query I'd like to get the child module attached to parent, by having a reference to what child model is referencing to. Please have in mind, Parent is linked to only one model.
I've looked at abstract, proxy models as well as model_utils.managers InheritenceManager but none stored child model information in parent.
How do I achieve that?
Thanks
The relationship is already defined by the ManyToManyField. Being able to display it is perhaps the question you're getting at.
You can reference the "through" model and register it in Admin like so:
from django.contrib import admin
# https://docs.djangoproject.com/en/3.0/ref/contrib/admin/#inlinemodeladmin-objects
#
# You can use TabularInline, or StackedInline --- whichever meets your style preferences
#
class PageModuleInline(admin.TabularInline):
model = Page.modules.through # the implicit "join table" model
class PageAdmin(admin.ModelAdmin):
inlines = [
PageModuleInline,
]
class ModuleAdmin(admin.ModelAdmin):
inlines = [
PageModuleInline,
]
see: https://docs.djangoproject.com/en/3.0/ref/contrib/admin/#working-with-many-to-many-models

How to edit a property in Django Admin?

I have a model with an attribute that is connected to another model as follow:
class Book(models.Model):
synced = models.OneToOneField('SyncedBook'
related_name='internal',
on_delete=models.CASCADE)
# some more attributes here...
#property
def book_address(self)
return self.synced.book_address
However, the book_address is a also a FK in the SyncedBook table as follow:
book_address = models.ForeignKey('Address', db_index=True, null=True, blank=True,
related_name='address_book', on_delete=models.PROTECT)
I don't know and understand how to be able to edit the book_address through the Django admin page in class BookingAdmin(admin.ModelAdmin), even though I have read over the documentation. At first I have the attribute as readonly, but now I want to be able to edit it and save the new address from the Address table. Is there a way to make it happen through the class BookingAdmin(admin.ModelAdmin) and how? Any example and solution would be appreciate
Model properties are typically used for presenting logically defined data for a particular model instance and not necessarily storing data on the model instance itself.
An example of when to use a model property is as follows:
# Defines a product instance
class Product(model.Models):
name = models.CharField(max_length=100)
description = models.TextField()
active = models.BooleanField(default=True)
cost = models.DecimalField(max_digits=5, decimal_places=2)
price = models.DecimalField(max_digits=5, decimal_places=2)
# calculate profits on product
#property
def profit(self)
p = self.price - self.cost
return p
In your case, you are trying to actually be able to modify data against a related model instance within the django admin. To me this sounds like more specifically an Inline (click here for documentation)
So in your case, you would need to create something like the following to your admin.py file:
class SyncedBookInline(admin.TabularInline):
model = BookInline
#admin.Register(Book)
class BookAdmin(admin.ModelAdmin):
# all your model admin settings
inlines = [SyncedBookInline]
Additional Info:
The Inline solution should still work for you. Please see the working code listed below:
models.py:
from django.db import models
class Hero(models.Model):
name = models.CharField(max_length=50)
class HeroAcquaintance(models.Model):
name = models.CharField(max_length=50)
hero = models.OneToOneField(Hero, on_delete=models.CASCADE)
admin.py:
from django.contrib import admin
from .models import *
class HeroAcquaintanceInline(admin.TabularInline):
model = HeroAcquaintance
#admin.register(Hero)
class HeroAdmin(admin.ModelAdmin):
list_display = (
'name',
)
inlines = [HeroAcquaintanceInline]
#admin.register(HeroAcquaintance)
class HeroAcquaintanceAdmin(admin.ModelAdmin):
list_display = (
'name',
)
Screenshot:

Assigning current user in rest framework view

I have been getting my head around these basics but I am not getting it right. I am trying to associate my view to my user model using team which is a foreign key. When I try to create of a gps, I get an error saying "team is a required field" but instead it should be read only. The team attribute should be filled automatically with the id of the currentUser
Model
class User(models.Model):
first_name = models.CharField(max_length=200,blank=False)
last_name = models.CharField(max_length=200, blank=False)
class Gps(models.Model):
location = models.CharField(max_length=200,blank=False)
team= models.ForeignKey(User, on_delete=models.CASCADE)
serializers
class GpsSerializer(serializers.ModelSerializer):
class Meta:
model = Gps
fields = ('id','location','team')
view
class Gps_list(generics.ListCreateAPIView):
queryset = Gps.objects.all()
serializer_class = GpsSerializer
team = serializers.PrimaryKeyRelatedField(
read_only=True,
default=serializers.CurrentUserDefault()
)
There are two changes needed. First, team field definition should be moved to serializer class instead of view. Second, you should use Django's contrib.auth.User model instead of your definition of User, as because serializers.CurrentUserDefault() will bring request.user only. So you should remove your User definition and import that to your models.py:
from django.contrib.auth.models import User
Further steps would be to replace read_only=True with queryset=User.objects.all() to allow create.

Creating many to many relation with AUTH_USER_MODEL in django via intermediary model

I am trying to create the following models. There is a ManyToMany relation from Entry to AUTH_USER_MODEL via the EntryLike intermediate model.
class BaseType(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
creation_time = models.DateTimeField(auto_now_add=True)
last_update_time = models.DateTimeField(auto_now=True)
class Meta:
abstract = True
class Title(BaseType):
text = models.CharField(max_length=100)
description = models.TextField()
class EntryLike(BaseType):
entry = models.ForeignKey(Entry)
user = models.ForeignKey(settings.AUTH_USER_MODEL)
class Entry(BaseType):
title = models.ForeignKey(Title, on_delete=models.PROTECT)
text = models.TextField()
user = models.ForeignKey(settings.AUTH_USER_MODEL)
liked_by_users = models.ManyToManyField(settings.AUTH_USER_MODEL, through='EntryLike', through_fields=('entry', 'user'))
Running migrations on the above model scheme throws the error: AttributeError:'str' object has no attribute 'meta'.
Any help in resolving this error would be highly appreciated. Am new to Django & Python, but not to Web Development.
The issue is that settings.AUTH_USER_MODEL is almost certainly not a model instance. It's probably a string that constrains the choices another model can make - settings would be a strange place to leave a model definition.
To do a MTM between the user model and your field above you need need to do:
from django.contrib.auth.models import User
class Entry(BaseType):
title = models.ForeignKey(Title, on_delete=models.PROTECT)
text = models.TextField()
user = models.ForeignKey(User)
def __str__(self):
return self.title
I've added the str function so that it gives a more sensible return when you're manipulating it in admin/shell.
I'd also question whether you need the second set of fields (removed here), as you can use select related between the Entry and EntryLike join table, without any duplication of the fields - you can probably go that way, it's just a bit unnecessary.
Lastly, I'd note that the way I'm using it above just uses the default User object that comes with Django - you may wish to customise it. or extend the base class as you've done here with your own models' base class.
(All of this is predicated on AUTH_USER_MODEL not being a model instance - if it is, can you post the model definition from settings.py? )

Categories

Resources