I have two models with the following relationship defined in models.py:
class InnerModel(models.Model):
name = models.CharField(max_length=100)
def __str__(self):
return self.name
class OuterModel(models.Model):
inner = models.OneToOneField(InnerModel)
def __str__(self):
return "OuterModel"
My forms.py looks like this:
class OuterModelForm(forms.ModelForm)
class Meta:
model = OuterModel
fields = ['inner']
My admin.py form looks like this:
class OuterModelAdmin(admin.ModelAdmin)
form = OuterModelForm
admin.site.register(OuterModel, OuterModelAdmin)
When I display the admin page, I can see the InnerModel instance and the name field is present, but the name field is an empty drop-down menu rather than a blank text field that can be edited.
How can I change the InnerModel name field so that it can be edited by admin?
You need to use inlines (doc):
class InnerModelInline(admin.StackedInline):
model = InnerModel
class OuterModelAdmin(admin.ModelAdmin):
inlines = [InnerModelInline]
admin.site.register(OuterModel, OuterModelAdmin)
Similar question: here
Related
I want to be able to sort a table column defined using a custom method in the Django admin.
I narrowed down the problem to this simple example in Django:
models.py:
from django.db import models
class MyObject(models.Model):
name = models.CharField(_("name"), max_length=255)
layers = models.URLField(_("Layers"), blank=True, max_length=1024)
choices = models.TextField(
verbose_name=_("Choice values"),
blank=True,
help_text=_("Enter your choice"),
)
class Meta:
verbose_name = _("Object config")
verbose_name_plural = _("Objects config")
def __str__(self): # my custom method
return self.name
and admin.py:
from django import forms
from django.contrib import admin
class MyObjectAdminForm(forms.ModelForm):
"""Form"""
class Meta:
model = models.MyObject
fields = "__all__"
help_texts = {
"layers": "URL for the layers",
}
class MyObjectAdmin(admin.ModelAdmin):
form = MyObjectAdminForm
list_filter = ["name",]
search_fields = ["name",]
# I want the first column (__str__) to be sortable in the admin interface:
list_display = ["__str__", ...] # the ... represent some other DB fields
but for the moment I cannot sort that first column (it is grayed out, I cannot click on its title):
So how could I sort the first column in this admin table as defined by the __str__() method of the MyObject model? (please note that I cannot change the model itself. I'm also brand new to Django, so don't hesitate to detail your answer as if you were speaking to a kid.)
I have 2 models that look like this:
models.py
class Client(models.Model):
deal = models.ManyToManyField('Deal', related_name="clients")
class Deal(models.Model):
client = models.ManyToManyField(Client, related_name="deals")
Then in the admin, I have inlined the related models to make it easy to make changes regardless of the object type you have open.
admin.py
class ClientInline(admin.TabularInline):
model = Deal.client.through
class DealAdmin(admin.ModelAdmin):
inlines = [ClientInline]
class DealInline(admin.TabularInline):
model = Client.deal.through
class ClientAdmin(admin.ModelAdmin):
inlines = [DealInline]
However, if you add a Client to a Deal and then open the Client detail page, the corresponding deal does not appear. Is there something I'm not connecting?
It is enough to have relation define only in one model. Otherwise you'll have 2 separate tables for separate ManyToMany relation: ClientDeal and DealClient.
What you need to do is to choose which one you need to leave. And probably update Admin inlines according to Django Admin documentation
class Client(models.Model):
deals = models.ManyToManyField('Deal', related_name="clients")
class Deal(models.Model):
pass
Yes, If you're using models.manytoMany() , you have to put it only in one model. no the two
But there's a very good attribute you should use: through
with through attribute you can create a intermediate model. here there's an example:
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=200)
groups = models.ManyToManyField('Group', through='GroupMember', related_name='people')
class Meta:
ordering = ['name']
def __unicode__(self):
return self.name
class Group(models.Model):
name = models.CharField(max_length=200)
class Meta:
ordering = ['name']
def __unicode__(self):
return self.name
class GroupMember(models.Model):
person = models.ForeignKey(Person, related_name='membership')
group = models.ForeignKey(Group, related_name='membership')
type = models.CharField(max_length=100)
def __unicode__(self):
return "%s is in group %s (as %s)" % (self.person, self.group, self.type))
later, you can use your inline admin class!
I just tested this an you were actually really close.
First, #wowkin2 said, you don't want to define a ManyToManyField in both models so I would probably just define it in your Deal model.
Second, replace this:
class DealInline(admin.TabularInline):
model = Client.deal.through
with this:
class DealInline(admin.TabularInline):
model = Deal.client.through
And everything should work.
So, this is what your files should now look like:
models.py
class Deal(models.Model):
client = models.ManyToManyField(Client, related_name="deals")
admin.py
class ClientInline(admin.TabularInline):
model = Deal.client.through
class DealAdmin(admin.ModelAdmin):
inlines = [ClientInline]
class DealInline(admin.TabularInline):
model = Deal.client.through
class ClientAdmin(admin.ModelAdmin):
inlines = [DealInline]
I added one model Author in models.py file in my app and created model names for the author while I opened in admin panel it's showing as Author object(12) how can I change that?
I tried to add Unicode
class Author(models.Model):
author_name=models.CharField(max_length=300)
I want field name instead of Author object in the admin panel.
below i want change Author Object
Try This:
class Author(models.Model):
author_name=models.CharField(max_length=300)
def __str__(self):
return self.author_name
Follow what #dirkgroten said "Make it a habit to always override str for all your models"
Also You can use list_display method in your admin.py to achieve similar result. Create a admin class and use list_display to render fields of model in tabular format
Admin.py
from app.models import Artist #<-----Import you artist model
#admin.register(Artist) #<----- admin class should be just below this line
class ArtistAdmin(admin.ModelAdmin):
list_display = ["id", "author_name"]
Or you can also do this:
from app.models import Artist #<-----Import you artist model
class ArtistAdmin(admin.ModelAdmin):
list_display = ["id", "author_name"]
admin.site.register(Artist, ArtistAdmin) #<----register your class also
You can overrride __str__ method in django model class like that
class Author(models.Model):
author_name=models.CharField(max_length=300)
def __str__(self):
return self.author_name
Here is the example of overriding __str__ method for cases like yours.
class Language(models.Model):
language = models.CharField(max_length=32)
class Meta:
app_label = "languages"
ordering = ["-modified"]
def __str__(self):
return f"{self.language} (language {self.id})"
I want to add 3 fields in my Admin.py page. out of which two fields are from Model.py and one field is from form.py. But somehow when i add these fields to admin.site.register function, an error pops up saying 'userlist' is not recognizable. Below is my code :
Models.py
class About(models.Model):
about_author = models.TextField()
pic = models.FileField(upload_to = '', default = 'static/defaul.jpg')
Form.py
class PostAuthorDetails(forms.ModelForm):
def __init__(self,*args,**kwargs):
super(PostAuthorDetails,self).__init__(*args,**kwargs)
self.fields['userlist'] = forms.ModelChoiceField(queryset=User.objects.all())
class Meta:
model = About
fields = '__all__'
Admin.py
class PostAuthorDetailsAdmin(admin.ModelAdmin):
form = PostAuthorDetails
def get_fieldsets(self,*args,**kwargs):
return((None,{'fields':('about_author','pic','userlist'),}),)
admin.site.register(About,PostAuthorDetailsAdmin)
Please advise whats wrong with the code.
FormFields are class members. You can not declare FormFields during the initialisation of the Form.
class PostAuthorDetails(forms.ModelForm):
userlist = forms.ModelChoiceField(queryset=User.objects.all())
class Meta:
model = About
'__all__'
See the docs about ModelForms: https://docs.djangoproject.com/en/1.10/topics/forms/modelforms/
As the title suggests. I want to be able to change the label of a single field in the admin application. I'm aware of the Form.field attribute, but how do I get my Model or ModelAdmin to pass along that information?
the verbose name of the field is the (optional) first parameter at field construction.
If your field is a property (a method) then you should use short_description:
class Person(models.Model):
...
def address_report(self, instance):
...
# short_description functions like a model field's verbose_name
address_report.short_description = "Address"
As Javier suggested you can use verbose name in your fields in model.py. Example as below,
class Employee(models.Model):
name = models.CharField(max_length = 100)
dob = models.DateField('Date Of Birth')
doj = models.DateField(verbose_name='Date Of Joining')
mobile=models.IntegerField(max_length = 12)
email = models.EmailField(max_length=50)
bill = models.BooleanField(db_index=True,default=False)
proj = models.ForeignKey(Project, verbose_name='Project')
Here the dob,doj and proj files will display its name in admin form as per the verbose_name mentioned to those fields.
from django.db import models
class MyClassName(models.Model):
field_name = models.IntegerField(verbose_name='Field Caption')
Building on Javier's answer; if you need one label in forms (on the front-end) and another label on admin it is best to set internal (admin) one in the model and overwrite it on forms. Admin will of course use the label in the model field automatically.
Use "verbose_name" to change a field name as the example below.
"models.py":
from django.db import models
class MyModel(models.Model): # Here
name = models.CharField(max_length=255, verbose_name="My Name")
If you want change the field label only on particular admin model without changing field of the model:
class MyModelAdmin(admin.ModelAdmin):
def get_form(self, request, obj=None, **kwargs):
form = super().get_form(request, obj, **kwargs)
form.base_fields["name"].label = "New label"
return form