I have the following admin class:
from django.contrib import admin
class CommandAdmin (admin.ModelAdmin):
list_display = ('name','status','get_requester', 'justification')
readonly_fields = ('name','status','get_requester', 'request', 'justification')
exclude = ('request',)
def get_requester(self,obj):
return obj.request.requester
get_requester.command_order_field = 'requester' #Allows column order sorting
get_requester.short_description = 'Who Requested' #Renames column head
def get_form(self, request, obj=None, **kwargs):
self.exclude = ['request']
form = super(CommandAdmin, self).get_form(request, obj, **kwargs)
return form
def get_queryset(self, request):
print request
qs = super(CommandAdmin, self).get_queryset(request).select_related('request')
return qs.filter(status='pending', request__isnull=False)
The Command model looks like this ...
class Command(models.Model):
... bunch of fields ...
justification = models.CharField(max_length=2000, blank=True, null=True)
request = models.ForeignKey('sudorequests.Request', blank=True, null=True)
When I get to the change form the 'Request' object still appears on the form. Here's a screen shot:
Related
I'm getting the following error when I go to the /val/4/13/bs url:
Page not found (404)
Request Method: GET
Request URL: http://127.0.0.1:8000/val/4/13/bs
Raised by: valapp.views.BSDetail
No balance sheet found matching the query
Here is the views.py code:
class BSDetail(generic.View):
def get(self, request, *args, **kwargs):
view = BSDisplay.as_view()
return view(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
view = PostEvent.as_view()
return view(request, *args, **kwargs)
class BSDisplay(generic.DetailView):
template_name = 'valapp/balsheet.jinja'
model = BalanceSheet
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
entityobject = get_object_or_404(Entity, pk=self.kwargs['pkent'])
context['bsinfo'] = BalanceSheet.objects.filter(company = entityobject)
return context
class EntityDetail(generic.View):
def get(self, request, *args, **kwargs):
view = EntityDetailDisplay.as_view()
return view(request, *args, **kwargs)
class EntityDetailDisplay(generic.DetailView):
model = Entity
template_name = 'valapp/entitydetail.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
engobject = get_object_or_404(Engagement, pk=self.kwargs['pk'])
entobject = get_object_or_404(Entity, pk=self.kwargs['pkent'])
context['engagement'] = engobject
context['entity'] = entobject
return context
The urls.py code is:
app_name = 'valapp'
urlpatterns = [
path('', views.IndexView.as_view(), name='index'),
path('<int:pk>/', views.ValDetailView.as_view(), name='engagement'),
path('<int:pk>/<int:pkent>/', views.EntityDetail.as_view(), name='entitydetail'),
path('<int:pk>/<int:pkent>/bs', views.BSDetail.as_view(), name='bs'),
path('newval/', views.newval, name="newval"),
path('<int:pk>/newentity/', views.NewEntity.as_view(), name="newentity"),
]
Here is the models.py:
class BalanceSheet(models.Model):
company = models.ForeignKey(Entity, on_delete=models.CASCADE)
account_type = models.CharField(max_length=50, choices = BS_ACT_CHOICES)
value = models.DecimalField(max_digits=20, decimal_places=2)
name = models.CharField(max_length=100)
year = models.IntegerField(choices=YEAR_CHOICES, default=2022)
tab_abv = models.DecimalField(max_digits=20, decimal_places=2, default=0)
tab_rdt = models.DecimalField(max_digits=20, decimal_places=2, default=0)
tab_debt = models.DecimalField(max_digits=20, decimal_places=2, default=0)
def __str__(self):
return self.name
There are balance sheet objects associated with Entity 13.
It's a bit messing with the the 'pk' and the 'pkent', which I plan to clean up in the future. Basically, each balance sheet is associated with an entity, which is associated with an engagement.
When I go to val/4/13, the page does load properly so there is an entity 13 and there are plenty of objects associated with entity 13 in the BalanceSheet model that should be loading.
If I'm not mistaken, your URL structure of <int:pk> and <int:pkent> is that the first pk is your Engagement and pkent is Entity. Your BSDisplay view is a DetailView which has a BalanceSheet model, however the pk passed to it is an Engagement pk, which Django is unable to find. Either change the model of the view or the PK that is passed to the URL.
My DB (MariaDB) is set to utf8mb4, my model and my view are all defined to use unicode characters.
The creation of the record is ok and a slug is correctly created with a value as for example corée. The problem raise right after the creation with a NoReverse match error msg. I had a look to the documentation but I don't understand what I'm doing wrong. Thanks for your support.
NoReverseMatch at /masterdat/countrycode/
Reverse for 'countrycode_update' with keyword arguments '{'slug': 'corée'}' not found. 1 pattern(s) tried: ['masterdat/countrycode/(?P[-a-zA-Z0-9_]+)/$']
Request Method: GET
Request URL: http://127.0.0.1:8000/masterdat/countrycode/
Django Version: 3.2.5
Exception Type: NoReverseMatch
Exception Value:
Reverse for 'countrycode_update' with keyword arguments '{'slug': 'corée'}' not found. 1 pattern(s) tried: ['masterdat/countrycode/(?P[-a-zA-Z0-9_]+)/$']
URL:
from django.urls import path
from masterdat import views
from masterdat.views import CountrycodeListView
from masterdat.views import CountrycodeCreateView, CountrycodeUpdateView
urlpatterns = [
path('masterdathome/', views.masterdathome, name='masterdathome'),
path('countrycode/', CountrycodeListView.as_view(),
name='countrycode_list'),
path('countrycode/add/', CountrycodeCreateView.as_view(),
name='countrycode_add'),
path('countrycode/<slug:slug>/', CountrycodeUpdateView.as_view(),
name='countrycode_update'),
]
Model:
class Countrycode(models.Model):
cou_code = models.CharField(
"Country name", max_length=40, primary_key=True)
cou_recblocked = models.BooleanField("Country record blocked")
cou_creator = models.ForeignKey(
User, on_delete=models.PROTECT, related_name='+',
verbose_name="Created by")
cou_creationdate = models.DateTimeField("Creation date",
auto_now=True)
cou_modifier = models.ForeignKey(
User, on_delete=models.PROTECT, related_name='+',
verbose_name="Last modification by")
cou_modified = models.DateTimeField(
"Last modification date", auto_now=True)
slug = models.SlugField(max_length=50, allow_unicode=True)
class Meta:
ordering = ["cou_code"]
def __str__(self):
return self.cou_code
def get_absolute_url(self):
return reverse('countrycode_update', kwargs={'slug': self.slug})
View:
from masterdat.models import Countrycode
#-----------------------
# List view Management
#-----------------------
class CountrycodeListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
permission_required = 'masterdat.view_countrycode'
model = Countrycode
paginate_by = 10
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(*args, **kwargs)
return context
# Search bar
def get_queryset(self):
result = super(CountrycodeListView, self).get_queryset()
query = self.request.GET.get('q')
if query:
query_list = query.split()
result = result.filter(
reduce(operator.and_,
(Q(cou_code__icontains=q) for q in query_list))
)
return result
#-----------------------------------
# Create and Update Views Management
#-----------------------------------
from masterdat.forms import CountrycodeForm
# Create View -----------
class CountrycodeCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
permission_required = 'masterdat.add_countrycode'
model = Countrycode
form_class = CountrycodeForm
success_url = reverse_lazy('countrycode_list')
def form_valid(self, form):
form.instance.slug = slugify(form.instance.cou_code, allow_unicode=True)
form.instance.cou_creator = self.request.user
form.instance.cou_modifier = self.request.user
form.save
return super().form_valid(form)
# Update View -----------
class CountrycodeUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
permission_required = 'masterdat.change_countrycode'
model = Countrycode
form_class = CountrycodeForm
success_url = reverse_lazy('countrycode_list')
def form_valid(self, form):
form.instance.cou_modifier = self.request.user
form.save
return super().form_valid(form)
The regular expression (?P[-a-zA-Z0-9_]+) will only match "cor" because "é" is not a member of the range "A-Z" or "a-z".
You could change it to (?P[-\w0-9_]+) to match non-ASCII characters.
I have extended the admin model, so for each staff member i can assign other customers only if they are in the same group.
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
is_manager = models.BooleanField(default=False)
group_account = models.CharField(max_length=3,blank=True,null=True)
clients_assigned = models.ManyToManyField(User, limit_choices_to = Q(groups__groupaccount__group_account=group_account),blank=True,null=True,related_name='+')
class UserProfileInline(admin.StackedInline):
model = UserProfile
verbose_name = "User extra"
verbose_name_plural = "extra"
filter_horizontal = ('clients_assigned', )
def save_model(self, request, obj, form, change):
return super().save_model(request, obj, form, change)
class UserAdmin(BaseUserAdmin):
inlines = [UserProfileInline, ]
def get_form(self, request, obj=None, **kwargs):
#permissions reduce for regular staff
if (not request.user.is_superuser):
self.exclude = ("app")
self.exclude = ("user_permissions")
## Dynamically overriding
#self.fieldsets[2][1]["fields"] = ('is_active', 'is_staff','is_superuser','groups')
self.fieldsets[2][1]["fields"] = ('is_active', 'is_staff')
form = super(UserAdmin,self).get_form(request, obj, **kwargs)
return form
and extended the group admin model
class GroupAccount(models.Model):
group_account = models.CharField(,max_length=3,blank=True,null=True)
group = models.OneToOneField(Group,blank=True,null=True)
def save(self, *args, **kwargs):
super(GroupAccount, self).save(*args, **kwargs)
what im trying to do is simply to limit the client list for each manager-user by his and their group indicator(group_account field), means the available client list are those whom have the same specific group as himself, such as '555'
when the group_account = '555' in the DB the result of groups__groupaccount__group_account=group_account are empty
but if i change it Hardcoded to: groups__groupaccount__group_account='555'
its return the relevant result.
is that possible and/or what the alternative?
django 1.9
thanks for the help
You should custom the formfield_for_foreignkey method of StackInline
class UserProfileInline(admin.StackedInline):
def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
field = super(UserProfileInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
if db_field.name == 'clients_assigned':
u = request.user
if not u.is_superuser:
field.queryset = field.queryset.filter(groups__in=u.groups.all())
return field
The admin.py is as follows :-
class SiteDetailInline(admin.TabularInline):
model = SiteDetail
form = SiteDetailForm
fields = ('name', )
can_delete = False
extra = 1
max_num = 1
def get_readonly_fields(self, request, obj=None):
if obj:
return ('clmsid',) + self.readonly_fields
return self.readonly_fields
class SiteAdmin(admin.ModelAdmin):
inlines = [ SiteDetailInline, ]
def queryset(self, queryset):
return Site.objects.filter(~Q(id = settings.SITE_ID))
signals.post_save.connect(create_sites_default_user, sender=Site)
admin.site.unregister(Site)
admin.site.register(Site, SiteAdmin)
The models.py is as follows :-
class SiteDetail(models.Model):
name = models.CharField(max_length=100, unique=True)
client = models.ForeignKey(client)
site = models.ForeignKey(Site)
clmsid = models.CharField(max_length=15, unique=True, verbose_name='clms id', help_text='clms identifier', ) # unique identifier L-XXXXXX-id
def save(self, *args, **kwargs):
if "L-" != self.clmsid[:2]:
self.clmsid = "%s-%s-%s" % ("L", self.accountid, self.id)
super(SiteDetail, self).save(*args, **kwargs)
def __unicode__(self):
return u''
I want to show the extra site details inline in the admin for the site framework. It is not giving any error. However the site details are not displayed inline. Please let me know, what mistake am I doing. Thanks in advance.
Try this
def get_fields(self, request, obj=None):
if obj:
return ('clmsid',) + self.fields
return self.fields
Let's say I have a simple blog app in Django 1.4:
class Post(models.Model):
title = …
published_on = …
tags = models.ManyToManyField('Tag')
class Tag(models.Model):
name = …
i.e. a post has many tags. On the Django admin, I get a nice little <select multi> if I include tags in the fields for the PostAdmin. Is there an easy way to include the list of the posts (as a simple <select multi>) in the TagAdmin? I tried putting fields = ['name', 'posts'] in the TagAdmin and got an ImproperlyConfigured error. (same result for post_set).
I'm alright with Django, so could whip up a proper AdminForm and Admin object, but I'm hoping there a Right Way™ to do it.
This is possible to do with a custom form.
from django.contrib import admin
from django import forms
from models import Post, Tag
class PostAdminForm(forms.ModelForm):
tags = forms.ModelMultipleChoiceField(
Tag.objects.all(),
widget=admin.widgets.FilteredSelectMultiple('Tags', False),
required=False,
)
def __init__(self, *args, **kwargs):
super(PostAdminForm, self).__init__(*args, **kwargs)
if self.instance.pk:
self.initial['tags'] = self.instance.tags.values_list('pk', flat=True)
def save(self, *args, **kwargs):
instance = super(PostAdminForm, self).save(*args, **kwargs)
if instance.pk:
instance.tags.clear()
instance.tags.add(*self.cleaned_data['tags'])
return instance
class PostAdmin(admin.ModelAdmin):
form = PostAdminForm
admin.site.register(Post, PostAdmin)
That False in there can be replaced with a True if you want vertically stacked widget.
A bit late to the party, but this is the solution that works for me (no magic):
# admin.py
from django.contrib import admin
from models import Post
class TagPostInline(admin.TabularInline):
model = Post.tags.through
extra = 1
class PostAdmin(admin.ModelAdmin):
inlines = [TagPostInline]
admin.site.register(Post, PostAdmin)
Reference: https://docs.djangoproject.com/en/dev/ref/contrib/admin/#working-with-many-to-many-models
Modify your models to add reverse field:
# models.py
from django.db import models
class Post(models.Model):
title = models.CharField(max_length=100)
published_on = models.DateTimeField()
tags = models.ManyToManyField('Tag')
class Tag(models.Model):
name = models.CharField(max_length=10)
posts = models.ManyToManyField('blog.Post', through='blog.post_tags')
Then in standard way add field to ModelAdmin:
#admin.py
from django.contrib import admin
class TagAdmin(admin.ModelAdmin):
list_filter = ('posts', )
admin.site.register(Tag, TagAdmin)
Matthew's solution didn't work for me (Django 1.7) when creating a new entry, so I had to change it a bit. I hope it's useful for someone :)
class PortfolioCategoriesForm(forms.ModelForm):
items = forms.ModelMultipleChoiceField(
PortfolioItem.objects.all(),
widget=admin.widgets.FilteredSelectMultiple('Portfolio items', False),
required=False
)
def __init__(self, *args, **kwargs):
super(PortfolioCategoriesForm, self).__init__(*args, **kwargs)
if self.instance.pk:
initial_items = self.instance.items.values_list('pk', flat=True)
self.initial['items'] = initial_items
def save(self, *args, **kwargs):
kwargs['commit'] = True
return super(PortfolioCategoriesForm, self).save(*args, **kwargs)
def save_m2m(self):
self.instance.items.clear()
self.instance.items.add(*self.cleaned_data['items'])
You can add a symmetrical many to many filter this way.
Credit goes to
https://gist.github.com/Grokzen/a64321dd69339c42a184
from django.db import models
class Pizza(models.Model):
name = models.CharField(max_length=50)
toppings = models.ManyToManyField(Topping, related_name='pizzas')
class Topping(models.Model):
name = models.CharField(max_length=50)
### pizza/admin.py ###
from django import forms
from django.contrib import admin
from django.utils.translation import ugettext_lazy as _
from django.contrib.admin.widgets import FilteredSelectMultiple
from .models import Pizza, Topping
class PizzaAdmin(admin.ModelAdmin):
filter_horizonal = ('toppings',)
class ToppingAdminForm(forms.ModelForm):
pizzas = forms.ModelMultipleChoiceField(
queryset=Pizza.objects.all(),
required=False,
widget=FilteredSelectMultiple(
verbose_name=_('Pizzas'),
is_stacked=False
)
)
class Meta:
model = Topping
def __init__(self, *args, **kwargs):
super(ToppingAdminForm, self).__init__(*args, **kwargs)
if self.instance and self.instance.pk:
self.fields['pizzas'].initial = self.instance.pizzas.all()
def save(self, commit=True):
topping = super(ToppingAdminForm, self).save(commit=False)
if commit:
topping.save()
if topping.pk:
topping.pizzas = self.cleaned_data['pizzas']
self.save_m2m()
return topping
class ToppingAdmin(admin.ModelAdmin):
form = ToppingAdminForm
admin.site.register(Pizza, PizzaAdmin)
admin.site.register(Topping, ToppingAdmin)