معرفی شرکت ها


django-smarter-1.1


Card image cap
تبلیغات ما

مشتریان به طور فزاینده ای آنلاین هستند. تبلیغات می تواند به آنها کمک کند تا کسب و کار شما را پیدا کنند.

مشاهده بیشتر
Card image cap
تبلیغات ما

مشتریان به طور فزاینده ای آنلاین هستند. تبلیغات می تواند به آنها کمک کند تا کسب و کار شما را پیدا کنند.

مشاهده بیشتر
Card image cap
تبلیغات ما

مشتریان به طور فزاینده ای آنلاین هستند. تبلیغات می تواند به آنها کمک کند تا کسب و کار شما را پیدا کنند.

مشاهده بیشتر
Card image cap
تبلیغات ما

مشتریان به طور فزاینده ای آنلاین هستند. تبلیغات می تواند به آنها کمک کند تا کسب و کار شما را پیدا کنند.

مشاهده بیشتر
Card image cap
تبلیغات ما

مشتریان به طور فزاینده ای آنلاین هستند. تبلیغات می تواند به آنها کمک کند تا کسب و کار شما را پیدا کنند.

مشاهده بیشتر

توضیحات

Smarter declarative style generic views for Django.
ویژگی مقدار
سیستم عامل -
نام فایل django-smarter-1.1
نام django-smarter
نسخه کتابخانه 1.1
نگهدارنده []
ایمیل نگهدارنده []
نویسنده Alexey Kinyov
ایمیل نویسنده rudy@05bit.com
آدرس صفحه اصلی https://github.com/05bit/django-smarter
آدرس اینترنتی https://pypi.org/project/django-smarter/
مجوز BSD
django-smarter ============== Another approach for declarative style generic views for Django. I beleive, it's a bit smarter :) Overview -------- So many times we have to write: .. sourcecode:: python @login_required def edit_post(request, pk): post = get_object_or_404(Post, pk=pk) if request.method == 'POST': form = EditPostForm(request.POST, instance=post) if form.is_valid(): post = form.save() return redirect(post.get_absolute_url()) else: form = EditPostForm() return render(request, 'edit_post.html', {'form': form}) Right? Well, it's ok to write some reusable helpers for such repeatable views, but when we don't need sophisticated ones here we go: .. sourcecode:: python class PostViews(smarter.GenericViews): model = Post options = { 'add': { 'form': NewPostForm, 'decorators': (login_required,) }, 'edit': { 'form': EditPostForm, 'decorators': (login_required,) }, 'remove': { 'decorators': (login_required,) } } That's it. Changes in v1.0 --------------- API is finally and completely changed since v0.6 release. We've made a "quantum jump" by breaking old-and-not-so-good API to new one - solid and nice. Hope you'll like it. Here are `some hints that may help you with migration <https://django-smarter.readthedocs.org/en/latest/migrate_0.x_to_1.0.html>`_. I'm actually successfully migrated my real-production project, so the hints are based on "real-battle" example. Contributors ------------ * `Fabio Santos <https://github.com/fabiosantoscode>`_ * `Sameer Al-Sakran <https://github.com/salsakran>`_ Thank you, comrades! :) Installation ------------ Requirements: - Django >= 1.4 Installation:: pip install django-smarter You *may* add ``smarter`` to your ``INSTALLED_APPS`` to get default templates and tests, but you *don't have to*: .. sourcecode:: python INSTALLED_APPS = ( # ... 'smarter', # ... ) Then you should define your views and include them in URLs, see `Getting started`_ section below. Getting started --------------- Create your models ~~~~~~~~~~~~~~~~~~ Let’s define a simple model: .. sourcecode:: python class Page(models.Model): owner = models.ForeignKey('auth.User') title = models.CharField(max_length=100) text = models.TextField() def __unicode__(self): return self.title Register views ~~~~~~~~~~~~~~ Now you can add generic views for the model. In your `urls.py`: .. sourcecode:: python import smarter from myapp.models import Page site = smarter.Site() site.register(smarter.GenericViews, Page) urlpatterns = patterns('', url(r'^', include(site.urls)), # other urls ... ) This code creates generic views for ``Page`` model, accessed by urls: - /page/ - /page/add/ - /page/``<pk>``/ - /page/``<pk>``/edit/ - /page/``<pk>``/remove/ Customize views ~~~~~~~~~~~~~~~ Subclass from ``smarter.GenericViews`` and set custom options and/or override methods. .. sourcecode:: python from django.contrib.auth.decorators import login_required import smarter from .models import Page class PageViews(smarter.GenericViews): model = Page options = { 'add': { 'decorators': (login_required,) 'exclude': ('owner',) }, } def add__save(self, request, form, **kwargs): obj = form.save(commit=False) obj.owner = request.user obj.save() return obj And don't forget to register new views in `urls.py`: .. sourcecode:: python import smarter from myapp.views import PageViews site = smarter.Site() site.register(PageViews) # model argument is not required as model is already set in PageViews urlpatterns = patterns('', url(r'^', include(site.urls)), ) Customize templates ~~~~~~~~~~~~~~~~~~~ In the example above each URL by default to template. ====================== ======================= ===================== URL Template Context ====================== ======================= ===================== /page/ myapp/page/index.html {{ objects_list }} /page/add/ myapp/page/add.html {{ obj }}, {{ form }} /page/``<pk>``/ myapp/page/details.html {{ obj }} /page/``<pk>``/edit/ myapp/page/edit.html {{ obj }}, {{ form }} /page/``<pk>``/remove/ myapp/page/remove.html {{ obj }} ====================== ======================= ===================== Default template search paths are: .. sourcecode:: python ('%(app)s/%(model)s/%(action)s.html', '%(app)s/%(model)s/%(action)s.ajax.html', 'smarter/%(action)s.html', 'smarter/_form.html', 'smarter/_ajax.html',) So, you have some easy way options: 1. you may override matching templates 2. you may set 'template' key in ``PageViews.options`` for each action 3. you may override default search paths by settings new ``PageViews.defaults`` (read `Options`_ section for details) Singleton Site ~~~~~~~~~~~~~~ A very special instance of `smarter.Site` is in the smarter module. It allows you to register your applications' views outside your urls.py file, and works well with `autodiscover()`. Here is smarter_views.py in your app: .. sourcecode:: python from smarter import site, GenericViews from models import Model class Views(GenericViews): model = Model # ... site.register(Views) ... And urls.py: .. sourcecode:: python from django.conf.urls import patterns, include, url import smarter smarter.autodiscover() urlpatterns = patterns('', url(r'^', include(smarter.site.urls)), ) This is mostly recommended for non-reusable applications local to your Django project. API reference ------------- Actions ~~~~~~~ **Actions** are actually "ids" for views. Well, each action has id like 'add', 'edit', 'bind-to-user' and is mapped to view method with underscores instead of '-': `add`, `edit`, `bind_to_user`. In ``smarter.GenericViews`` class such actions are defined by default: ======= ================= ========================= ======================== Action URL View method Named URL ======= ================= ========================= ======================== index / index(``request``) [prefix]-[model]-index add /add/ add(``request``) [prefix]-[model]-add details /``<pk>``/ details(``request, pk``) [prefix]-[model]-details edit /``<pk>``/edit/ edit(``request, pk``) [prefix]-[model]-edit remove /``<pk>``/remove/ remove(``request, pk``) [prefix]-[model]-remove ======= ================= ========================= ======================== What is **[prefix]**? Prefix is defined for ``smarter.Site`` instance: .. sourcecode:: python site = smarter.Site(prefix='myapp') site.register(PageViews) # ... So, it **can be empty** and URL names without prefix are defined as `[model]-index`. Please, read `Reversing urls`_ section for more details. Options ~~~~~~~ **Options** is a ``GenericViews.options`` dict, class property, it contains actions names as keys and actions parameters as values. Parameters structure is: .. sourcecode:: python { 'url': <string for url pattern>, 'form': <form class>, 'decorators': <tuple/list of decorators>, 'fields': <tuple/list of form fields>, 'exclude': <tuple/list of excluded form fields>, 'initial': <tuple/list of form fields initialized by request.GET>, 'permissions': <tuple/list of required permissions>, 'widgets': <dict for widgets overrides>, 'help_text': <dict for help texts overrides>, 'required': <dict for required fields overrides>, 'template': <string template name>, 'redirect': <string or callable returning redirect path> } Every key here is optional. So, here's how options can be defined for views: .. sourcecode:: python import smarter class Views(smarter.GenericViews): model = <model> defaults = <default parameters> options = { '<action 1>': <parameters 1>, '<action 2>': <parameters 2> } And here's ``GenericViews.defaults`` class attribute: .. sourcecode:: python defaults = { 'initial': None, 'form': ModelForm, 'exclude': None, 'fields': None, 'labels': None, 'widgets': None, 'required': None, 'help_text': None, 'next': None, 'template': ( '%(app)s/%(model)s/%(action)s.html', '%(app)s/%(model)s/%(action)s.ajax.html', 'smarter/%(action)s.html', 'smarter/_form.html', 'smarter/_ajax.html',), 'decorators': None, 'permissions': None, } When option value can't be found in options dict for action it's searched in `GenericViews.defaults`. Note, that defaults are applied to **all actions**. Action names and URLs ~~~~~~~~~~~~~~~~~~~~~ Actions are named so they can be mapped to views methods and they should not override reserved attributes and methods, so they: 1. **must contain only** latin symbols and '_' or '-', **no spaces** 2. **can't** be in this list: 'model', 'defaults', 'options', 'deny' 3. **can't** start with '-', '_' or 'get\_' 4. **can't** contain '`__`' Sure, you'll get an exception if something goes wrong with that. We're following `'errors should never pass silently'` here. And here's how URLs for default views are defined: .. sourcecode:: python { 'index': { 'url': r'', }, 'details': { 'url': r'(?P<pk>\d+)/', }, 'add': { 'url': r'add/', }, 'edit': { 'url': r'(?P<pk>\d+)/edit/', }, 'remove': { 'url': r'(?P<pk>\d+)/remove/', } } smarter.Site ~~~~~~~~~~~~ | **Site**\(prefix=None, delim='-') | - constructor | | **register**\(views, model=None, base_url=None, prefix=None) | - method to add your views for model | | **urls** | - property, returns URLs sequence for all registered views that can be included in `urlpatterns` | | **autodiscover** | - method which goes over `settings.INSTALLED_APPS` and looks for apps with `smarter_views` modules, which it imports, so they can register their views. Site ++++ Constructor gets two keyword arguments: 1. `prefix=None`, for prefixing URL names for views registered with site object, like '**%(prefix)s**-%(model)s-%(action)s'. If prefix if empty, URLs are named without prefix, like '%(model)s-%(action)s'. 2. `delim='-'`, delimiter for URL names, can be '-', '_' or empty string. URL names are composed with specified delimiter and with uderscore it would be like '%(prefix)s_%(model)s_%(action)s'. Site.register +++++++++++++ This method gets 1 required argument for views class and optional keyword arguments: 1. `model=None`, model class for views. This argument is required if views class doesn't have 'model' property. 2. `base_url=None`, base URL for views. If empty, then lower-case model name is used, so base URL becomes '%(model)s/'. 3. `prefix=None`, prefix for URL names. If empty, then lower-case model name is used. smarter.GenericViews ~~~~~~~~~~~~~~~~~~~~ | **model** | - class property, model class for views | | **defaults** | - class property, dict with default options applied to all actions until being overriden by `options` | | **options** | - class property, dict for views configration, each key corresponds to single action like 'add', 'edit', 'remove' etc. | | **deny**\(``request, message=None``) | - method, is called when action is not permitted for user, raises ``PermissionDenied`` exception or can return ``HttpResponse`` object for redirecting or rendering some page | | **get_url**\(``action, *args, **kwargs``) | - method, returns url for given action name | | **get_form**\(``request, **kwargs``) | - method, returns form for request | | **get_object**\(``request, **kwargs``) | - method, returns single object for request | | **get_objects_list**\(``request, **kwargs``) | - method, returns objects for request | | **get_template**\(``request_or_action``) | - method, returns template name or sequence of template names by action name or per-request | | **get_param**\(``self, request_or_action, name, default=None``) | - method, returns option parameter by name for action or per-request | | **get_initial**\(``self, request``) | - method, returns form initial data per-request | | **<action>**\(``request, **kwargs``) | - method, 1st (starting) handler in default pipeline | | **<action>__perm**\(``request, **kwargs``) | - method, 2nd handler in default pipeline, checks extended permissions, e.g. per-object permissions (basic checks are handler separatelly) | | **<action>__form**\(``request, **kwargs``) | - method, 3rd handler in default pipeline, manages form processing | | **<action>__save**\(``request, form, **kwargs``) | - method, called from **<action>__form** when form is ready to save, saves the form and returns saved instance | | **<action>__post**\(``request, **kwargs``) | - method, 4th handler in default pipeline for post-processing: save messages, extend render context, etc. | | **<action>__done**\(``request, **kwargs``) | - method, 5th (last) view handler in default pipeline, performs render or redirect Pipeline ~~~~~~~~ Each action like 'add', 'edit' or 'remove' is a **pipeline**: a sequence (list) of methods called one after another. A result of each method is passed to the next one. The result is either **None** or **dict** or **HttpResponse** object: 1. **None** - result from previous pipeline method is used for next one, 2. **dict** - result is passed to next pipeline method, 3. **HttpResponse** - returned immidiately as view response. For example, 'edit' action pipeline is: 'edit' -> 'edit__perm' -> 'edit__form' -> 'edit__post' -> 'edit__done'. Note about **__perm** step. Basic permissions are checked **before** pipeline start view (e.g 'edit'), as if view were decorated with ``permission_required`` decorator. Actualy we're not using decorator, because we need to call our custom ``deny()`` method if permissions are not sufficient, but it's not the key. The key is **you don't need to check basic permissions in custom __perm method, it's necessary for per-object permissions checks.** ========== ===================================== =================================================== Method Parameters Result ========== ===================================== =================================================== edit ``request, **kwargs`` 'pk' ``{'obj': obj, 'form': {'instance': obj}}`` edit__perm ``request, **kwargs`` 'obj', 'form' pass (``None``) or ``PermissionDenied`` exception edit__form ``request, **kwargs`` 'obj', 'form' | ``{'form': form, 'obj': obj, 'form_saved': True}`` | - form successfully saved | ``{'form': form, 'obj': obj}`` | - first open or form contains errors edit__post ``request, **kwargs`` pass (``None``) by default 'obj', 'form', 'form_saved' edit__done ``request, **kwargs`` 'obj', 'form', 'form_saved' render template or redirect to ``obj.get_absolute_url()`` ========== ===================================== =================================================== Note, that in general you won't need to redefine pipeline methods, as in many cases custom behavior can be reached with declarative style using **options**. If you're going too far with overriding views, that may mean you'd better write some views from scratch separate from "smarter". Reversing URLs ~~~~~~~~~~~~~~ Every action mapped to named URL. Names are composed as:: [site prefix][delimiter][views prefix][delimiter][action] Where: - **site prefix** is 'prefix' parameter in `smarter.Site`_ constructor - **delimiter** is 'delim' paratemer in `smarter.Site`_ constructor - **views prefix** is 'prefix' parameter in `Site.register`_ method So, in `Getting started`_ example named URLs are 'page-add', 'page-edit', 'page-remove', etc., as we don't provide any custom prefixes and delimiter is '-' by default. Pipeline example ---------------- For deeper understanding here's an example of custom pipeline for 'edit' action. It's not actually a **recommended** way, as we can reach the same effect without overriding ``edit`` method by defining ``options['edit']['initial']``, but it illustrates the principle of pipeline. .. sourcecode:: python import smarter class PageViews(smarter.GenericViews): model = Page def edit(request, pk=None): # Custom initial title initial = {'title': request.GET.get('title': '')} return { 'obj': self.get_object(request, pk=pk), 'form' {'initial': initial, 'instance': obj} } def edit__perm(request, **kwargs): # Custom permission check if kwargs['obj'].owner != request.user: return self.deny(request) def edit__form(request, **kwargs): # Actually, nothing custom here, it's totally generic: # we should validate & save form and then return dict # with 'form_saved' set to True if it's ok. kwargs['form'] = self.get_form(request, **kwargs) if kwargs['form'].is_valid(): kwargs['obj'] = self.edit__save(request, **kwargs) kwargs['form_saved'] = True return kwargs def edit__done(request, obj=None, form=None, form_saved=None): # Custom redirect to pages index on success if form_saved: # Success, redirecting! return redirect(self.get_url('index')) else: # Start edit or form has errors return render(request, self.get_template(request), {'obj': obj, 'form': form}) Complete example ---------------- | You may look at complete example source here: | https://github.com/05bit/django-smarter/tree/master/example License ------- Copyright (c) 2013, Alexey Kinyov <rudy@05bit.com> Licensed under BSD, see LICENSE for more details.


نحوه نصب


نصب پکیج whl django-smarter-1.1:

    pip install django-smarter-1.1.whl


نصب پکیج tar.gz django-smarter-1.1:

    pip install django-smarter-1.1.tar.gz