
Security News
MCP Community Begins Work on Official MCP Metaregistry
The MCP community is launching an official registry to standardize AI tool discovery and let agents dynamically find and install MCP servers.
A popup field for django which can create\update\delete ForeignKey and ManyToManyField instance by popup windows.
A popup field for django which can create銆乽pdate銆乨elete ForeignKey
and ManyToManyField
instance by popup windows.
You can get this demo at popup.yinkh.top
Install django-popup-field
with pip:
pip install django-popup-field
Install the dependencies django-popup-field
to INSTALLED_APPS
in your project's settings.py
:
INSTALLED_APPS = [
...
'popup_field',
...
]
Assume I have a post app which models.py
is:
class Category(models.Model):
name = models.CharField(max_length=255, verbose_name='name')
...
class Tag(models.Model):
name = models.CharField(max_length=255, verbose_name='name')
...
class Post(models.Model):
title = models.CharField(max_length=255, verbose_name='title')
category = models.ForeignKey('post.Category', related_name='post_category', on_delete=models.CASCADE,
verbose_name='category')
tags = models.ManyToManyField('post.Tag',
verbose_name='tags')
...
New popups.py
in post app,the content is:
from popup_field.views import PopupCRUDViewSet
from .models import *
class CategoryForm(forms.ModelForm):
class Meta:
model = Category
fields = ['name']
class TagForm(forms.ModelForm):
class Meta:
model = Tag
fields = ['name']
class CategoryPopupCRUDViewSet(PopupCRUDViewSet):
model = Category
form_class = CategoryForm
template_name_create = 'popup/create.html'
template_name_update = 'popup/update.html'
class TagPopupCRUDViewSet(PopupCRUDViewSet):
model = Tag
form_class = TagForm
template_name_create = 'popup/create.html'
template_name_update = 'popup/update.html'
Change widget for category and tag used in forms.py
:
from django import forms
from .popups import CategoryPopupCRUDViewSet, TagPopupCRUDViewSet
from .models import *
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = ['title', 'category', 'tags']
widgets = {
'category': CategoryPopupCRUDViewSet.get_fk_popup_field(),
'tags': TagPopupCRUDViewSet.get_m2m_popup_field(),
}
Custom your popup template, popup/create.html
:
{% extends "popup/base.html" %}
{% block css %}
{% endblock %}
{% block js %}
{% endblock %}
{% block main %}
<div class="layui-container" style="margin: 4px">
<form class="layui-form" enctype="multipart/form-data"
action="{{ request.path }}{% if to_field %}?to_field={{ to_field }}{% endif %}"
method="post">
{% csrf_token %}
{{ form.media }}
{{ form }}
<div class="layui-form-item">
<div class="layui-input-block">
<button class="layui-btn">Add</button>
</div>
</div>
</form>
</div>
{% endblock %}
popup/update.html
:
{% extends "popup/base.html" %}
{% block css %}
{% endblock %}
{% block js %}
{% endblock %}
{% block main %}
<div class="layui-container" style="margin: 4px">
<form class="layui-form" enctype="multipart/form-data"
action="{{ request.path }}{% if to_field %}?to_field={{ to_field }}{% endif %}"
method="post">
{% csrf_token %}
{{ form.media }}
{{ form }}
<div class="layui-form-item">
<div class="layui-input-block">
<button class="layui-btn">Edit</button>
</div>
</div>
</form>
</div>
{% endblock %}
The object_name
inside template always is popup
.The point is you must append {% if to_field %}?to_field={{ to_field }}{% endif %}
in form action or keep set as "{{ request.path }}{% if to_field %}?to_field={{ to_field }}{% endif %}"
.
All url for popup create\update\delete is generate by PopupCRUDViewSet
, urls.py
:
from .views import *
urlpatterns = [
path('', PostCreateView.as_view(), name='post_create'),
CategoryPopupCRUDViewSet.urls(),
TagPopupCRUDViewSet.urls(),
]
this will register the following urls:
path('category/', include([
path('popup/', cls.create(), name='category_popup_create'),
path('popup/<int:pk>/', cls.update(), name='category_popup_update'),
path('popup/delete/<int:pk>/', cls.delete(), name='category_popup_delete'),
])
path('tag/', include([
path('popup/', cls.create(), name='tag_popup_create'),
path('popup/<int:pk>/', cls.update(), name='tag_popup_update'),
path('popup/delete/<int:pk>/', cls.delete(), name='tag_popup_delete'),
])
template_name_create
and template_name_update
template_name_create
is the template used for create popup window, template_name_update
is the template used for update popup window.
You can set default template_name_create
and template_name_update
in settings like:
POPUP_TEMPLATE_NAME_CREATE = 'popup/create.html'
POPUP_TEMPLATE_NAME_UPDATE = 'popup/update.html'
PopupCRUDViewSet
will use this as default template_name_create
and template_name_update
if you don't have a special assignment in PopupCRUDViewSet
.
PopupCreateView
and PopupUpdateView
in PopupCRUDViewSet
class CategoryPopupCRUDViewSet(PopupCRUDViewSet):
...
template_name_create = 'popup/create.html'
template_name_update = 'popup/update.html'
class TagPopupCRUDViewSet(PopupCRUDViewSet):
...
template_name_create = 'popup/create.html'
template_name_update = 'popup/update.html'
ForeignKeyWidget
and ManyToManyWidget
If you want override template used by ForeignKeyWidget
and ManyToManyWidget
,you have to way to achieve this,first one is:
class PopupCRUDViewSet(object):
...
template_name_fk = 'popup/foreign_key_select.html'
template_name_m2m = 'popup/many_to_many_select.html'
second one is:
class PostForm(forms.ModelForm):
...
class Meta:
model = Post
fields = ['title', 'category', 'tags']
widgets = {
'category':CategoryPopupCRUDViewSet.get_fk_popup_field(template_name='popup/foreign_key_select.html')
'tags': TagPopupCRUDViewSet.get_m2m_popup_field(template_name='popup/many_to_many_select.html'),
}
PopupCreateView銆丳opupUpdateView銆丳opupDeleteView
in PopupCRUDViewSet
You can set parent class for PopupCreateView銆丳opupUpdateView銆丳opupDeleteView
in PopupCRUDViewSet
like:
class IsStaffUserMixin(AccessMixin):
"""
request must be staff
"""
raise_exception = True
permission_denied_message = 'You are not a staff'
def dispatch(self, request, *args, **kwargs):
if not request.user.is_staff:
return self.handle_no_permission()
return super(IsStaffUserMixin, self).dispatch(request, *args, **kwargs)
class CategoryPopupCRUDViewSet(PopupCRUDViewSet):
model = Category
form_class = CategoryForm
parent_class = IsStaffUserMixin
class TagPopupCRUDViewSet(PopupCRUDViewSet):
model = Tag
form_class = TagForm
parent_class = IsStaffUserMixin
The usage is set common permission check for PopupCreateView銆丳opupUpdateView銆丳opupDeleteView
. In demo we will check whether the operator is a staff.
You can set permissions_required
in CategoryPopupCRUDViewSet
for different operation, if the operator don't has corresponding permissions,then the corresponding button will be hide and the corresponding view will ask this permission when operation.
If you want check permissions for popup fields, demo is here:
popups.py
should like:
class CategoryPopupCRUDViewSet(PopupCRUDViewSet):
model = Category
form_class = CategoryForm
template_name_create = 'popup/create.html'
template_name_update = 'popup/update.html'
permissions_required = {
'create': ('post.add_category',),
'update': ('post.update_category',),
'delete': ('post.delete_category',)
}
views.py
should like:
class PostCreateView(CreateView):
raise_exception = True
form_class = PostForm
template_name = 'post/create.html'
success_url = reverse_lazy('post_create')
def get_form_kwargs(self):
kwargs = super(PostCreateView, self).get_form_kwargs()
kwargs['request'] = self.request
return kwargs
The request
kwarg passed to form
is used for perms check.
forms.py
should like:
class PostForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
request = kwargs.pop('request')
super(PostForm, self).__init__(*args, **kwargs)
self.fields['category'].widget.request = request
self.fields['tags'].widget.request = request
...
class CategoryPopupCRUDViewSet(PopupCRUDViewSet):
model = Category
form_class = CategoryForm
context_for_create = {'operation': 'create'}
context_for_update = {'operation': 'update'}
The default popup title is operation+model's verbose_name
,you can custom model's verbose_name
with:
class CategoryPopupCRUDViewSet(PopupCRUDViewSet):
class_verbose_name = 'Custom Category'
The default url name is model name's lower case+_popup_+operation
,you can custom model name's lower case
with:
class CategoryPopupCRUDViewSet(PopupCRUDViewSet):
class_name = 'custom_category'
FAQs
A popup field for django which can create\update\delete ForeignKey and ManyToManyField instance by popup windows.
We found that django-popup-field demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
The MCP community is launching an official registry to standardize AI tool discovery and let agents dynamically find and install MCP servers.
Research
Security News
Socket uncovers an npm Trojan stealing crypto wallets and BullX credentials via obfuscated code and Telegram exfiltration.
Research
Security News
Malicious npm packages posing as developer tools target macOS Cursor IDE users, stealing credentials and modifying files to gain persistent backdoor access.