Django get attributes from foreign key's class - python

I would like to show one attribute from another class. The current class has a foreign key to class where I want to get the attribute.
# models.py
class Course(models.Model):
name = models.CharField(max_length=100)
degree = models.CharField(max_length=15)
university = models.ForeignKey(University)
def __unicode__(self):
return self.name
class Module(models.Model):
code = models.CharField(max_length=10)
course = models.ForeignKey(Course)
def __unicode__(self):
return self.code
def getdegree(self):
return Course.objects.filter(degree=self)
# admin.py.
class ModuleAdmin(admin.ModelAdmin):
list_display = ('code','course','getdegree')
search_fields = ['name','code']
admin.site.register(Module,ModuleAdmin)
So what i'm trying to do is to get the "degree" that a module has using the "getdegree". I read several topics here and also tried the django documentation but i'm not an experienced user so even I guess it's something simple, I can't figure it out. Thanks!

It is pretty straight forward.
Try this:
def getdegree(self):
return self.course.degree
Documentation here
You can do this safely because course is not a nullable field. If it were, you should have checked for existence of object before accessing its attribute.

Related

DRF serializers how to best handle indirect references to a FK?

Let's say I have the following models:
class Thing(models.Model):
thing_key = models.AutoField(primary_key=True)
state = models.ForeignKey(State, db_column='state_key', on_delete=models.CASCADE, default=0)
[...other fields unrelated to the question...]
class Meta:
db_table = 'THING'
class State(models.Model):
state_key = models.AutoField(primary_key=True)
flag = models.IntegerField(unique=True)
description = models.CharField(max_length=50)
class Meta:
db_table = 'STATE'
And let's say I need to create new Things based on data received via POST requests.
And let's say these POST requests do NOT contain the FK of Thing, which is state_key, but actually the flag field from the State model.
What is the best way to implement serializers that help accomplish the following things:
Create a new Thing even though the state_key is unknown.
Return a serialized representation of the newly created Thing without exposing the state_key.
After reading and re-reading the documentation, the best I could do is the following. It works, but I'm suspect there's a much more straightforward way to do it:
class FlagField(serializers.RelatedField):
def to_representation(self, value):
return value.flag
def to_internal_value(self, data):
return State.objects.get(flag=data)
class ThingSerializer(serializers.ModelSerializer):
state_flag = FlagField(queryset=State.objects.all(), source='state')
class Meta:
model = Thing
exclude = ['state']
Is this an acceptable approach? If not, what is wrong with it and how else could I accomplish the goal?
Thanks in advance!

How to change field in ModelForm generated html form?

I'm making one of my first django apps with sqlite database. I have some models like for example:
class Connection(models.Model):
routeID = models.ForeignKey(Route, on_delete=models.CASCADE)
activityStatus = models.BooleanField()
car = models.ForeignKey(Car, on_delete=models.CASCADE)
class Route(models.Model):
name = models.CharField(max_length=20)
and forms
class RouteForm(ModelForm):
class Meta:
model = Route
fields = ['name']
class ConnectionForm(ModelForm):
class Meta:
model = Connection
fields = ['routeID', 'activityStatus', 'car']
And in my website, in the url for adding new Connection, I have cascade list containing RouteIDs. And I'd like it to contain RouteName, not ID, so it would be easier to choose. How should I change my ConnectionForm, so I could still use foreign key to Route table, but see RouteName instead of RouteID?
For now it's looking like this, but I'd love to have list of RouteNames, while still adding to Connection table good foreign key, RouteID
Update the Route Model's __str__ method:
class Route(models.Model):
name = models.CharField(max_length=20)
def __str__(self):
return self.name
Because the __str__() method is called whenever you call str() on an object. Django uses str(obj) in a number of places like in Modelform. By default it returns id or pk that is why you were seeing ids in model form. So by overriding it with name, you will see the names appear in choice field. Please see the documentation for more details on this.

What is doing __str__ function in Django? [duplicate]

This question already has answers here:
What is the difference between __str__ and __repr__?
(28 answers)
Closed last month.
I'm reading and trying to understand django documentation so I have a logical question.
There is my models.py file:
from django.db import models
class Blog(models.Model):
name = models.CharField(max_length=255)
tagline = models.TextField()
def __str__(self):
return self.name
class Author(models.Model):
name = models.CharField(max_length=255)
email = models.EmailField()
def __str__(self):
return self.name
class Post(models.Model):
blog = models.ForeignKey(Blog)
headline = models.CharField(max_length=255)
body_text = models.TextField()
pub_date = models.DateField()
mod_date = models.DateField()
authors = models.ManyToManyField(Author)
n_comments = models.IntegerField()
n_pingbacks = models.IntegerField()
rating = models.IntegerField()
def __str__(self):
return self.headline
What is doing here each __str__ function in each class?
What is the reason I need those functions in it?
You created a Blog model. Once you migrate this, Django will create a table with "name" and "tagline" columns in your database.
If you want to interact with the database with the model, for example create an instance of the model and save it or retrieve the model from db,
def __str__(self):
return self.name
will come handy. Open the python interactive shell in your project's root folder via:
python manage.py shell
Then
from projectName.models import Blog
Blog.objects.all() # will get you all the objects in "Blog" table
Also, when you look at the models in your admin panel, you will see your objects listed, with the name property.
The problem is, the return will look like this if you did not add that function:
<QuerySet [<Blog:>,<Blog:>,<Blog:>....]
So you will not know what those objects are. A better way to recognize those objects is retrieving them by one of its properties which you set it as name. This way you will get the result as follow:
<QuerySet [<Blog:itsName>,<Blog:itsName>,<Blog:itsName>....]
If you want to test this out, run python manage.py shell and run:
from projectName.models import Blog
# The below will create and save an instance.
# It is a single step. Copy-paste multiple times.
Blog.objects.create(name="first",tagline="anything")
Blog.objects.all() # check out the result
The __str__ method just tells Django what to print when it needs to print out an instance of the any model. It is also what lets your admin panel, go from this
Note: how objects are just plainly numbered
to this
.
Note: proper object names here
You could choose what to show in the admin panel, as per your choice. Be it a field value or a default value or something else.
This overrides the default name of the objects of this class, it's something like Author:object which isn't very helpful.
overriding it gives a more human friendly name of the object like the Author.name
def str(self): is a python method which is called when we use print/str to convert object into a string. It is predefined , however can be customised. Will see step by step.Suppose below is our code.
class topics():
def __init__(self,topics):
print "inside init"
self.topics=topics
my_top = topics("News")
print(my_top)
Output:
inside init
<__main__.topics instance at 0x0000000006483AC8>
So while printing we got reference to the object. Now consider below code.
class topics():
def __init__(self,topics):
print "inside init"
self.topics=topics
def __str__(self):
print "Inside __str__"
return "My topics is " + self.topics
my_top = topics("News")
print(my_top)
Output:
inside init
Inside __str__
My topics is News
So, here instead of object we are printing the object. As we can see we can customize the output as well. Now, whats the importance of it in a django models.py file?
When we use it in models.py file, go to admin interface, it creates object as "News", otherwise entry will be shown as main.topics instance at 0x0000000006483AC8 which won't look that much user friendly.
The __str__ function is used add a string representation of a model's object, so that is
to tell Python what to do when we convert a model instance into a string.
And if you dont mention it then it will take it by default the USERNAME_FIELD for that purpose.
So in above example it will convert Blog and Author model's object to their associated name field and the objects of Post model to their associated headline field
Django has __str__ implementations everywhere to print a default string representation of its objects. Django's default __str__ methods are usually not very helpful. They would return something like Author object (1). But that's ok because you don't actually need to declare that method everywhere but only in the classes you need a good string representation. So, if you need a good string representation of Author but not Blog, you can extend the method in Author only:
class Author(models.Model):
name = models.CharField(max_length=100)
...
def __str__(self):
return f'{self.name}' # This always returns string even if self.name is None
class Post(models.Model):
author = models.ForeignKey(Author, on_delete=models.CASCADE)
text = models.CharField(max_length=100)
author = Author.objects.create(name='David')
print(author) # David
post = Post.objects.create(author=author, text='some text')
print(post) # Post object(1)
Now, beyond Django, __str__ methods are very useful in general in Python.
More info here.
When you want to return the objects in that class then you'll see something such as <QuerySet [object(1)]>. However no body wants to see something like this. they want actual name that human can understand what exactly is present in that table, so they use this function.
For example, you define __str__() in Person model as shown below:
# "models.py"
from django.db import models
class Person(models.Model):
first_name = models.CharField(max_length=20)
last_name = models.CharField(max_length=20)
def __str__(self): # Here
return self.first_name + " " + self.last_name
Then, you define Person admin as shown below:
# "admin.py"
from django.contrib import admin
from .models import Person
#admin.register(Person)
class PersonAdmin(admin.ModelAdmin):
pass
Now, the full name is displayed in the message and list in "Change List" page:
And in "Change" page:
And in "Delete" page:
Next, if you don't define __str__() in Person model as shown below:
# "models.py"
from django.db import models
class Person(models.Model):
first_name = models.CharField(max_length=20)
last_name = models.CharField(max_length=20)
# def __str__(self): # Here
# return self.first_name + " " + self.last_name
Now, the object name and id are displayed in the message and list in "Change List" page:
And in "Change" page:
And in "Delete" page:

How to insert data for multiple tables/models from the same page of django admin?

I am a Django newbie and working on admin section of my project. Below is my code for models.py.
class Shops(models.Model):
name = models.CharField(max_length=200)
description = models.CharField(max_length=1500)
address = models.CharField(max_length=1000)
location = models.CharField(max_length=100)
contact_number = models.IntegerField()
other_details = models.CharField(max_length=100,null='true')
def __str__(self): # __unicode__ on Python 2
return (self.name)
class Shop_Type(models.Model):
category = models.CharField(max_length=500)
def __str__(self): # __unicode__ on Python 2
return (self.category)
class Shop_Category(models.Model):
shop_id = models.ForeignKey(Shops)
category_id = models.ForeignKey(Shop_Type)
Now I want to display option for inserting data in both "Shops" and "Shop_Category" tables from the single page of admin module as both of them are connected. I referred this question but failed to achieve what I want. Below is the code for admin.py I used:
class ShopCatAdmin(admin.ModelAdmin):
model = Shop_category
class ShopsAdmin(admin.ModelAdmin):
inlines = [ShopCatAdmin]
admin.site.register(Shops, ShopsAdmin)
It is throwing some attribute error saying that - "'ShopCatAdmin' object has no attribute 'get_formset'"
It would be great if anyone can help me out with this.
Thanks in advance :)
You need to define ShopCatAdmin as inheriting from an inline admin class, not the basic admin.
class ShopCatAdmin(admin.TabularInline):
model = Shop_Category
(Note, Python style discourages underscores in class names; your models should be called ShopType and ShopCategory.)

Django one-to-many, add fields dynamically in Admin

I have the following code:
class Item(models.Model):
name = models.CharField(max_length=100)
keywords = models.CharField(max_length=255)
type = models.ForeignKey(Type)
class Meta:
abstract = True
class Variant(models.Model):
test_field = models.CharField(max_length=255)
class Product(Item):
price = models.DecimalField(decimal_places=2, max_digits=8,null=True, blank=True)
brand = models.ForeignKey(Brand)
variant = models.ForeignKey(Variant)
def get_fields(self):
return [(field.name, field.value_to_string(self)) for field in Product._meta.fields]
def __unicode__(self):
return self.name
Im using Grappelli.
I want my Product to have multiple Variations. Should I use a manytomanyfield?
I want to be able to add Variants to my Product directly in the Admin. Now I get an empty dropwdown with no variants(because they doesnt exists).
I thought Django did this automatically when u specified a Foreign Key?
How can I get the Variant fields to display directly on my Product page in edit?
I've read someting about inline fields in Admin?
Well, it's the other way around :)
1/ Place the foreign key field in your Variant, not in your Product (what you describe is actually a OneToMany relationship).
2/ Link the Variant to your Product in the relative ProductAdmin in admin.py as an inline (i.e VariantInline).
See the docs for further informations : https://docs.djangoproject.com/en/1.6/ref/contrib/admin/#inlinemodeladmin-objects
Hope this helps !
Regards,

Categories