I have a Django 3.x web site. There are 3 models, among others, Document, MetaData, MetaDataValue. The MetaDataValue model has a foreign key relationship to the MetaData model.
In a simple world, there would be a foreign key relationship from MetaData to Document. Then the DocumentAdmin would display the MetaData field as a dropdown, filled with the appropriate MetaDataValues. There would also be edit/add (pencil/plus) links next to the dropdown to allow the user to edit/add the MetaDataValue for that MetaData object.
However, one of the requirements for the project was not to define which, or how many, MetaData objects would be associated with a particular Document type until run time. Those associations are through another set of models. Therefore, the Document admin change page adds the different MetaData fields to the change admin page at run time, by looking into the database for which MetaData fields are associated with this type of Document, and then adding them to the fieldset through the get_fieldsets method.
The implication of this design is that one cannot edit/add values to a particular MetaData field on the Document admin change page, because, I assume, Django lost the underlying foreign key relationship between the Document and MetaData models because the fieldset is generated in the admin's get_fieldsets method.
I could add pages of code to show how the MetaData fields are generated at run time, but I don't think that would make the description any clearer. I have looked at the page source and fieldsets generated for the "simple world" example described above above, and cannot see where Django is figuring out when to add the edit/change links to the drop down for a particular foreign key field.
My question, is how can I add the pencil and plus sign to these MetaData fields displayed in the Document admin change page, and give the user to option to add/edit the MetaDataValue for that particular MetaData object? I could just create some Ajax calls and do all the heavy lifting myself, bu I would prefer to leverage as much of the Django infrastructure as possible, and not reinvent more than I have to.
Thanks!
Mark
I found a solution using the RelatedFieldWidgetWrapper. I added this widget wrapper to all my selects that needed the green plus (add) and yellow pencil (edit).
There is too much code to post here, but here is the meat of it. My db table MetaData has the names of all the fields, and MetaDataValue has the values for each metadata field. The metadata is used to describe a document (text, video, image), but there are no FK relationships between the MetaData model and the Document model. The relationship between the metadata and the documents is contained in a JSON field in another table. The MetaData table also has what type of Django field is used for that metadata field. There is also another table that determines which metadata fields apply to which document type (image, text, video). For all the ModelChoiceFields, I add the field and the widget (Select wrapped in a RelatedFieldWidgetWrapper).
elif (metadata_names[i].field_type == MetaData.MODELCHOICEFIELD):
fields[metadata_names[i].name] = forms.ModelChoiceField(queryset=MetaDataValue.objects.filter(metadata_id=metadata_names[i].metadata_id).order_by('value'), required=False, label=metadata_names[i].label, help_text=metadata_names[i].help_text)
# add the green plus (add) and pencil (edit) links to each select field
fields[metadata_names[i].name].widget = RelatedFieldWidgetWrapper(fields[metadata_names[i].name].widget, MetaDataValue._meta.get_field('tag_value'), admin_site, can_add_related=True, can_change_related=True)
if 'documentType_id' in fields:
# Editing/add a new document type seems like a bad idea, as document type is used a lot in the processing logic
fields['documentType_id'].widget.can_add_related = False
fields['documentType_id'].widget.can_change_related = False
The hard part was getting the right arguments for the RelatedFieldWidgetWrapper. The documentation is a little sparse on that widget, because, I think, it was an early part of the admin, but much of the Django code has changed since it was first implemented, so a lot of ways this wrapper was used in the past (ie stack overflow posts) has been deprecated. I just looked at the source, and tried what seemed to be appropriate until it worked. Finally, these articles helped a lot:
RelatedFieldWidgetWrapper
More RelatedFieldWidgetWrapper – My Very Own Popup
How can I remove the add and change buttons from a TabularInline admin field?
I spent two hours trying to find out how to customize select2 widget in Django admin to implement this simple feature.
I have a model (Article) that contains many other objects (Pictures). Every Picture has a set of FileFields representing the original image file, the thumbnail, post-processed (using Pillow) preview and some meta stuff.
What I'm going to achieve is to be able to upload new images on the Article change page, and select/deselect them in the fancy Select2 dropdown widget.
How can I do that? Should I use ImageField instead of FileField? Should I use inlines and through for ManyToMany relation between Article and Pictures? Should I make my own widget? How do Django admin uses Select2 and how could I pass parameters like "templateResult" to be able to change the look of dropdown items?
Thank you in advance.
When and where should I use wagtail pages and when should I write my custom urls and views using django? for example should I create pages for user profiles or should I add a urlpattern for profile and write profile logic in a django view?
This question is pretty broad and it depends a lot on what you are trying to achieve, but here are some thoughts.
General Approach
Use Wagtail pages if your pages have CMS (user) editable content and need to be placed (and easily moved) within the main page tree along with other editable pages.
If a page is not editable and URL must be fixed, it might be best to approach this either with Django URLs and views. Eg. Sitemap or Search page.
The docs cover how to set up mixed URLs in Integrating into Django.
Specific Use Case - User Profiles
You could create a Wagtail page model like UserProfileIndex which could contain some CMS editable content about that page such as body text and images.
This assumes you are wanting to make a social media type index and page for each user.
Then use RoutablePageMixin to have the URLs for each individual profile page.
Sometimes this index page thinking can come in handy, it let's you change the root URL but puts the logic for sub-urls within the model.
Remember that this means CMS users could technically change the slug of this page, unless it is locked down.
If you are trying to create a user profile page that is more suited for a user to manage their profile then it would probably best to use Django view.
I'm new using Mezzanine and figured out how to set-up pages where I can manage content from Admin page.
But I have static pages, where I want to store some content and being able to control that content from Admin page.
Is this something I can do with Mezzanine?
I imagine that I need to create a model with richtext field add that model to admin interface and than somehow access to that model through templatage.
But any exact example would greatly appreciated.
Thanks!
See the docs on creating custom content types. The primary approach is to subclass the Page model and add your custom fields.
Alternatively, if your custom content is conceptually independent from your pages, it might make sense to create independent models with relational fields to the RichTextPage model and edit them through inlines.
Note that the mezzanine docs on custom content types and the django docs on inlines use the same author/book example so you can easily compare the two strategies.
Is there a good way to implement editing of a PlaceholderField before the model is added to an app?
I have an app with an apphook, and at present one has to create the model in the admin interface, save it (causing it to appear on the website), and then add the CMS content to the already-visible rendering of the model. Clearly this isn't very good.
Ideally I would like to be able to create the Placeholder content 'inline' along with the rest of the model.
What would be the best way to go about this? Is there an existing method, or do I hack the admin interface and the model's save method using the CMS API?
Thanks