{ "info": { "author": "Yin KangHong", "author_email": "614457662@qq.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 3 - Alpha", "Environment :: Web Environment", "Framework :: Django", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python :: 3", "Topic :: Software Development :: Libraries" ], "description": "## django-popup-field\nA popup field for django which can create\u9286\u4e7dpdate\u9286\u4e68elete `ForeignKey` and `ManyToManyField` instance by popup windows.\n\n### Requirements\n- Python3\n- Django\n\n### Demo\n\nYou can get this demo at [popup.yinkh.top](http://popup.yinkh.top)\n\n![popup demo](https://www.yinkh.top/media/summer_note/20180515-170605-512.gif)\n\n### TODO\n- internationalization\n- optimize action in form\n- css override\n\n### QuickStart\n\n1. Install `django-popup-field` with pip:\n\n pip install django-popup-field\n\n2. Install the dependencies `django-popup-field` to `INSTALLED_APPS` in your project's `settings.py`:\n\n INSTALLED_APPS = [\n ...\n 'popup_field',\n ...\n ]\n3. Assume I have a post app which `models.py` is:\n\n\t class Category(models.Model):\n\t name = models.CharField(max_length=255, verbose_name='name')\n\n\t ...\n\n\n\t class Tag(models.Model):\n\t name = models.CharField(max_length=255, verbose_name='name')\n\n\t ...\n\n\n\t class Post(models.Model):\n\t title = models.CharField(max_length=255, verbose_name='title')\n\t category = models.ForeignKey('post.Category', related_name='post_category', on_delete=models.CASCADE,\n\t verbose_name='category')\n\t tags = models.ManyToManyField('post.Tag',\n\t verbose_name='tags')\n\t ...\n\n\tNew `popups.py` in post app,the content is:\n\n\t from popup_field.views import PopupCRUDViewSet\n\n\t from .models import *\n\n\n\t class CategoryForm(forms.ModelForm):\n\t\t class Meta:\n\t\t model = Category\n\t\t fields = ['name']\n\n\n\t class TagForm(forms.ModelForm):\n\t\t class Meta:\n\t\t model = Tag\n\t\t fields = ['name']\n\n\n\t class CategoryPopupCRUDViewSet(PopupCRUDViewSet):\n\t\t model = Category\n\t\t form_class = CategoryForm\n\t\t template_name_create = 'popup/create.html'\n\t\t template_name_update = 'popup/update.html'\n\n\t class TagPopupCRUDViewSet(PopupCRUDViewSet):\n\t\t model = Tag\n\t\t form_class = TagForm\n\t\t template_name_create = 'popup/create.html'\n\t\t template_name_update = 'popup/update.html'\n\n\n4. Change widget for category and tag used in `forms.py`:\n\n from django import forms\n\t from .popups import CategoryPopupCRUDViewSet, TagPopupCRUDViewSet\n\n\t from .models import *\n\n\n\t class PostForm(forms.ModelForm):\n\n\t\t class Meta:\n\t\t\t model = Post\n\t\t\t fields = ['title', 'category', 'tags']\n\t\t\t widgets = {\n\t\t\t\t 'category': CategoryPopupCRUDViewSet.get_fk_popup_field(),\n\t\t\t\t 'tags': TagPopupCRUDViewSet.get_m2m_popup_field(),\n\t\t\t }\n\n5. Custom your popup template, `popup/create.html`:\n\n {% extends \"popup/base.html\" %}\n {% block css %}\n {% endblock %}\n\n {% block js %}\n {% endblock %}\n\n {% block main %}\n
\n
\n\n {% csrf_token %}\n {{ form.media }}\n {{ form }}\n\n
\n
\n \n
\n
\n
\n
\n {% endblock %}\n\n `popup/update.html`:\n\n {% extends \"popup/base.html\" %}\n\n {% block css %}\n {% endblock %}\n\n {% block js %}\n {% endblock %}\n\n {% block main %}\n
\n
\n {% csrf_token %}\n {{ form.media }}\n {{ form }}\n\n
\n
\n \n
\n
\n
\n
\n {% endblock %}\n\n\tThe `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 %}\"`.\n6. All url for popup create\\update\\delete is generate by `PopupCRUDViewSet`, `urls.py` :\n\n\t\tfrom .views import *\n\n\t\turlpatterns = [\n\t\t path('', PostCreateView.as_view(), name='post_create'),\n\n\t\t CategoryPopupCRUDViewSet.urls(),\n\t\t TagPopupCRUDViewSet.urls(),\n\t\t]\n\n\tthis will register the following urls:\n\n\t\tpath('category/', include([\n\t path('popup/', cls.create(), name='category_popup_create'),\n\t path('popup//', cls.update(), name='category_popup_update'),\n\t path('popup/delete//', cls.delete(), name='category_popup_delete'),\n\t ])\n\n\t\tpath('tag/', include([\n\t path('popup/', cls.create(), name='tag_popup_create'),\n\t path('popup//', cls.update(), name='tag_popup_update'),\n\t path('popup/delete//', cls.delete(), name='tag_popup_delete'),\n\t ])\n\n### Advance\n#### Set default `template_name_create` and `template_name_update`\n`template_name_create` is the template used for create popup window, `template_name_update` is the template used for update popup window.\n\nYou can set default `template_name_create` and `template_name_update` in settings like:\n\n POPUP_TEMPLATE_NAME_CREATE = 'popup/create.html'\n POPUP_TEMPLATE_NAME_UPDATE = 'popup/update.html'\n\n`PopupCRUDViewSet` will use this as default `template_name_create` and `template_name_update` if you don't have a special assignment in `PopupCRUDViewSet`.\n\n#### Override template for `PopupCreateView` and `PopupUpdateView` in `PopupCRUDViewSet`\n class CategoryPopupCRUDViewSet(PopupCRUDViewSet):\n\t ...\n\t template_name_create = 'popup/create.html'\n\t template_name_update = 'popup/update.html'\n\n class TagPopupCRUDViewSet(PopupCRUDViewSet):\n\t ...\n\t template_name_create = 'popup/create.html'\n\t template_name_update = 'popup/update.html'\n\n\n#### Override template for `ForeignKeyWidget` and `ManyToManyWidget`\nIf you want override template used by `ForeignKeyWidget` and `ManyToManyWidget`,you have to way to achieve this,first one is:\n\n\tclass PopupCRUDViewSet(object):\n\t ...\n\t template_name_fk = 'popup/foreign_key_select.html'\n\t template_name_m2m = 'popup/many_to_many_select.html'\nsecond one is:\n\n class PostForm(forms.ModelForm):\n ...\n\n class Meta:\n model = Post\n fields = ['title', 'category', 'tags']\n widgets = {\n 'category':CategoryPopupCRUDViewSet.get_fk_popup_field(template_name='popup/foreign_key_select.html')\n 'tags': TagPopupCRUDViewSet.get_m2m_popup_field(template_name='popup/many_to_many_select.html'),\n }\n\n#### Set parent class for `PopupCreateView\u9286\u4e33opupUpdateView\u9286\u4e33opupDeleteView` in `PopupCRUDViewSet`\nYou can set parent class for `PopupCreateView\u9286\u4e33opupUpdateView\u9286\u4e33opupDeleteView` in `PopupCRUDViewSet` like:\n\n\tclass IsStaffUserMixin(AccessMixin):\n\t \"\"\"\n\t request must be staff\n\t \"\"\"\n\t raise_exception = True\n\t permission_denied_message = 'You are not a staff'\n\n\t def dispatch(self, request, *args, **kwargs):\n\t if not request.user.is_staff:\n\t return self.handle_no_permission()\n\t return super(IsStaffUserMixin, self).dispatch(request, *args, **kwargs)\n\n\tclass CategoryPopupCRUDViewSet(PopupCRUDViewSet):\n\t model = Category\n\t form_class = CategoryForm\n\t parent_class = IsStaffUserMixin\n\n\tclass TagPopupCRUDViewSet(PopupCRUDViewSet):\n\t model = Tag\n\t form_class = TagForm\n\t parent_class = IsStaffUserMixin\n\nThe usage is set common permission check for `PopupCreateView\u9286\u4e33opupUpdateView\u9286\u4e33opupDeleteView`. In demo we will check whether the operator is a staff.\n\n#### Permission check for create\u9286\u4e7dpdate\u9286\u4e68elete button\nYou 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.\n\nIf you want check permissions for popup fields, demo is here:\n\n`popups.py` should like:\n\n class CategoryPopupCRUDViewSet(PopupCRUDViewSet):\n\t model = Category\n\t form_class = CategoryForm\n\t template_name_create = 'popup/create.html'\n\t template_name_update = 'popup/update.html'\n\t permissions_required = {\n\t 'create': ('post.add_category',),\n\t 'update': ('post.update_category',),\n\t 'delete': ('post.delete_category',)\n\t }\n\n\n`views.py` should like:\n\n\n class PostCreateView(CreateView):\n raise_exception = True\n form_class = PostForm\n template_name = 'post/create.html'\n success_url = reverse_lazy('post_create')\n\n def get_form_kwargs(self):\n kwargs = super(PostCreateView, self).get_form_kwargs()\n kwargs['request'] = self.request\n return kwargs\n\nThe `request` kwarg passed to `form` is used for perms check.\n\n`forms.py` should like:\n\n class PostForm(forms.ModelForm):\n\t def __init__(self, *args, **kwargs):\n\t request = kwargs.pop('request')\n\t super(PostForm, self).__init__(*args, **kwargs)\n\t self.fields['category'].widget.request = request\n\t self.fields['tags'].widget.request = request\n\n\t\t...\n\n#### Custom context for create and update\n\n\tclass CategoryPopupCRUDViewSet(PopupCRUDViewSet):\n\t model = Category\n\t form_class = CategoryForm\n context_for_create = {'operation': 'create'}\n\t context_for_update = {'operation': 'update'}\n\n#### Custom popup title and url name\nThe default popup title is `operation+model's verbose_name`,you can custom `model's verbose_name` with:\n\n\tclass CategoryPopupCRUDViewSet(PopupCRUDViewSet):\n\t class_verbose_name = 'Custom Category'\n\nThe default url name is `model name's lower case+_popup_+operation`,you can custom `model name's lower case` with:\n\n\tclass CategoryPopupCRUDViewSet(PopupCRUDViewSet):\n\t class_name = 'custom_category'\n\n### v 0.1.0\n- take create\u9286\u4e7dpdate and delete to viewset\n\n### v 0.1.1\n- add gif and demo site\n\n### v 0.1.2\n- allow custom template_name for popup_field\n\n### v 0.1.3\n- compatible with django 1.x\n- change viewset achieve logic\n\n### v 0.1.4\n- add default POPUP_TEMPLATE_NAME_CREATE\u9286\u4e33OPUP_TEMPLATE_NAME_UPDATE in setting\n- add template_name_fk\u9286\u4e7cemplate_name_m2m in PopupCRUDViewSet\n- add parent_class in PopupCRUDViewSet\n\n### v 0.1.5\n- add class_name\u9286\u4e67lass_verbose_name in PopupCRUDViewSet\n- remove popup_name inside create and update url\n- custom context for create and update\n- custom popup title and url name\n\n### v 0.1.6\n- add context_for_all in PopupCRUDViewSet\n\n", "description_content_type": "", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/yinkh/django-popup-field.git", "keywords": "django-popup-field", "license": "BSD 3-Clause License", "maintainer": "", "maintainer_email": "", "name": "django-popup-field", "package_url": "https://pypi.org/project/django-popup-field/", "platform": "", "project_url": "https://pypi.org/project/django-popup-field/", "project_urls": { "Homepage": "https://github.com/yinkh/django-popup-field.git" }, "release_url": "https://pypi.org/project/django-popup-field/0.1.6/", "requires_dist": null, "requires_python": "", "summary": "A popup field for django which can create\\update\\delete ForeignKey and ManyToManyField instance by popup windows.", "version": "0.1.6" }, "last_serial": 4271469, "releases": { "0.1.0": [ { "comment_text": "", "digests": { "md5": "792f3d6e732401d67aa03fbbb0f060ce", "sha256": "3a13333df1bc52899d6021d3a8fde0e7d17ae09f7d87a9b9f1e77c6c5618a6a1" }, "downloads": -1, "filename": "django_popup_field-0.1.0-py3-none-any.whl", "has_sig": false, "md5_digest": "792f3d6e732401d67aa03fbbb0f060ce", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 6686, "upload_time": "2018-05-15T06:05:46", "url": "https://files.pythonhosted.org/packages/52/b6/00b71c5a103c80e2984aa082307603f20dfd572474154c4ee0d3c166bbe1/django_popup_field-0.1.0-py3-none-any.whl" } ], "0.1.1": [ { "comment_text": "", "digests": { "md5": "27132799f050d0639f8c8a204c34ae29", "sha256": "32f160a2d228969aaeb22a0d8700bb5e233ee53a5a295c3c519e8393eb5b49b9" }, "downloads": -1, "filename": "django_popup_field-0.1.1-py3-none-any.whl", "has_sig": false, "md5_digest": "27132799f050d0639f8c8a204c34ae29", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 82283, "upload_time": "2018-05-15T06:10:47", "url": "https://files.pythonhosted.org/packages/b5/d1/f34ebc7d34382446f3ae35621a412e4605ef5ebcd664cd4e007466050a9e/django_popup_field-0.1.1-py3-none-any.whl" } ], "0.1.2": [ { "comment_text": "", "digests": { "md5": "8b9bc1f2be7ad578260d9f12528fa39f", "sha256": "cc5fe047b3b1b094ac7988d4fc3ed60aaf291af395432d07460413001db8feb6" }, "downloads": -1, "filename": "django_popup_field-0.1.2-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "8b9bc1f2be7ad578260d9f12528fa39f", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 83294, "upload_time": "2018-09-11T06:07:15", "url": "https://files.pythonhosted.org/packages/28/22/9590cf777ccd2476de3b7667a84efe67edbe7aa6ec6124c19c7160fa782a/django_popup_field-0.1.2-py2.py3-none-any.whl" } ], "0.1.3": [ { "comment_text": "", "digests": { "md5": "faa6bdeec0021347b003f5227ec08ee9", "sha256": "902fa29199805349114d675b90d2152689d835588db902869f0e109eeffe30f0" }, "downloads": -1, "filename": "django_popup_field-0.1.3-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "faa6bdeec0021347b003f5227ec08ee9", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 82482, "upload_time": "2018-09-12T09:00:02", "url": "https://files.pythonhosted.org/packages/b2/dc/1ba85a6dcec3102e9e7dd22da4540c38c984c20aaa04f47051ea52b35ceb/django_popup_field-0.1.3-py2.py3-none-any.whl" } ], "0.1.4": [ { "comment_text": "", "digests": { "md5": "b8ca78d21f1c8988cb4bbfe3b438620d", "sha256": "f3a322c96301148ed306bd1869a7b46504d1cf623f87c194bd03a89ee7538a69" }, "downloads": -1, "filename": "django_popup_field-0.1.4-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "b8ca78d21f1c8988cb4bbfe3b438620d", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 83287, "upload_time": "2018-09-14T02:34:55", "url": "https://files.pythonhosted.org/packages/de/74/65cfd92269485385c641f0df70eb5241b40e96d3a801b87a4b28ffcf5160/django_popup_field-0.1.4-py2.py3-none-any.whl" } ], "0.1.5": [ { "comment_text": "", "digests": { "md5": "2084b52139e0584854121bb93ccb78af", "sha256": "037cd2203f8a9a3a9046e9809840e1bb88346a20e1fe1efd2900ef1d91bbcf47" }, "downloads": -1, "filename": "django_popup_field-0.1.5-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "2084b52139e0584854121bb93ccb78af", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 83645, "upload_time": "2018-09-14T07:32:21", "url": "https://files.pythonhosted.org/packages/15/2c/120aeba313e8d6c164e0d5d1705b50d40968c4ba93ef07c0960c56025fa7/django_popup_field-0.1.5-py2.py3-none-any.whl" } ], "0.1.6": [ { "comment_text": "", "digests": { "md5": "e986b5755403ba9652298ee6b04f7f13", "sha256": "01706627d4654f98d900005f8b226beceac2555078e512888c2293dffa75ad46" }, "downloads": -1, "filename": "django_popup_field-0.1.6-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "e986b5755403ba9652298ee6b04f7f13", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 83666, "upload_time": "2018-09-14T08:25:50", "url": "https://files.pythonhosted.org/packages/4b/f4/d9ab445577c89fe1a5b1c0c7a6332f4ef110fcc50917f698de350322ab2e/django_popup_field-0.1.6-py2.py3-none-any.whl" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "e986b5755403ba9652298ee6b04f7f13", "sha256": "01706627d4654f98d900005f8b226beceac2555078e512888c2293dffa75ad46" }, "downloads": -1, "filename": "django_popup_field-0.1.6-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "e986b5755403ba9652298ee6b04f7f13", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": null, "size": 83666, "upload_time": "2018-09-14T08:25:50", "url": "https://files.pythonhosted.org/packages/4b/f4/d9ab445577c89fe1a5b1c0c7a6332f4ef110fcc50917f698de350322ab2e/django_popup_field-0.1.6-py2.py3-none-any.whl" } ] }