I'm using Django 1.2's new ManyToMany admin.TabularInline to display related objects in the admin app, and it works great except I can't figure out what to set the "ordering" property to so it can sort by one of the cross-referenced field names.
For instance:
class Foo(models.Model):
name = models.CharField(max_length=100)
class Bar(models.Model):
title = models.CharField(max_length=100)
foos = models.ManyToManyField(Foo)
class FooBarInline(admin.TabularInline):
model = Bar.foos.through
ordering = ('name', ) # DOES NOT WORK
raw_id_fields = ('name', ) # THROWS EXCEPTION
class FooAdmin(admin.ModelAdmin):
inlines = (FooBarInline, )
class Meta:
model = Foo
How can I get to the Foo.name field to order by it in the inline?
The model ordering meta option designates the order of the inline elements.
class Foo(models.Model):
name = models.CharField(max_length=100)
class Meta:
ordering = ('name',)
If you needed to have the ordering of the admin model different from your primary ordering, you could do something like this:
class Foo_Extended(Foo):
class Meta:
ordering = ('name',)
And use Foo_Extended for your AdminInline model.
I'm assuming you know this, but Django 1.3 adds and ordering option to the InlineAdmin model but I know you said Django 1.2
I think you may override
ModelAdmin.formfield_for_foreignkey(self, db_field, request, **kwargs)
You can find details in the docs for ModelAdmin.formfield_for_foreignkey.
Related
I have a main model, called "Employees", and I need to link to it another 16 model classes (Employees Additional Data, Employees Observations, etc) in the same app. What would be the best way to write these classes in models.py?
Could be like that?
class Employees(models.Model):
class Meta:
db_table = "employees"
#fields
#fields
class EmployeesObs(models.Model):
class Meta:
db_table = "employeesobs"
#fields
#fields
class EmployeesAdditionalData(models.Model):
class Meta:
db_table = "employeesaditional"
#fields
#fields
Now, in this views.py i need:
Explaining this in the template, I need to have these other tabs (Employees Additional Data, Employees Observations, etc) in the employee register, as in the image:
Now how do I write this in views.py?
I'm using Class Based Views. Can someone help me by giving me an example of code, function or documentation?
Part of code in CBV:
class AddEmployeesView(SuccessMessageMixin, CreateView):
model = Employees
form_class = EmployeesForm
template_name = '../templates/employees/form_employees.html'
success_url = reverse_lazy('list_Employees')
success_message = "Employees %(EmployeesNome)s Added!"
class EditEmployeesView(SuccessMessageMixin, UpdateView):
model = Employees
form_class = EmployeesForm
template_name = '../templates/employees/form_employees.html'
success_url = reverse_lazy('list_Employees')
success_message = "Employees %(EmployeesNome)s Edited!"
I tried to put the other model names in the "model" part of the CBV, but I got errors.
You'll need to use a foreign key to your Employee model :
class Employee(models.Model):
class Meta:
db_table = "employees"
#fields
#fields
class EmployeesObs(models.Model):
class Meta:
db_table = "employeesobs"
employee = models.ForeignKey(Employee, on_delete=models.CASCADE, related_name='observations')
#fields
class EmployeesAdditionalData(models.Model):
class Meta:
db_table = "employeesaditional"
employee = models.ForeignKey(Employee, on_delete=models.CASCADE, related_name='additional_data')
#fields
Then you can use CBV for these models as well. You can either add one observation at once or you can use an inline formset to add/edit multiple children at once.
Just keep in mind that these tabs can't be accessed before the employee is first created (because you need the ID to link to it)
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]
Here's my setup:
from django.contrib.auth.models import User
class Product(models.Model):
...
email_users = models.ManyToManyField(User, null=True, blank=True)
...
[elsewhere]
class ProductAdmin(admin.ModelAdmin):
list_display = ('name','platform')
admin.site.register(Product, ProductAdmin)
My main problem is, when I'm viewing the "Product" page in the admin section, email users are not being being ordered by their ID by default, and I'd like that to be ordered by their username.
From what I've read so far, it seems like I need to be adding:
email_users.admin_order_field = 'xxxx'
But I'm not quite sure what the syntax is to access the username.
The answer was referred to in Hao Lian's comment above, essentially, this is what needed to be done:
class ProductAdminForm(ModelForm):
email_users = forms.ModelMultipleChoiceField(queryset=User.objects.order_by('username'))
class Meta:
model = Product
class ProductAdmin(admin.ModelAdmin):
list_display = ('name','platform')
form = ProductAdminForm
admin.site.register(Product, ProductAdmin)
Mine was slightly different in the sense that I required the forms.ModelMultipleChoiceField, whereas the answer provided used forms.ModelChoiceField()
Solution above works well, but in my case I lost all attributes and customizations that my component had by default (like required, label, etc).
In some cases could be better override __init__() method in order to customize only your queryset, nothing else will change.
class ProductAdminForm(ModelForm):
class Meta:
model = Product
fields = '__all__' # required in new versions
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['email_users'].queryset = (
self.fields['email_users'].queryset.order_by('username')
)
I want to define two model fields: created_by, modified_by in a parent model, they will be acting as common fields for the child models.
class ExtendedModel(models.Model):
created_by = models.ForeignKey(User,related_name='r_created_by')
modified_by = models.ForeignKey(User,related_name='r_modified_by')
class Meta:
abstract = True
class ChildModel1(ExtendedModel):
pass
class ChildModel2(ExtendedModel):
pass
this gives errors as ChildModel1 and ChildModel2 has related_name clashed with each other on their created_by and modified_by fields.
The Django docs explain how to work around this: http://docs.djangoproject.com/en/dev/topics/db/models/#abstract-related-name
class ExtendedModel(models.Model):
created_by = models.ForeignKey(User,related_name='"%(app_label)s_%(class)s_created_by')
modified_by = models.ForeignKey(User,related_name='"%(app_label)s_%(class)s_modified_by')
class Meta:
abstract = True
class ChildModel1(ExtendedModel):
pass
class ChildModel2(ExtendedModel):
pass