Django-mptt admin categories - python

In my Django project I have a model:
class Category(MPTTModel):
name = models.CharField(default='',
max_length=50,
verbose_name='Название')
slug = models.SlugField(default='')
parent = TreeForeignKey('self',
related_name='children',
null=True,
blank=True,
verbose_name='Родительская категория'
)
order = models.PositiveSmallIntegerField(blank=False,
null=False,
default=0,
verbose_name='Порядок')
is_active = models.BooleanField(default=True,
db_index=True,
verbose_name='Отображать на сайте')
class Meta:
verbose_name = 'Категория'
verbose_name_plural = 'категории'
class MPTTMeta:
order_insertion_by = ['order']
If I add the main categories first (one, two, three), and then add subcategories (four in one, five in two, six in three), I would like to see it in the admin panel like this:
-one
--four
-two
--five
-three
--six
But I have this ordering:
-one
-two
-three
--four
--five
--six
What am I doing wrong?

You need to register Category model with MPTTModelAdmin
In your admin.py
from django.contrib import admin
from mptt.admin import MPTTModelAdmin
from .models import Category
admin.site.register(Category, MPTTModelAdmin)
Reference: https://django-mptt.github.io/django-mptt/admin.html

Thanx! It seems that SortableModelAdmin from suit.admin broke an order.
My admin.py was:
from suit.admin import SortableModelAdmin
from mptt.admin import MPTTModelAdmin
from .models import Category, Good
class CategoryAdmin(MPTTModelAdmin, SortableModelAdmin):
mptt_level_indent = 20
list_display = ('name', 'slug', 'is_active', 'order')
list_editable = ('is_active',)
prepopulated_fields = {"slug": ("name",)}
# Specify name of sortable property
sortable = 'order'
admin.site.register(Category, CategoryAdmin)

Related

ERROR: admin.E108 and admin.E116 Django Framework Python

I got the these two errors below:
<class 'blog.admin.CommentAdmin'>: (admin.E108) The value of
'list_display[4]' refers to 'active', which is not a callable, an
attribute of 'CommentAdmin', or an attribute or method on
'blog.Comment'.
<class 'blog.admin.CommentAdmin'>: (admin.E116) The value of
'list_filter[0]' refers to 'active', which does not refer to a Field.
This is my models.py code:
from django.contrib.auth.models import User
# Create your models here.
STATUS = (
(0,"Draft"),
(1,"Publish")
)
class Post(models.Model):
title = models.CharField(max_length=200, unique=True)
slug = models.SlugField(max_length=200, unique=True)
author = models.ForeignKey(User, on_delete= models.CASCADE,related_name='blog_posts')
updatedOn = models.DateTimeField(auto_now= True)
content = models.TextField()
createdOn = models.DateTimeField(auto_now_add=True)
status = models.IntegerField(choices=STATUS, default=0)
class Meta:
ordering = ['-createdOn']
def __str__(self):
return self.title
class Comment(models.Model):
post = models.ForeignKey(
Post, on_delete=models.CASCADE, related_name='comments')
name = models.CharField(max_length=80)
email = models.EmailField()
body = models.TextField()
createdOn = models.DateTimeField(auto_now_add=True)
status = models.BooleanField(default=False)
class Meta:
ordering = ['createdOn']
def __str__(self):
return 'Comment {} by {}'.format(self.body, self.name)
This is my admin.py code:
from django.contrib import admin
from .models import Post, Comment
# Register your models here.
class PostAdmin(admin.ModelAdmin):
list_display = ('title', 'slug', 'status','createdOn')
list_filter = ("status", 'createdOn')
search_fields = ['title', 'content']
prepopulated_fields = {'slug': ('title',)}
#admin.register(Comment)
class CommentAdmin(admin.ModelAdmin):
list_display = ('name', 'body', 'post', 'createdOn', 'active')
list_filter = ('active', 'createdOn')
search_fields = ('name', 'email', 'body')
actions = ['approveComments']
def approveComments(self, request, queryset):
queryset.update(active=True)
admin.site.register(Post, PostAdmin)
This is my forms.py code:
from .models import Comment
from django import forms
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ('name', 'email', 'body')
Any help is greatly appreciated.
The message is clear 'active' is not a field
class Comment(models.Model):
post = models.ForeignKey(
Post, on_delete=models.CASCADE, related_name='comments')
name = models.CharField(max_length=80)
email = models.EmailField()
body = models.TextField()
createdOn = models.DateTimeField(auto_now_add=True)
status = models.BooleanField(default=False)
your fields are: post, name, email, createdOn, status
Therefore create a field named active or suppress active in list_display &
list_filter
status = models.IntegerField(choices=STATUS, default=0)
should be:
active = models.IntegerField(choices=STATUS, default=0)
I got the same error below:
ERRORS: <class 'store.admin.PersonAdmin'>: (admin.E116) The value of
'list_filter[0]' refers to 'PersonAgeFilter', which does not refer to
a Field.
When assigning the custom filter PersonAgeFilter to list_filter() with parentheses as shown below:
# "store/admin.py"
from django.contrib import admin
from .models import Person
class PersonAgeFilter(admin.SimpleListFilter):
# ...
#admin.register(Person)
class PersonAdmin(admin.ModelAdmin):
list_filter = ("PersonAgeFilter",)
# ↑ Parentheses ↑
So, I removed the parentheses from "PersonAgeFilter" as shown below then the error was solved.
# "store/admin.py"
from django.contrib import admin
from .models import Person
class PersonAgeFilter(admin.SimpleListFilter):
# ...
#admin.register(Person)
class PersonAdmin(admin.ModelAdmin):
list_filter = (PersonAgeFilter,)
# Without parentheses

Django admin: adding objects for foreignkey from other side

so I have these two models
class Recipe(models.Model):
short_description = HTMLField(max_length=400)
likes = models.ManyToManyField(User, blank=True, related_name='recipe_likes')
slug = models.SlugField(blank=True, unique=True)
published_date = models.DateTimeField(blank=True, default=datetime.now)
ratings = GenericRelation(Rating, related_query_name='recipes')
class Ingredient(models.Model):
name = models.CharField(max_length=20)
amount = models.FloatField()
recipe = models.ForeignKey(Recipe, on_delete=models.CASCADE, related_name='recipe_ingredients')
In the admin panel from the recipes section, if I choose a recipe I want to be able to add ingredients for that recipe, what do I need? I think I don't know the right searchterms to use, hope you understand what I mean.
Thanks for the help.
EDIT
This is the solution:
from django.contrib import admin
from .models import Recipe, Ingredient
class IngredientInline(admin.TabularInline):
model = Ingredient
extra = 3
#admin.register(Recipe)
class RecipeAdmin(admin.ModelAdmin):
list_display = ('title',)
search_fields = ('title', )
inlines = [IngredientInline,]
from django.contrib import admin
from .models import Recipe, Ingredient
class IngredientInline(admin.TabularInline):
model = Ingredient
extra = 3
#admin.register(Recipe)
class RecipeAdmin(admin.ModelAdmin):
list_display = ('title',)
search_fields = ('title', )
inlines = [IngredientInline,]
You'll want to read up on InlineModelAdmins:
https://docs.djangoproject.com/en/3.1/ref/contrib/admin/#inlinemodeladmin-objects
When you register your models with a model admin class, add an inlines list.
The documentation is good on this, so please expand your question if you have more detailed questions!

Get Django admin.ModelAdmin to display join of two tables

I have a Django app with the following models.py
from django.db import models
class Order(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
email = models.EmailField()
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
paid = models.BooleanField(default=False)
delivered = models.BooleanField(default=False)
class OrderItem(models.Model):
order = models.ForeignKey(Order,
related_name='items',
on_delete=models.CASCADE)
product = models.ForeignKey(Product,
related_name='order_items',
on_delete=models.CASCADE)
price = models.DecimalField(max_digits=10, decimal_places=2)
And in my admin.py, I have this
from django.contrib import admin
#admin.register(Order)
class OrderAdmin(admin.ModelAdmin):
list_display = ['id', 'first_name', 'last_name', 'email',
'paid', 'delivered']
list_filter = ['paid', 'delivered']
This only shows the Order table.
I would like to join the Order with the OrderItem table and display it in the Django admin. I am not sure this is relevant but for one Order, there could be many OrderItem(s).
As far as I know, you can't show OrderItems in OrderAdmin directly. But you can show Order in OrderItemAdmin, or use InLineModelAdmin to show OrderItems in Order Detail page. Like this:
class OrderItemInline(admin.TabularInline):
model = OrderItem
class OrderAdmin(admin.ModelAdmin):
inlines = [
OrderItemInline,
]
If you still want to display OrderItems (or parts of order item) in admin page, then you can add a method in list_display field, and use that method to fetch OrderItems. Like this:
class OrderAdmin(admin.ModelAdmin):
list_display = (..., 'get_order_items')
def get_order_items(self, obj):
return return ", ".join(obj.items.values_list("pk", flat=True))
get_order_items.short_description = 'Order Items'

django import-export "NOT NULL constraint failed"

I'm pretty new at Django and am stuck trying to implement Django import-export. My three pertinent model are Officer, Incident, and Details. Officer and Incident are in a M2M relationship through Details. I have gotten all of the functionality to work besides importing details. When I try to import via the import button, I get "NOT NULL constraint failed: police_archive_details.incident_id" for each row in the .xls or .csv file I'm importing.
Here's my (current) admin.py
from django.contrib import admin
from import_export import resources, widgets, fields
from import_export.admin import ImportExportModelAdmin, ImportExportActionModelAdmin
from forms import AdminTextForm, OfficerTextForm
from .models import Officer, Incident, Details, SiteText
class FullNameForeignKeyWidget(widgets.ForeignKeyWidget):
def get_queryset(self, value, row):
return self.model.objects.filter(
first_name__iexact=row["first_name"],
last_name__iexact=row["last_name"]
)
class DetailsInlineAdmin (admin.TabularInline):
model = Details
extra = 5
class OfficerResource(resources.ModelResource):
class Meta:
model = Officer
class OfficerAdmin(ImportExportModelAdmin):
list_display = ('first_name', 'last_name', 'badge', 'department')
search_fields = ['first_name', 'last_name']
inlines = [DetailsInlineAdmin]
resource_class = OfficerResource
form=OfficerTextForm
class Media:
js = ('//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js','/static/admin/js/admin/popup.js')
class IncidentResource(resources.ModelResource):
officer = fields.Field(
column_name='officer',
attribute='officer',
widget=widgets.ForeignKeyWidget(Officer, 'badge'))
class Meta:
fields = ('officer',)
model = Incident
class IncidentAdmin(ImportExportModelAdmin):
list_display = ('office','case_number')
search_fields = ['case_number']
inlines = [DetailsInlineAdmin]
resource_class = IncidentResource
class DetailsResource(resources.ModelResource):
officer = fields.Field(
column_name='officer',
attribute='officer',
widget=FullNameForeignKeyWidget(Officer))
incident = fields.Field(
column_name='incident',
attribute='incident',
widget=widgets.ForeignKeyWidget(Incident, 'case_number'))
class Meta:
fields = ('id','incident','officer__last_name','officer__first_name','allegation', 'finding', 'action')
model = Details
class DetailsAdmin(ImportExportModelAdmin):
list_display=('incident','officer', 'allegation', 'finding', 'action')
search_fields = ['officer__last_name', 'incident__case_number']
resource_class = DetailsResource
class SiteTextAdmin(admin.ModelAdmin):
form=AdminTextForm
admin.site.register(Officer, OfficerAdmin)
admin.site.register(Incident, IncidentAdmin)
admin.site.register(Details, DetailsAdmin)
admin.site.register(SiteText, SiteTextAdmin)
And here's models.py
from __future__ import unicode_literals
from django.db import models
from tinymce import models as tinymce_models
class Officer(models.Model):
first_name = models.CharField(max_length=80, blank=True, null=True)
last_name = models.CharField(max_length=80, blank=True, null=True)
badge = models.IntegerField(blank=True, null=True)
department = models.CharField(max_length=50, blank=True, null=True)
model_pic = models.ImageField(upload_to = "police_archive/officer_photos", default= 'noimage', blank=True, null=True)
description = tinymce_models.HTMLField(blank=True, null=True)
def __str__(self):
return self.last_name + ', ' + self.first_name
class Meta():
ordering = ['last_name']
class Incident(models.Model):
officer = models.ManyToManyField(Officer, through='Details')
case_number = models.CharField(max_length=50, blank=True)
OFFICE_CHOICES = (
('CRA', 'Civilian Review Authority'),
('IA', 'Internal Affairs'),
('OPCR', 'Office of Police Conduct Review'),
)
office = models.CharField(max_length=10,
choices=OFFICE_CHOICES,
)
def __str__(self):
return self.case_number
class Meta():
ordering = ['-case_number']
class Details(models.Model):
officer = models.ForeignKey(Officer, on_delete=models.CASCADE, blank=True)
incident = models.ForeignKey(Incident, on_delete=models.CASCADE, blank=True)
allegation = models.CharField(max_length=50, blank=True)
finding = models.CharField(max_length=50, blank=True)
action = models.CharField(max_length=50, blank=True)
def __str__(self):
return self.officer.first_name + ' '+ self.officer.last_name+ ', ' + self.incident.case_number
class Meta():
verbose_name_plural = "details"
ordering = ['incident__case_number']
class SiteText(models.Model):
content1 = tinymce_models.HTMLField()
content2 = models.TextField(max_length=500, blank=True)
OK, I spent all day debugging yesterday and got everything working properly. Here's my admin.py now, models.py is unchanged. I forget exactly which change solved the original error I posted about.
from django.contrib import admin
from import_export import resources, widgets, fields
from import_export.admin import ImportExportModelAdmin, ImportExportActionModelAdmin
from forms import AdminTextForm, OfficerTextForm
from .models import Officer, Incident, Details, SiteText
class DetailsInlineAdmin (admin.TabularInline):
model = Details
extra = 5
class OfficerResource(resources.ModelResource):
class Meta:
model = Officer
class OfficerAdmin(ImportExportModelAdmin):
list_display = ('first_name', 'last_name', 'badge', 'department')
search_fields = ['first_name', 'last_name']
inlines = [DetailsInlineAdmin]
resource_class = OfficerResource
form=OfficerTextForm
class Media:
js = ('//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js','/static/admin/js/admin/popup.js')
class IncidentResource(resources.ModelResource):
class Meta:
fields = ('officer','case_number', 'office')
model = Incident
import_id_fields = ['case_number']
class IncidentAdmin(ImportExportModelAdmin):
list_display = ('office','case_number')
search_fields = ['case_number']
inlines = [DetailsInlineAdmin]
resource_class = IncidentResource
class DetailsResource(resources.ModelResource):
class BadgeForeignKeyWidget(widgets.ForeignKeyWidget):
def get_queryset(self, value, row):
return self.model.objects.filter(
badge__iexact=row["badge"]
)
officer = fields.Field(
column_name='officer',
attribute='officer',
widget=BadgeForeignKeyWidget(Officer, 'last_name'))
incident = fields.Field(
column_name='incident',
attribute='incident',
widget=widgets.ForeignKeyWidget(Incident, 'case_number'))
class Meta:
fields = ('id','officer','incident', 'allegation', 'finding', 'action')
model = Details
class DetailsAdmin(ImportExportModelAdmin):
list_display=('incident','officer', 'allegation', 'finding', 'action')
search_fields = ['officer__last_name', 'incident__case_number']
resource_class = DetailsResource
class SiteTextAdmin(admin.ModelAdmin):
form=AdminTextForm
admin.site.register(Officer, OfficerAdmin)
admin.site.register(Incident, IncidentAdmin)
admin.site.register(Details, DetailsAdmin)
admin.site.register(SiteText, SiteTextAdmin)
Another note is that you need to put an 'id' column in your spreadsheet. I was able to leave mine blank and then Django would generate an id to use as a primary key.

list_display doesn't work

There is a class named Employees in models.py
class Employees(models.Model):
employee_id = models.CharField(verbose_name = _("Employee ID"), max_length=20, primary_key=True)
employee_name = models.CharField(verbose_name = _("Employee Name"), max_length=20)
department = models.CharField(verbose_name = _("Department"), max_length=100)
post = models.CharField(verbose_name = _("Post"), max_length=100)
Then I wrote some code in admin.py
class EmployeesAdmin(admin.ModelAdmin):
list_display = ('employee_id', 'employee_name', 'department', 'post')
According to the tutorial, there should be four fields in the Employee branch. But in my situation, there is only one field named Employees, just like I didn't add EmployeesAdmin class in admin.py. What's wrong with it? Did I miss something?
admin.py:
from django.contrib import admin
from .models import Employees, Purchase, ProductsOut
# Register your models here.
admin.site.register(Employees)
admin.site.register(Purchase)
admin.site.register(ProductsOut)
Register your admin in admin.site like:-
admin.site.register(ModelName, AdminName)
Try the following after declaring your EmployeesAdmin class in admin.py:
admin.site.register(Employees, EmployeesAdmin)

Categories

Resources