Package: django-related
==============django-related==============django-related is a set of class-based-view mixins that help with commonscenarios that involves related objects. The generic class-based views like``CreateView`` or ``UpdateView`` only deal with single objects. However, fornested resources, or in cases where we might want to use an existing object ifavaialble, these views lack functionality. This is what django-relatedprovides... contents::Installation============Installation can be done using pip::pip install django-relatedThere is no need to add ``related`` to installed apps. It can be useddirectly::from related.views import RedirectOnExistingMixin, CreateWithRelatedMixin...GetExistingMixin================This mixin is deprecated. It is currently just an alias forRedirectOnExistingMixin_ to provide backwards compatibility. It will be removedbecause of the confusing name.Only the class name has changed. All property and method names are left intact.RedirectOnExistingMixin=======================This mixin is used when an attempt to create an object that already exists inthe database should result in a redirect. If the object does not exist in thedatabase, it will not do anything.Basic usage::from related.views import RedirectOnExistingMixinfrom django.views.gneric import CreateViewfrom models import Fooclass MyView(RedirectOnExistingMixin, CreateView):model = Fooexisting_redirect_url = '/bar'With the above view, if we submit a form that contains a ``pk`` or ``slug``field, and the ``Foo`` object with matching ``pk`` or ``slug`` field exists,user will be redirected to ``/bar`` path, and the model form for ``Foo`` willnot even be processed. The redirect path can be customized using the optionsdiscussed further below.Note that this mixin _will_ result in extra database queries to determinewhether an object exists.The view can be further customized using the following properties (and matchingmethods):``existing_form_class`` (``get_existing_form_class()``)Uses the specified form to process the request rather than requestparameters. Default is ``None`` (does no use forms).``existing_form_field``Form field that contains data about existence of the object. Note that thisfield does not need to evaluate to an actual object. Any non-``False``value will be treated as signifying object's existence. The most common usecase is to use a ``ModelChoiceField`` or some field that reads the databasein advance, and provides a choice of values that are only available whenobjects exist.``existing_form_initial`` (``get_existing_form_initial()``)Dictionary of initial values for the ``existing_form_class`` form (if formis used).``existing_pk_field``The model field that contains the primary key. Default is ``'pk'``.``existing_slug_field``The model field that contains the slug. Default is ``'slug'````existing_request_pk_key``The request parameter that represents the primary key. Default is ``'pk'``.``existing_request_slug_key``The request parameter that represents the slug. Note that if primary key isspecified (it is by default), and it is passed in request, slug will not belooked up.``existing_redirect_url`` (``get_existing_redirect_url()``)Required attribute. The URL that client will be redirected to if the objectexists.``existing_form_name`` (``get_existing_form_name``)Customizes the name of the context object containing the form.RelatedObjectMixin===============This mixin is a generic related object pre-fetching mixin. Before resorting tousing this mixin, let's first discuss an approach that works well without theoverhead of ``RelatedObjectMixin``, in cases where you are only fetching therelated object, but doing nothing else. Consider this URL pattern::/posts/(?P<pk>\d+)/comments(Yes, there is a whole comment system included in Django, so, sorry for thecorny example.) In the above case You would normally use a list view for thecomments. But you might also want to fetch the post object as well. There is noneed to use ``RelatedObjectMixin`` in this particular case, because you cancombine Django's built-in ``SingleObjectMixin`` with ``ListView`` to achievewhat you want.Another case where you *do not* want to use this mixin is if you can fetch therelated object using Django's DB API. For example, if you have a ``book``object, you can probably get the related author as ``book.author``.This mixin is useful only if you need two physically unrelated objects (likeusing two ``SingleObjectMixin`` mixins in a view). If there is no actualrelationship between the two objects via a foreign key, then you should usethis mixin.For users of the previous versions of django-related, it has to be noted thatthis mixin is simply ripped out of what used to be a monolithicCreateWithRelatedMixin_. It therefore behaves more or less the same as thatmixin.Here is an example::from related import RelatedObjectMixinfrom django.views.detail import SingleObjectMixinfrom django.views import FormViewfrom cards.models import Cardfrom cards.forms import MatchCardsForm# view for `/match/(?P<first_card_pk>\d+)/(?<second_card_pk>\d+)/`class ViewAttachment(RelatedObjectMixin, SingleObjectMixin, FormView):model = Cardrelated_model = Cardpk_url_kwarg = 'first_card_pk'related_pk_url_kwarg = 'second_card_pk'form_class = MatchCardsFormtemplate_name = 'attachment.html'success_url = '/foo'def get_initial(self):return {'first_card': self.object.pk,'second_card': self.related_object.pk,}def form_valid(self, form):# Do something with the form, etcNote that naming of properties is basically cloned from the``SingleObjectMixin``, with a ``related_`` prefix. In most cases, you can guessthe properties you need to set if you know what they are called in``SingleObjectMixin``.``RelatedObjectMixin`` is currently limited to fetching only one object, justlike ``SingleObjectMixin``, and is therefore not suitable for complex nestedstructures. Again, using Django's DB API would be more reasonable in many ofthose cases.The view can be customized using the following attributes (and matchingmethods):``related_model``Related model under which the current model is nested. This attribute isrequired.``related_404_redirect_url`` (``get_related_404_url()``)If specified, the view will redirect instead of raising``django.http.Http404`` or returning ``django.http.HttpResponseGone``.Default is ``None``.``related_404_message`` (``get_rlated_404_message()``)If ``related_404_redirect_url`` is used, the ``django.contrib.messages`` isused to display an error message. This attribute is used to customize thismessage. Default is ``'%s does not exist'`` where ``'%s'`` will evaluate tothe ``related_model``'s verbose name.``related_pk_field``The field on the ``related_model`` that contains the primary key. Defaultsto ``'pk'``.``related_pk_url_kwarg``The URL parameter that contains the primary key. Defaults to ``'pk'``.``related_slug_field``The field on the ``related_model`` that contains the sulug field. Defaultsto ``'slug'``.``related_slug_url_kwarg``The URL parameter that contains the slug field. Defaults to ``'slug'``.``related_object_name`` (``get_related_object_name()``)Customizes name of the context object that contains the related object.``cache_backend`` (``get_cache_backend``)Specifies the object that implements the caching methods. This object is``django.core.caching.cache`` by default. Any interface that you specifymust provide the same methods as the default one.CreateWithRelatedMixin======================This mixin is used when we are dealing with a ``CreateView`` for a nestedresource. The main assumption is that higher levels of the path contains a slugor pk that points to the related model's object.As discussed in the RelatedObjectMixin_ section, this mixin is based on it, sothe same customization options are available.The key difference between normal CreateView (which can be persuaded to giveyou the related object using the ``queryset`` attribute and ``get_object``method) and this mixin, lies in the form processing. This mixin does two thingsdifferently:1. It ensures that the related object exists (behavior similar to``get_object`` is forced)2. It attaches the related object to the appropriate field in the submittedform.Here is an example::from related import CreateWithRelatedMixinfrom django.views import CreateViewfrom models import Attachment, Postfrom forms import CustomAttachmentModelForm# View for `/posts/(?P<slug>[\w-]+)/attachments`class AttachmentCreateView(CreateWithRelatedMixin, CreateView):model = Attachmentform_class = CustomAttachmentModelFormrelated_model = PostWith the above setup, the ``django.http.Http404`` is raised if GET request ismade to this view with the slug in the URL that points to a non-existent post.If POST request is made to the same URL, ``django.http.HttpResponseGone`` (410)is returned if post does not exist. Otherwise, the ``CustomAttachmentModelForm``is processed, and the ``Post`` object that was found based on the slug will beadded to ``post`` field of the object resulting from the form processing.The view can be customized using the following attributes (and matchingmethods):``related_model``Related model under which the current model is nested. This attribute isrequired.``related_field``Field on the current model that must point to the related object. Bydefault, lower-cased ``related_model``'s class name (e.g., ``'foo'`` for amodel called ``Foo``).``related_404_redirect_url`` (``get_related_404_url()``)If specified, the view will redirect instead of raising``django.http.Http404`` or returning ``django.http.HttpResponseGone``.Default is ``None``.``related_404_message`` (``get_rlated_404_message()``)If ``related_404_redirect_url`` is used, the ``django.contrib.messages`` isused to display an error message. This attribute is used to customize thismessage. Default is ``'%s does not exist'`` where ``'%s'`` will evaluate tothe ``related_model``'s verbose name.``related_pk_field``The field on the ``related_model`` that contains the primary key. Defaultsto ``'pk'``.``related_pk_url_kwarg``The URL parameter that contains the primary key. Defaults to ``'pk'``.``related_slug_field``The field on the ``related_model`` that contains the sulug field. Defaultsto ``'slug'``.``related_slug_url_kwarg``The URL parameter that contains the slug field. Defaults to ``'slug'``.``related_object_name`` (``get_related_object_name()``)Customizes name of the context object that contains the related object.``integritiy_error_message`` (``get_integrity_error_message()``)If there is an integrity error saving the object pointing to the relatedobject, the view will rerender the form, but will also add an error messageto the response object using ``django.contrib.messages``. This attributecustomizes the message. Default is ``'Such record already exists'``.``cache_backend`` (``get_cache_backend``)Specifies the object that implements the caching methods. This object is``django.core.caching.cache`` by default. Any interface that you specifymust provide the same methods as the default one.Reporting bugs==============Please report bugs and feature requests to the Bitbucket `issue tracker`_... _issue tracker: https://bitbucket.org/monwara/django-related/issues