📜 ⬆️ ⬇️

django.newforms: Using

Occasionally working on my personal project, I got to the task of making a form ... A form for adding a place. The problem is that it is not quite typical. I decided to write about this article, which will help to penetrate deeper into newforms for beginners.

It all started simply with this code:

 from django import new forms as forms <br />
 class AddPlaceForm (forms.Form):
     title = forms.CharField (max_length = 50)
     category = forms.IntegerField ()
     text = forms.CharField (widget = forms.Textarea)
     tags = forms.CharField (max_length = 50))
     city ​​= forms.IntegerField ()
     metrostation = forms.IntegerField (null = True)
     adress = forms.CharField (max_length = 255)


But then a thought appeared, but not one:
')
All these thoughts concern the category, metrostation and city fields. The issue of validating values ​​was solved easily. A new field class has been created and a clean () method has been added to it, which looks like this:

     def clean (self, value):
	 from my.site.models import Category
	 try:
		 item = Category.objects.get (pk = value)
        	 return item
	 except ObjectDoesNotExist:
		 raise forms.ValidationError (u'Invalid input ')


In addition to all the charms, in clean_data ['category'] we will already have an object ready for use. Further grief followed, it is necessary to create this for each field object. Plus, I still haven't solved the problem with automatic filling with values. Therefore, it was decided to create a universal class.

  class SelectFromModel (forms.Field):
     widget = forms.Select ()
     def __init __ (self, objects, * args, ** kwargs):
         self.objects = objects
         super (SelectFromModel, self) .__ init __ (* args, ** kwargs)
         self.loadChoices ()
     def loadChoices (self):
         choices = ()
         for object in self.objects.order_by ('title'):
             choices + = ((object.id, object.title),)
         self.widget.choices = choices
     def clean (self, value):
         value = int (value)
         for cat_id, cat_title in self.widget.choices:
             if cat_id == value:
                 return self.objects.get (pk = cat_id)
         raise forms.ValidationError (u'Invalid input ')

 Accordingly the form
 class AddPlaceForm (forms.Form):
     title = forms.CharField (max_length = 50)
     category = SelectFromModel (objects = Category.objects.all ())
     text = forms.CharField (widget = forms.Textarea)
     # More on this later
     tags = TagField ()
     city ​​= SelectFromModel (objects = City.objects.all ())
     metrostation = SelectFromModel (objects = MetroStation.objects.all ())
     adress = forms.CharField (max_length = 255)


So, what is this, and most importantly "nahto." I created a descendant of a regular field in which I defined the default widget as forms.Select (which is the usual drop-down list), the data in which is loaded automatically when the field is created. At the same time, we do not lose flexibility ... We even add. For example, order_by ('title') in the fill cycle is superfluous (but I did it purposefully, in order not to add sorting each time when creating the field). What is the flexibility. Even when defining a form (more precisely, a form field), we define a circle of objects for which we want the user to make a choice. More precisely, we pass the object request to the object by which to select these objects (LazyLoad). Also, the flexibility lies in the fact that we can easily change the widget to something similar to Select (which, in principle, is planned in the future).

Next came the question with the tag field. It will be used in many forms, so it was decided to put it in a separate class, since it is planned to modernize it (autocompletion, tag separation methods, etc.). Principle, here's the code:

  class TagField (forms.CharField):
     def clean (self, value):
         from daparty.site.models import Tag, TagCynonym
         tags = value.split (',')
         resoult = []
         for tag in tags:
             tag = tag.strip (). lower ()
             # We are looking in existing tags or create
             dbtag = Tag.objects.get_or_create (title = tag)
             resoult.append (dbtag)
         return resoult


In fact, we simply see if there is such a tag in the database, if not - create, if there is, select and give the list as a cleaned result. You also need to think about how to do the reverse operation on the machine (tag objects in a string), but let it be homework (in order to hide the author’s incompetence in this matter :). Many may also notice the TagCynonym class. I am still thinking about how to make more intelligent the comparison of different tags (porno - porno).

References:


UPD: That's interesting, for what they lower karma?) Probably PHP lovers)))

Source: https://habr.com/ru/post/16472/


All Articles