I am trying to use the Django admin to allow rudimentary management of page menus. I have one principal menu which I decided to extend with a sub menu to allow drop downs where necessary. Because the submenu item would have the same fields as the main menu items I though it would be a good idea to use inheritance and so the sub menu would inherit all the fields from main menu as well as having a foreign key relationship like so:
# main menu
class MainMenu(models.Model):
title = models.CharField(max_length=50)
url = models.URLField()
def __unicode__(self):
return self.title
class Meta:
verbose_name_plural = "Main Menu Items"
# submenu - for drop downs
class SubMenu(MainMenu):
main_menu = models.ForeignKey(MainMenu, related_name='+', null=True, blank=True)
class Meta:
verbose_name_plural = "Sub Menu Items"
I register the models with the admin, but when I save an item in the submenu, not only does it go into the sub menu it makes the same entry in the Main Menu. Any ides what I'm doing wrong? Do I need to somehow tell Django that I inherit the methods of MainMenu without saving to it? Any help much appreciated.
But that's how model inheritance works. SubMenu has an implicit OneToOne relationship with MainMenu, but the "inherited" fields actually belong to MainMenu.
What you could do is to define a BaseMenu abstract model - use abstract = True in the inner Meta class. Now both MainMenu and SubMenu inherit from that, but SubMenu adds its main_menu link.
Related
I have inline with many2many field in it.
After adding new record using add button and popup window for manytomany field, newly added record is not shown in other inlines in the page. Also, if I want to add new inline after it, newly added manytomany record does not exist until page is refreshed.
Example:
class Target(models.Model):
name = models.TextField()
class Task(models.Model):
targets = models.ManyToManyField(Target)
section = models.ForeigKey(Section)
class Section(models.Model):
name = models.TextField()
And in admin:
class TaskInline(admin.StackedInline):
model = Task
class SectionAdmin(admin.ModelAdmin):
inlines = (TaskInline,)
If I add new Target from TaskInline form, newly added target cannot be seen in other Task inline forms, nor if I add new Task inline.
Is there a way to refresh the page on Target save, or is there any better solution?
What I have:
a) A simple class to store tags:
class Tag(models.Model):
"""
Defines a tag for any model object.
"""
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey()
type = models.ForeignKey(TagType, related_name='+', verbose_name="Typ", db_column='Typ')
value = models.CharField("Wert", max_length=80, db_column='Wert')
b) A mixin that adds the reverse direction to any class:
class TaggedMixin(models.Model):
""" Mixed into a model class, provides it with the ability to receive tags
(i.e. Tag objects).
"""
_tags = GenericRelation(Tag)
c) And some class, call it Data, that inherits from the Mixin. In the admin, this class uses a GenericTabularInline for Tag to display the Data's tags. It also sets "save_as" to True in order to get the "Save As" button on its admin page.
What happens:
When I click "Save As" for a Data object that has at least one tag, I get:
Integrity Error (1048, "Column 'content_type_id' cannot be null")
To me it seems like Django Admin does not handle GenericForeignKeys properly when doing the "Save As". Is there a way to get it running? A way to work around the problem? Or could I be doing something wrong here?
Perhaps I should add, I am using Django 1.7.7 here.
EDIT: We have upgraded to 1.8.2 and the problem still persists. Any ideas?
I have apps and models similar to these:
In App 'Animals':
class Animal(models.Model):
name = models.CharField()
class Lion(Animal):
roar_loudness_decibel = models.IntegerField()
class Bear(Animal):
salmons_eaten = models.IntegerField()
# And many more that inherit Animal
In Application Zoo:
from Animal.models import Animal
class Zoo(models.Model):
animals = models.ManyToManyField(Animal)
In the Django admin interface, I have registered all app models.
Whenever I create a Zoo and want to add animals in the same form (click the green plus button and get a popup), I get the create form for Animal (not the models which have subclassed it).
Is there any way to be able to select which subclassed model to add for a ManyToManyField?
Or is there a better way to solve this (contenttypes? override the form?)
I'd rather not change the models if I can avoid it.
(I know that it is possible to add Bear or Lion separately and just select those objects when selecting animals for a Zoo, but what I'm asking for seems better usability-wise)
Override add_view() method of the AnimalAdmin and if it is called from popup window then show intermediate page with a list of available species.
Just the proof of concept:
admin.py
class AnimalAdmin(admin.ModelAdmin):
def add_view(self, request, form_url='', extra_context=None):
if request.method == 'GET' and '_popup' in request.GET:
return render(request, 'admin/animals/choose_animal.html')
return super(AnimalAdmin, self).add_view(request, form_url,
extra_context)
templates/admin/animals/choose_animal.html
<body>
Choose an animal:
<ul>
<li>Lion</li>
<li>Bear</li>
</ul>
</body>
Should've spent more time Googling for this.
I found https://django-polymorphic.readthedocs.org which offers selecting the child model in the admin interface and much more:
From the docs:
The add screen gains an additional step where the desired child model
is selected.
The edit screen displays the admin interface of the
child model.
I am using django-autocomplete in my "edit user details view" for adding "friends"
django-autocomplete works perfect but displays also the "current user" (who is editing his profile) and the user "anonymous"
I want to exclude those two.
How can I accomplish that?
models.py
class Profile(UserenaLanguageBaseProfile):
friends = models.ManyToManyField(User,related_name='userfriends', blank=True, null=True)
forms.py
class EditProfileForm(forms.ModelForm):
class Meta:
widgets = {
'friends': MultipleAutocompleteWidget(Profile.friends),
}
It's not a complete answer, but you should do something along those lines:
autocomplete = AutocompleteView()
class ProfileAutocomplete(AutocompleteSettings):
queryset = Profile.objects.exclude(friends='anonymous')
autocomplete.register(Profile.friends, UserAutocomplete)
But this will not exclude the current user. To get that you will have override/extend the view method of your ProfileAutocomplete class. In this method you will need to get the user ID (probably from the session) and then exclude it from the queryset. If using the session is not working (it's possible, I didn't put too much time on it), you 'll probably have to modify the jquery_autocomplete.js script to pass the user to the view method.
Django raw_id_fields don't display tables the way I expect, am I doing something wrong? I'm trying to use a raw_id_fields widget to edit a ForeignKey field as follows:
#models.py
class OrderLine(models.Model):
product = ForeignKey('SternProduct')
class SternProduct(models.Model):
def __unicode__(self): return self.product_num
product_num = models.CharField(max_length=255)
#admin.py
#import and register stuff
class OrderLineAdmin(admin.ModelAdmin):
raw_id_fields=('product')
I get the little textbox and magnifier widget as expected, but clicking the magnifier gives me this:
flickr.com/photos/28928816#N00/5244376512/sizes/o/in/photostream/
(sorry, can't post more than one hyperlink apparently)
I thought I would get something closer to the changelist page c/w columns, filters and search fields. In fact, that's apparently what others get.
Any thoughts about how to enable the more featureful widget?
Ah, OK, this should have been obvious, but it isn't explained in the Django docs. The list that appears in the raw_id_fields popup uses the same options as the admin object for the referenced model. So in my example, to get a nice looking popup I needed to create a SternProductAdmin object as follows:
class SternProductAdmin(admin.ModelAdmin):
list_display = ('__unicode__', 'drawing_number', 'drawing_revision',)
list_filter = ('drawing_number',)
search_fields = ('drawing_number',)
actions = None
Hopefully this will help others in the future.