These are my models:
class Partner(models.Model):
name = models.CharField(max_length=200, verbose_name="Organisation name")
class ResearchActivity(models.Model):
title = models.CharField(max_length=200)
partner = models.ManyToManyField(ActivityPartner, blank=True)
I'd like, in the Django administration forms, to have a field in my Partner edit form representing the ResearchActivity linked to that Partner.
Can this be achieved by adding a field to my Partner model (say, naming it linked_partner) and then edit my admin.py like so:
#admin.register(ActivityPartner)
class ActivityPartnerAdmin(admin.ModelAdmin):
search_fields = ['academic',]
autocomplete_fields = ['partnership_type', 'relationship_type', 'academic_links']
def get_changeform_initial_data(self, request):
return {'live_contract': ResearchActivity.objects.all().filter(linked_partner__id=request.ResearchActivity.partner.id)}
?
I have just come across in the display() decorator, new from Django 3.2. With it, I can simply do:
#admin.register(ActivityPartner)
class ActivityPartnerAdmin(admin.ModelAdmin):
search_fields = ['academic',]
autocomplete_fields = ['partnership_type', 'relationship_type', 'academic_links',]
readonly_fields = ('get_ra',)
#admin.display(description='Live contract(s)')
def get_ra(self, obj):
return list(ResearchActivity.objects.filter(partner=obj.id))
to achieve what I want.
If I also wanted to edit those ManyToMany relations, I can use the inlines option:
class LiveContractsInline(admin.TabularInline):
model = ResearchActivity.partner.through
#admin.register(ActivityPartner)
class ActivityPartnerAdmin(admin.ModelAdmin):
inlines = [
LiveContractsInline,
]
Related
admin.py
class authUserMenu(admin.ModelAdmin):
list_display = ["__str__", "user_id", "menu_id","is_active"]
class Meta:
Model = AuthUserMenu
admin.site.register(AuthUserMenu, authUserMenu)
models.py
class AuthUserMenu(models.Model): # USER VS MENU relation
user = models.ForeignKey(AuthUser,on_delete=models.DO_NOTHING,blank=True, null=True)
menu = models.ForeignKey(Menu,on_delete=models.DO_NOTHING,blank=True, null=True)
is_active = models.BooleanField(default=False)
class Meta:
db_table = 'auth_user_menu'
ordering = ['user','menu','is_active']
def __str__(self):
# return self.id
return str([self.user.username,'>>>>>>', self.menu.menu_name])
In my Django admin panel
When filtering with username should only show some menus under some condition... How can I achieve this?
Suppose here for the username 4 menu is showing. But it should show 2 menu. This may obtain by db querying.
This is how A user related to menus
You need some JS to call a view asyncronously every time the user field is updated and change the options in the menu field with the response. The package django-autocomplete-light is a popular choice for exactly this, especially updating field values from other fields is relevant
forms.py
class AuthUserMenuForm(forms.ModelForm):
class Meta:
model = AuthUserMenu
fields = '__all__'
widgets = {
'menu': autocomplete.ModelSelect2(
url='menu-autocomplete',
forward=['user']
)
}
views.py
class MenuAutocomplete(autocomplete.Select2QuerySetView):
def get_queryset(self):
qs = Menu.objects.all()
user = self.forwarded.get('user', None)
if user:
# Not clear exactly what your filter would be here so left it but you have user available
qs = qs.filter(...)
return qs
urls.py
urlpatterns = [
...
path('menu-autocomplete/', views.MenuAutocomplete.as_view(), name='menu-autocomplete'),
...
]
class AuthUserMenuAdmin(admin.ModelAdmin):
form = AuthUserMenuForm
list_display = ["__str__", "user_id", "menu_id", "is_active"]
admin.site.register(AuthUserMenu, AuthUserMenuAdmin)
Sorry But the filter's you are applying for admin is only valid for how they are Going to look on the admin panel it won't customize your model properties and in order to achieve that you need to create a filter as eg ...
user = self.get_object()
articles = Article.objects.filter(author_id)
Something like that
I have an example model which has a fk relation with user model and Blog model. Now I have a get api which only requires certain fields of user to be displayed.
My model:
class Example(models.Model):
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
null=True,
related_name="user_examples",
)
blog = models.ForeignKey(
Blog,
on_delete=models.CASCADE,
null=True,
related_name="blog_examples",
)
/................./
Now my view:
class ExampleView(viewsets.ModelViewSet):
queryset = Example.objects.all()
serializer_class = ExampleSerializer
def list(self, request, *args, **kwargs):
id = self.kwargs.get('pk')
queryset = Example.objects.filter(blog=id)
serializer = self.serializer_class(queryset,many=True)
return Response(serializer.data,status=200)
My serializer:
class ExampleSerializer(serializers.ModelSerializer):
class Meta:
model = Example
fields = ['user','blog','status']
depth = 1
Now when I call with this get api, I get all example objects that is required but all the unnecessary fields of user like password, group etc . What I want is only user's email and full name. Same goes with blog, I only want certain fields not all of them. Now how to achieve this in a best way??
You will have to specify the required fields in nested serializers. e.g.
class BlogSerializer(serializers.ModelSerializer):
class Meta:
model = Blog
fields = ['title', 'author']
class ExampleSerializer(serializers.ModelSerializer):
blog = BlogSerializer()
class Meta:
model = Example
fields = ['user','blog','status']
are you setting depth in serializer's init method or anywhere else? beacause ideally it should only display id's and not anything else. if yes then set depth to zero and use serializer's method field to return data that you need on frontend. I can provide you with example code samples
I have a Comment table on Django Admin:
models.py
class Comment(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
item = models.ForeignKey(Listing, on_delete=models.CASCADE)
comment = models.TextField(max_length=250)
datetime = models.DateTimeField(auto_now=True)
def __str__(self):
return f"{self.item}"
admin.py
class CommentInline(admin.TabularInline):
model = Comment
class ItemAdmin(admin.ModelAdmin):
inlines = [
CommentInline,
]
#admin.register(Comment)
class CommentAdmin(admin.ModelAdmin):
list_display = ('item','user','comment','datetime',)
list_filter = ('item',)
And I want to edit this table with the same values item that will display with a single row, and then after clicked on it will display another table contain user comment and datetime .
Thanks so much for any advice to me !!!
If item is a foreign key to one of your other models, you should be able to use an InlineModelAdmin object to create a tabular inline view of the user/comment/datetime using the item's admin view.
See
https://docs.djangoproject.com/en/3.1/ref/contrib/admin/#inlinemodeladmin-objects for reference.
In your case you may end up with something like:
class CommentInline(admin.TabularInline):
model = Comment
fields = ('user', 'comment', 'datetime')
class ItemAdmin(admin.ModelAdmin):
inlines = [
CommentInline,
]
If item is a models.CharField though I don't think you can do it with the Django Admin as provided by Django.
I just learned django last January and I'm currently working on website to store and show lyrics. My problem is that in createview the fields are not sorted.
Here is my models.py:
class Singer(models.Model):
song_singer = models.CharField(max_length=200)
def __str__(self):
return self.song_singer
def get_absolute_url(self):
return reverse('singer_author')
class Lyrics(models.Model):
title = models.CharField(max_length=50)
singer = models.ForeignKey(Singer, on_delete=models.RESTRICT)
type = models.ForeignKey(Type, on_delete=models.RESTRICT)
lyrics = models.TextField()
Views.py:
class AddSongView(LoginRequiredMixin, CreateView):
model = Lyrics
fields = ['title', 'singer', 'type', 'lyrics']
Screenshot in the browser
As you can see in the attached screenshot, the choices from singer field is not sorted. How to sort those choices? Thank you!
The easiest way to do this is by defining a default ordering=… [Django-doc] on your Singer model, this will then order the items by name if you do not specify another ordering:
class Singer(models.Model):
# …
class Meta:
ordering = ['song_singer']
Best to use a ModelForm here. This also gives you the chance to modify your form even more:
from django import forms
class SongForm(forms.ModelForm):
singer = forms.ModelChoiceField(queryset=Singer.objects.all().order_by('song_singer'))
class Meta:
model = Lyrics
fields = ['title', 'singer', 'type', 'lyrics']
class AddSongView(LoginRequiredMixin, CreateView):
form_class = SongForm
I have a django model named Event with a generic inline relation to Relationship, like this:
# models.py
class Person(models.Model):
...
class Role(models.Model):
...
class Event(models.Model):
...
class Relationship(models.Model):
person = models.ForeignKey(Person)
role = models.ForeignKey(Role)
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey("content_type", "object_id")
# admin.py
class RelationshipInline(generic.GenericTabularInline):
model = Relationship
extra = 0
class EventAdmin(admin.ModelAdmin):
inlines = [RelationshipInline]
I'd like to find a way to edit the inlines not only from the event admin page, but from the people admin page too. SO far I have added the following code to display inlines in the people page too
class ReverseRelationshipInline(admin.TabularInline):
model = Relationship
class IndividualAdmin(admin.ModelAdmin):
inlines = [ReverseRelationshipInline]
But I get content_type and object_id fields in the form and it is not very informational for admin users since it is just references to primary keys. I would rather prefer to resolve and show the content_object(even if it is not editable, to know at list to what objects are people related to).
Any direction to recommend?
Thanks.
Your "ReverseRelationshipInline" has to be a GenericTabularInline, not a TabularInline. That's all :-)
UPDATE
I think I now understand what you're after, and my answer is:
You won't be able to edit the content object inline of Person, but you want to show it nicely, maybe even as a link to its change form.
Add a function to Relationship which returns such an HTML link, provide your own ModelForm to your inline and specify the fields you want, which now includes your new function value (read-only). Something like this (untested):
# models.py
from django.core import urlresolvers
class Relationship(models.Model):
...
def link_content_object_changeform(self):
obj = self.content_object
change_url = urlresolvers.reverse(
'admin:%s_%s_change' % (
obj._meta.app_label,
obj._meta.object_name.lower()
),
args=(obj.id,)
)
return u'%s' % (change_url, obj.__unicode__())
link_content_object_changeform.allow_tags = True
link_content_object_changeform.short_description = 'in relation to'
# admin.py
class ReverseRelationshipInlineForm(forms.ModelForm):
class Meta:
model = Relationship
fields = ('person', 'role', 'link_content_object_changeform')
readonly_fields = ('link_content_object_changeform',)
class ReverseRelationshipInline(admin.TabularInline):
model = Relationship
form = ReverseRelationshipInlineForm