Django Admin showing Object - not working with __unicode__ OR __str__ - python

my Django admin panel is showing object instead of self.name of the object.
I went through several similar questions here yet couldn't seem to resolve this issue. __unicode__ and __str__ bear the same results, both for books and for authors. I've changed those lines and added new authors/books in every change but no change.
MODELS.PY
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Author(models.Model):
name = models.CharField(max_length=100)
def __str__(self):
return self.name
class Book(models.Model):
auto_increment_id = models.AutoField(primary_key=True)
name = models.CharField('Book name', max_length=100)
author = models.ForeignKey(Author, blank=False, null=False)
contents = models.TextField('Contents', blank=False, null=False)
def __unicode__(self):
return self.name
I used both unicode & str interchangeably, same result.
Here are the screenshots of the admin panel by menu/action.
1st screen
Author List
Single Author

Your indentation is incorrect. You need to indent the code to make it a method of your model. It should be:
class Author(models.Model):
name = models.CharField(max_length=100)
def __str__(self):
return self.name
If you are using Python 3, use __str__. If you are using Python 2, use __unicode__, or decorate your class with the python_2_unicode_compatible decorator. After changing the code, make sure you restart the server so that code changes take effect.

Related

Name issue. Can't change the name of the Models in django database

from django.db import models
# Create your models here.
class Course (models.Model):
name = models.CharField(max_length=100)
language= models.CharField(max_length=100)
price= models.CharField(max_length=100)
def __str__(self):
return self.name
in django database the object dosent change name still named Course object (1) in the list. Why does it not change? def str(self):
return self.name
what should one do to make django show the courses names? This should be correct. no errors or anything it just simply dosent do what it should. it seems strange.
The __str__ function should be in your class, not after it
class Course(models.Model):
name = models.CharField(max_length=100)
language = models.CharField(max_length=100)
price = models.CharField(max_length=100)
def __str__(self):
return self.name
class Course(models.Model):
name = models.CharField(max_length=100)
language= models.CharField(max_length=100)
price= models.CharField(max_length=100)
def __str__(self):
return self.name
i got answer for this so you have to add this in respective modules like i have category module in which models.py and then add this method.

unique_together with a field from a foreign key in a through table for a ManyToMany relation

I am developing a Django 2.0 project app. It has a (non-working) models.py file, which looks something like this:
from django.db import models
from django.utils import timezone
class Computer(models.Model):
name = models.CharField(max_length=25)
def __str__(self):
return "Computer {}".format(self.name)
class Software(models.Model):
name = models.CharField(max_length=25)
description = models.CharField(max_length=1024, blank=True)
def __str__(self):
return self.name
class SoftwareVersion(models.Model):
software = models.ForeignKey(Software, on_delete=models.CASCADE, related_name="versions")
version = models.CharField(max_length=100)
released_at = models.DateTimeField(default=timezone.now)
def __str__(self):
return "{} {}".format(self.software, self.version)
class ComputerSoftwareBundle(models.Model):
computer = models.ForeignKey(Computer, on_delete=models.CASCADE, related_name="bundles")
installed_at = models.DateTimeField(default=timezone.now)
versions = models.ManyToManyField(SoftwareVersion, through="BundleSoftwareVersion", related_name="bundles")
class BundleSoftwareVersion(models.Model):
bundle = models.ForeignKey(ComputerSoftwareBundle, on_delete=models.CASCADE)
version = models.ForeignKey(SoftwareVersion, on_delete=models.CASCADE)
class Meta:
unique_together = (("bundle", "version__software"),)
The app tracks software bundles currently or previously installed on computers. The thing here is that a bundle should not contain more than one version of the same software. Also, SoftwareVersion should contain a reference to Software, because the same version string has a different meaning for different pieces of software.
The code does not work as described in this Stackoverflow answer. I left the unique_together line in to illustrate what I am trying to achieve.
I've tried to work around this limitation of Django (not being able to use fields referred to via a foreign key in unique_together) by overriding the save and validate_unique methods in BundleSoftwareVersion but that did not work out completely well. Here's the implementation I have tried:
class BundleSoftwareVersion(models.Model):
bundle = models.ForeignKey(ComputerSoftwareBundle, on_delete=models.CASCADE)
version = models.ForeignKey(SoftwareVersion, on_delete=models.CASCADE)
def save(self, *args, **kwargs):
self.validate_unique()
super().save(*args, **kwargs)
def validate_unique(self, exclude=None):
super().validate_unique(exclude)
bundle_versions = BundleSoftwareVersion.objects.filter(bundle=self.bundle,
version__software=self.version.software)
count = len(bundle_versions)
if not self.pk:
# if this instance is not stored in the database,
# we need to increment the count to take this instance
# into account
count += 1
if count > 1:
raise ValidationError("There already is an instance of software '{}' in this bundle.".format(self.version.software))
I have thus far tried out these models via the admin site. The checks work when changing an existing ComputerSoftwareBundle (the admin site displays a message next to the offending entry), but adding results in an uncaught exception.
Is there a better way to enforce this kind of uniqueness?
I have come up with a workaround:
class BundleSoftwareVersion(models.Model):
bundle = models.ForeignKey(ComputerSoftwareBundle, on_delete=models.CASCADE)
version = models.ForeignKey(SoftwareVersion, on_delete=models.CASCADE)
_software = models.ForeignKey(Software, on_delete=models.CASCADE, null=True, editable=False)
class Meta:
unique_together = (("bundle", "_software"),)
def save(self, *args, **kwargs):
self._software = self.version.software
super().save(*args, **kwargs)
As you can see, I now have a helper field _software which is used in unique_together and into which the self.version.software is stored on each save.
So far, I have experienced one downside with this approach: trying to save a ComputerSoftwareBundle containing duplicate software instances results in an error page for IntegrityError being displayed instead of an error message within the form.
I would appreciate suggestions on how to fix this downside, or even suggestions for a different approach altogether.

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:

Show a field name instead of the whole object for ManyToMany object in django admin site

My models are as follows:
class Retailer(BaseModel):
brand = models.ManyToManyField('brands.Brand',blank=True)
class Brand(BaseModel):
name = models.CharField(max_length=100, unique=True)
website = models.URLField(max_length=500, blank=True, default='')
And my admin class is as follows:
class RetailerAdmin(admin.ModelAdmin):
filter_horizontal = ('brand',)
The admin site does show the multi-select field for me, but every entry in the brand list is just shown as Brand object, which makes no sense to me. I want every entry to be shown as the name field of that brand. What should I do?
You can just add __unicode__ (python 2) or __str__ (python 3) method to your model so it'll look like this
class Brand(BaseModel):
name = models.CharField(max_length=100, unique=True)
website = models.URLField(max_length=500, blank=True, default='')
def __unicode__(self):
return self.name

Models bleeding together in models.py?

In Django I'm trying to write a ModelForm for a ContactForm and when I try to load the page containing the form it says that it doesn't exist. Then when I try to render the other form I had previously written it says that
Caught AttributeError while rendering: 'CashtextsForm' object has no attribute 'subject'
'Subject' is a field in the form that I was trying to render in ContactForm. So is there some certain order I have to list them in models.py? Here's that code:
# Create your models here.
from django.db import models
from django.forms import ModelForm
class Cashtexts(models.Model):
cashTexts = models.CharField(max_length=100, blank=True) #change me to a website filter
superPoints = models.CharField(max_length=100, blank=True)#chance to "superPoints _Username"
varolo = models.CharField(max_length=100, blank=True)
swagbucks = models.CharField(max_length=100, blank=True)
neobux = models.CharField(max_length=100, blank=True)
topline = models.CharField(max_length=100, blank=True)
Paidviewpoint = models.CharField(max_length=100, blank=True)
cashcrate = models.CharField(max_length=100, blank=True)
def __unicode__(self):
return self.cashcode
class Contact(models.Model):
sender = models.EmailField()
subject = models.CharField(max_length=25)
message = models.TextField()
class CashtextsForm(ModelForm):
class Meta:
model = Cashtexts
def __unicode__(self):
return self.subject
class ContactForm(ModelForm):
class Meta:
model = Contact
I previously had them arranged as Model-Modelform, Model-Modelform but hereit shows them as the way I now currently have them.
Also Is there any advantages to write just forms? Right now I'm more comfortable writing model forms over forms(I dont imagine they are much differnt) but if I only wrote model forms would I be missing out on features? So is there anything I missed on how t write multiple forms in models.py or did I have them written worng? or can i not create them via the command syncdb?
The __unicode__(self) method should be part of your Contact class
class Contact(models.Model):
sender = models.EmailField()
subject = models.CharField(max_length=25)
message = models.TextField()
def __unicode__(self):
return self.subject
It doens't make sense inside CashtextsForm as that does not "know" a subject attribute.
Yes, your form really does not have subject, just remove __unicode__ definition and everything will be ok.
This is because of declarative style of django code. If you want to inspect your objects use pdb module and dir builtin.
You will use ModelForm subclasses almost every time, but sometimes you will need a form which can not be built from model. In this case django will help you to describe such form and to use form clean and field validation.
the subject field is defined in the model and not in the modelform, since a modelform can be initialized without a model instance it is not safe to do something like this:
def __unicode__(self):
return self.instance.subject
What you can do (but I do not really see the point of doing this):
def __unicode__(self):
if getattr(self, 'instance') is not None:
return self.instance.subject
return super(CashtextsForm, self).__unicode__()

Categories