<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Maxim Danilov</title>
    <description>The latest articles on DEV Community by Maxim Danilov (@danilovmy).</description>
    <link>https://dev.to/danilovmy</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F556016%2F5e194089-8c2f-4c18-9347-f6bb98e33c0a.jpg</url>
      <title>DEV Community: Maxim Danilov</title>
      <link>https://dev.to/danilovmy</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/danilovmy"/>
    <language>en</language>
    <item>
      <title>Django Nested Inline. Save Data.</title>
      <dc:creator>Maxim Danilov</dc:creator>
      <pubDate>Wed, 31 Aug 2022 17:26:43 +0000</pubDate>
      <link>https://dev.to/danilovmy/django-nested-inline-save-data-5a7n</link>
      <guid>https://dev.to/danilovmy/django-nested-inline-save-data-5a7n</guid>
      <description>&lt;p&gt;&lt;em&gt;This article is part 2 in a 3-part series on creating nested inlines in the Django admin panel.&lt;/em&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/danilovmy/django-nested-inline-redering-4pfg"&gt;Nested inline rendering&lt;/a&gt;. This article is about rendering a Nested Inline. At the end we should see a Nested Inline in our ModelAdmin. But this Nested Inline can not save own data yet.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Django nested inline. Save data.&lt;/strong&gt;&lt;br&gt;
The second article shows integration of Nested-inlines in the ModelAdmin to make saving data possible.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Django nested inline. Javascript.&lt;br&gt;
The final article in the series explains how to override the inlines.js in Django package to make it possible to add/remove Nested Inlines on fly in the ModelAdmin.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;On the journey to a working nested inline in this article I will touch on the issues of form prefixes, validating a custom field, saving a custom field and form encoding's problem.&lt;/p&gt;

&lt;p&gt;If you are want a quick code example &lt;a href="https://github.com/wP-soft-GmbH/django_admin_nested_inlines"&gt;click here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Form prefixes
&lt;/h2&gt;

&lt;p&gt;First, we need to handle the form prefixes so that our data is sent in the correct form.&lt;/p&gt;

&lt;p&gt;Djangos inline has a &lt;code&gt;prefix&lt;/code&gt; associated with it, each new line gets its own &lt;code&gt;id&lt;/code&gt;, set as follows &lt;code&gt;prefix-*index*&lt;/code&gt;. I thought a reasonable solution for nested-inline would be to handle the prefix of the nested-forms as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;parentPrefix_parentIndex_childPrefix-childIndex
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;In the end it should resemple this stucture:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt;ParentPrefix-0
&amp;gt;&amp;gt;ParentPrefix_0_ChildPrefix-0
&amp;gt;&amp;gt;ParentPrefix_0_ChildPrefix-1

&amp;gt;ParentPrefix-1
&amp;gt;&amp;gt;ParentPrefix_1_ChildPrefix-0
&amp;gt;&amp;gt;ParentPrefix_1_ChildPrefix-1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We update the inline-formset prefix with the prefix of the parent form. This can be done in the &lt;code&gt;image_inline&lt;/code&gt; method, but first we need to get the prefix of the parent form from somewhere. We can set the &lt;code&gt;form&lt;/code&gt; attribute in instance inside the &lt;code&gt;__init__&lt;/code&gt; method of that form itself.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;So we get the 'prefix' from the parent form to generate the 'prefix' of the child forms.&lt;/p&gt;

&lt;h2&gt;
  
  
  Data validation
&lt;/h2&gt;

&lt;p&gt;Django handles validation of the main form and its own inlines on its own, but validation of nested inlines is not yet supported.&lt;/p&gt;

&lt;p&gt;Since validation happens in ModelForm, we need to look there to implement validation for our nested-inlines.&lt;/p&gt;

&lt;p&gt;While I was trying different methods, I realized that it would be much easier to implement the nested-inline itself in the form as follows.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;We see that inside the &lt;code&gt;is_valid&lt;/code&gt; method calls &lt;code&gt;self.nested.formset.is_valid()&lt;/code&gt;. &lt;code&gt;Self.nested&lt;/code&gt; is an attribute that keeps the link to the nested inline.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First is created an instance of *Product*ModelAdmin.&lt;/li&gt;
&lt;li&gt;After that, the &lt;code&gt;_create_formsets&lt;/code&gt; method is called. This method returns the corresponding form sets and their instances depending on whether &lt;code&gt;change_view&lt;/code&gt; or &lt;code&gt;add_view&lt;/code&gt; was requested.&lt;/li&gt;
&lt;li&gt;After &lt;code&gt;get_inline_formsets&lt;/code&gt; returns the nested inlines of that form.&lt;/li&gt;
&lt;li&gt;At the end the prefix is handled and the finished inline is returned.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We set the &lt;code&gt;request&lt;/code&gt; attribute of &lt;code&gt;ShopModelAdmin&lt;/code&gt; in the &lt;code&gt;render_change_form&lt;/code&gt; method before. Now, that's not enough. If we want to have the &lt;code&gt;request&lt;/code&gt; attribute for both &lt;strong&gt;GET&lt;/strong&gt; and &lt;strong&gt;POST&lt;/strong&gt; requests, we need to set the attribute in &lt;code&gt;changeform_view&lt;/code&gt;, because this method is called earlier and is independent of the method of request.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Now that the nested inline is processed in the form, we can shorten the code of the original &lt;code&gt;image_inline&lt;/code&gt; method.&lt;/p&gt;

&lt;h1&gt;
  
  
  save method
&lt;/h1&gt;

&lt;p&gt;Let's wrap the &lt;code&gt;save_form&lt;/code&gt; method of &lt;code&gt;ShopModelAdmin&lt;/code&gt; to also save nested-inlines.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;A form calls its save method only when 2 conditions are met. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;form.is_valid()&lt;/code&gt; must be &lt;strong&gt;True&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;form.has_changed()&lt;/code&gt; must be &lt;strong&gt;True&lt;/strong&gt;. 
We've already handled the is_valid method. Now we need to change the &lt;code&gt;has_changed&lt;/code&gt; method. It should check if our nested data has changed. We also need to specify, which fields have changed so that the form can save the changed data in the model.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Fortunately, we can do everything in one &lt;code&gt;changed_data&lt;/code&gt; property.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;br&gt;
&lt;em&gt;Of course it should be a on-line generator and not the two for's&lt;/em&gt; 

&lt;p&gt;Since our nested-inline is defined as a &lt;strong&gt;read-only&lt;/strong&gt; field, the &lt;code&gt;changed_data&lt;/code&gt; property will nominally ignore all changes in nested-inline, so we need to add the modified fields of nested- inline to the other modified fields.&lt;/p&gt;

&lt;p&gt;Right now we have a working nested-inline for most Use-cases. But I discovered an exception. If our nested-inline contain any &lt;code&gt;FileField&lt;/code&gt;, the &lt;code&gt;request.POST&lt;/code&gt; processing breaks. It took me a long time to figure out, why it worked with other fields and not with the FileField. The answer lies in the attribute enctype="" of the HTML-form.&lt;/p&gt;
&lt;h2&gt;
  
  
  Form encoding
&lt;/h2&gt;

&lt;p&gt;There are two types of enctype attribute values for our purposes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"application/x-www-form-urlencoded"&lt;/li&gt;
&lt;li&gt;"multipart/form-data"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This attribute determines how the browser sends the HTML form data.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The &lt;code&gt;application/x-www-form-urlencoded&lt;/code&gt; enctype creates a simple long string of name and value pairs. These pairs are separated by &lt;code&gt;&amp;amp;&lt;/code&gt;, and the name and value are separated by &lt;code&gt;=&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;multipart/form-data&lt;/code&gt; enctype define a 'delimeter' in the Conent-Type header. Each pair of values is separated by this boundary formatted as: &lt;code&gt;--&amp;lt;boundary_value&amp;gt;&lt;/code&gt;. Then comes &lt;code&gt;Content-Disposition: form-data; name="&amp;lt;field_name&amp;gt;"&lt;/code&gt;. After that, the value of the field is set. After that comes another boundary.&lt;br&gt;
Final &lt;code&gt;--&lt;/code&gt; closes the body of the query.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It is not possible to send files with the &lt;code&gt;application/x-www-form-urlencoded&lt;/code&gt;. This enctype is best used for most web forms with short alphanumeric values.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;multipart/form-data&lt;/code&gt;, as already mentioned, is used when we want to send files of any type.&lt;/p&gt;

&lt;p&gt;But why do we need two arts of enctypes for HTML forms?&lt;/p&gt;

&lt;p&gt;The answer lies in the speed and size of the request. The request without data with &lt;code&gt;application/x-www-form-urlencoded&lt;/code&gt; enctype is about 6 times faster and incredibly smaller than the same request in &lt;code&gt;multipart/form-data&lt;/code&gt; enctype.&lt;/p&gt;

&lt;p&gt;Why is this important for our nested-inline? If we have a &lt;code&gt;FileField&lt;/code&gt; in a nested-inline, by default the form does not recognize it, because we have nested-inline as a read-only field.  This means that the nested-inline will not send the content of the FileField. The other fields will be handled normally.&lt;/p&gt;

&lt;p&gt;To fix this, we need to wrap the &lt;code&gt;is_multiform&lt;/code&gt; method of our form so that it also calls the &lt;code&gt;is_multiform&lt;/code&gt; method of the nested inline.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Why not use &lt;code&gt;multipart/form-data&lt;/code&gt; enctype all the time? Yes, you can do that, and it will work. But the query size increases significantly with each field you add to the form. That's just unnecessary overhead.&lt;/p&gt;

&lt;p&gt;For more information on the encoding of HTML forms I would recommend &lt;a href="https://dev.to/sidthesloth92/understanding-html-form-encoding-url-encoded-and-multipart-forms-3lpa"&gt;this article&lt;/a&gt; about it and &lt;a href="https://stackoverflow.com/questions/4007969/application-x-www-form-urlencoded-or-multipart-form-data"&gt;this discussion&lt;/a&gt; on Stackoverflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limitations
&lt;/h2&gt;

&lt;p&gt;This implementation of nested inlines is not without its flaws. This is just an example of how to approach creating nested inlines.&lt;/p&gt;

&lt;p&gt;With a little more time and determination, it is possible to implement general inline support in the Django-inlines themselves, which would make creating nested-inlines pretty easy.&lt;/p&gt;

&lt;p&gt;In this solution, we assume that an inline is already defined in ProductModelAdmin. But that may not be the case. We can add a check to see if ModelAdmin has an inline.&lt;/p&gt;

&lt;p&gt;Multiple inlines with multiple nested.inlines are not implemented in this solution. The &lt;code&gt;nested&lt;/code&gt; method returns only the first inline from ProducModelAdmin. This is solvable by returning a list of all ModelAdmin inlines.&lt;/p&gt;

&lt;p&gt;As you can see, this is not the final answer to the question of creating nested inlines, but this is the working solution that you can use in your projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next Article
&lt;/h2&gt;

&lt;p&gt;Saving data is now possible in a nested inline, but you may notice that it still cannot be used in the django admin panel. This is a result of the mess the django developers created in inline.js.&lt;/p&gt;

&lt;p&gt;We'll solve this problem in the next article.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Written by Martin Achenrainer&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;PS: I would like to thank Maxim Danilov for his extensive help on this series of articles, he was the inspiration and led me to this clever solution. I would also like to thank him and his company &lt;strong&gt;wP soft&lt;/strong&gt; for giving me the opportunity to develop and improve my programming skills in a working environment.&lt;/p&gt;

</description>
      <category>python</category>
      <category>django</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Django nested inline redering</title>
      <dc:creator>Maxim Danilov</dc:creator>
      <pubDate>Fri, 24 Jun 2022 09:26:41 +0000</pubDate>
      <link>https://dev.to/danilovmy/django-nested-inline-redering-4pfg</link>
      <guid>https://dev.to/danilovmy/django-nested-inline-redering-4pfg</guid>
      <description>&lt;p&gt;This article expands on the ideas of my previous articles:&lt;br&gt;
&lt;a href="https://dev.to/danilovmy/django-admin-dynamic-inline-positioning-3cam"&gt;Django admin dynamic Inline positioning&lt;/a&gt; and &lt;a href="https://dev.to/danilovmy/how-to-solve-the-singleton-problem-in-django-modeladmin-g42"&gt;How to solve the singleton problem in Django ModelAdmin&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This is also the first part of a three-part series on how to get Nested Inlines in the Django admin panel.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Django Nested Inline. Rendering.&lt;/strong&gt;&lt;br&gt;
This article is about rendering a Nested Inline. At the end we should see a Nested Inline in our ModelAdmin. But this Nested Inline can not save own data yet.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/danilovmy/django-nested-inline-save-data-5a7n"&gt;Django nested inline. Save data.&lt;/a&gt;&lt;br&gt;
The second article shows integration of nested inlines in the ModelAdmin to make saving data possible.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Django nested inline. Javascript.&lt;br&gt;
The final article in the series explains how to override the inlines.js in Django package to make it possible to add/remove Nested Inlines on fly in the ModelAdmin.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Although you will hopefully not need to implement nested-inlines at present, you can learn a thing or two about Django.&lt;/p&gt;

&lt;p&gt;If you are want a quick code example &lt;a href="https://github.com/wP-soft-GmbH/django_admin_nested_inlines" rel="noopener noreferrer"&gt;click here&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Introspection of existed Nested Inline packages
&lt;/h2&gt;

&lt;p&gt;The direct way to get Nested Inlines in Django Admin would be to install the package, since surely someone has already solved this problem, right?&lt;/p&gt;

&lt;p&gt;After a quick search, you come across &lt;a href="https://pypi.org/project/django-nested-inline/" rel="noopener noreferrer"&gt;Django-Nested-Inline&lt;/a&gt; and think you're done. &lt;br&gt;
Unfortunately, this solution has some problems and does not work properly. &lt;/p&gt;

&lt;p&gt;For example, it doesn't allow synchronous editing of objects at the same time. I mean - if several people are working with your Admin Panel at the same time, there will be unexplainable errors all the time. The probability of such errors grows exponentially with each manager and each nested Inline.&lt;/p&gt;

&lt;p&gt;So we can try to create our own Nested Inline. It's not complicated.&lt;/p&gt;
&lt;h2&gt;
  
  
  Basic Nested Inline rendering
&lt;/h2&gt;

&lt;p&gt;First create a shop model, a product model and an image model. The product model must relate to the shop model, and the image model must relate to the product model.&lt;/p&gt;

&lt;p&gt;Something like this:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Now we create some basic ModelAdmins with Inlines, like this:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Let's make some changes to ProductModelAdmin and ShopModelAdmin. We need to set the request and response as attributes for both ModelAdmin.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Experienced Django developers may notice that using a ModelAdmin instance as a container is not threadsave, and they would be correct if it were the default admin panel. &lt;br&gt;
Here I refer them back to my &lt;a href="https://dev.to/danilovmy/how-to-solve-the-singleton-problem-in-django-modeladmin-g42"&gt;previous article&lt;/a&gt; to explain how this works.&lt;/p&gt;

&lt;p&gt;This is one of the cornerstones of how to create nested Inlines.&lt;/p&gt;

&lt;p&gt;Additionally we should override the &lt;code&gt;get_inline_instances&lt;/code&gt; method of &lt;code&gt;ShopModelAdmin&lt;/code&gt; to set the &lt;code&gt;modeladmin&lt;/code&gt; inline attribute to the current admin instance, this will be useful later.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;I have made this function as  generator, it calculated only when the result used for iteration.&lt;/p&gt;

&lt;p&gt;We can now take the idea of &lt;a href="https://dev.to/danilovmy/django-admin-dynamic-inline-positioning-3cam"&gt;dynamic inline positioning&lt;/a&gt; and develop it further. If it's possible to use inline in &lt;code&gt;ModelAdmin&lt;/code&gt; as a field, it should be possible to do the same in inline itself, so let's copy the &lt;code&gt;ProductModelAdmin&lt;/code&gt; code from that article.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;But not everything works the same as in the &lt;code&gt;ModelAdmin&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;First, we can not get the context from the &lt;code&gt;self.response&lt;/code&gt; attribute because the inline does not have that attribute. &lt;br&gt;
But the &lt;code&gt;Inline&lt;/code&gt; has the attribute &lt;code&gt;modeladmin&lt;/code&gt; because we defined it in &lt;code&gt;get_inline_instances&lt;/code&gt;. &lt;code&gt;inline.modeladmin&lt;/code&gt; is the &lt;code&gt;ModelAdmin&lt;/code&gt; instance. That has a &lt;code&gt;request&lt;/code&gt; and a &lt;code&gt;response&lt;/code&gt; attribute. So we can get the context from there.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

context = getattr(self.modeladmin.response, 'context_data', None) or {}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Secondly, Context does not contain the Information about Nested inline. With the code above we want to display a nested inline in the field of the current inline. We can call the view method for ProductModelAdmin and extract a nested inline from response. There is inline that must be nested.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

admin_response = ProductModelAdmin(self.model, self.modeladmin.admin_site).add_view(self.modeladmin.request)

inline = admin_response.context_data['inline_admin_formsets'][0]



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Although it should be noted that this is not the final version: in reality we need to call the appropriate &lt;code&gt;ModelAdmin&lt;/code&gt; view as requested, rather than just &lt;code&gt;add_view&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Thirdly, we need to modify the args we pass to the &lt;code&gt;render&lt;/code&gt; method so, that they contain an updated context that includes our extracted nested inline, and request.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

return get_template(inline.opts.template).render(context | {'inline_admin_formset': inline}, self.modeladmin.request)



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;In this construction we don't change context variable directly. The update operator ('|') creates a copy of the dictionary and updates it with the new values.&lt;/p&gt;

&lt;p&gt;The final method should look like this:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;If we start our project and try add a new shop model we see our nested inline.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4kq0vn7a36lcj16k1f8y.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4kq0vn7a36lcj16k1f8y.PNG" alt="basic nested inline"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, our nested inline is displayed. Yay! But you might also notice that there are some problems rendering the inlines. This is because Djangos inlines.js for inlines is a complete mess and needs to be refactored. My &lt;a href="https://code.djangoproject.com/ticket/33394" rel="noopener noreferrer"&gt;issue about it&lt;/a&gt; in djangoproject was rejected as "ivalid".&lt;/p&gt;

&lt;p&gt;Fortunately, I will show, how to do this in last article of this series.&lt;/p&gt;

&lt;p&gt;At the moment, this display error can be temporarily fixed by changing one line of code in the django\contrib\admin\static\admin\js\inlines.js file. &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

// row 335:
$(selector).stackedFormset(selector, inlineOptions.options);

// change to:

$(this).find("[id^=" + inlineOptions.name.substring(1) + "-]").stackedFormset(selector, inlineOptions.options);



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Not it works better than before.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqveesbj3nokdcovb3icj.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqveesbj3nokdcovb3icj.PNG" alt="inline with js fixed"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now it's not perfect, and the rendering problem still exists.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhueazw1ro8v3ezo4kv9l.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhueazw1ro8v3ezo4kv9l.PNG" alt="inline with js fixed, extended"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Next Article
&lt;/h2&gt;

&lt;p&gt;This article was only about getting the nested inline before the first render, without validation and saving data of nested Inline. In the next article I will show how to save the data properly.&lt;/p&gt;

&lt;p&gt;This article war Written by &lt;strong&gt;Martin Achenrainer&lt;/strong&gt;. I thank Martin, for translating and assisting with this English article. This idea was first presented in September 2021 at PyCon RU&lt;/p&gt;

&lt;p&gt;Some words from Martin:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I would like to thank Maxim Danilov for his extensive help on this series of articles, he was the inspiration and led me to this clever solution. I would also like to thank him and his company wP Soft for giving me the opportunity to develop and improve my programming skills in learning by doing.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>django</category>
      <category>python</category>
    </item>
    <item>
      <title>Autoregister Django ModelAdmins</title>
      <dc:creator>Maxim Danilov</dc:creator>
      <pubDate>Tue, 07 Jun 2022 10:25:40 +0000</pubDate>
      <link>https://dev.to/danilovmy/autoregister-django-modeladmins-3jao</link>
      <guid>https://dev.to/danilovmy/autoregister-django-modeladmins-3jao</guid>
      <description>&lt;p&gt;Some time ago I discovered that Django has the ability to auto-register &lt;code&gt;ModelAdmins&lt;/code&gt;. Since this is not common knowledge and carries a number of benefits, I decided to write an article about it to bring it to the attention of the Django community.&lt;/p&gt;

&lt;p&gt;First, let's go over the basics of how to normally register &lt;code&gt;ModelAdmin&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Standard &lt;code&gt;ModelAdmin&lt;/code&gt; registration
&lt;/h2&gt;

&lt;p&gt;To register &lt;code&gt;ModelAdmin&lt;/code&gt;, we first create a model&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Next you need to create a &lt;code&gt;ModelAdmin&lt;/code&gt; and register it with the model on the &lt;code&gt;SiteAdmin&lt;/code&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Now let's run our dev server and see if it worked.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvejd0dodot6i10vi8zl8.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvejd0dodot6i10vi8zl8.PNG" alt="admin panel registered models"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But what are these? Some additional &lt;code&gt;ModelAdmins&lt;/code&gt; are registered, but we've never defined them. This means Django is auto-registering these standard &lt;code&gt;ModelAdmins&lt;/code&gt; somewhere.&lt;/p&gt;

&lt;h2&gt;
  
  
  Django &lt;code&gt;ModelAdmins&lt;/code&gt; integrated auto-register.
&lt;/h2&gt;

&lt;p&gt;After some digging in &lt;code&gt;django.contrib.admin.apps&lt;/code&gt;, I found that these &lt;code&gt;ModelAdmins&lt;/code&gt; are registered in the &lt;code&gt;ready&lt;/code&gt; method of the &lt;code&gt;AdminConfig&lt;/code&gt; class.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class AdminConfig(SimpleAdminConfig):
    """The default AppConfig for admin which does autodiscovery."""

    default = True

    def ready(self):
        super().ready()
        self.module.autodiscover()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We can use this fact to our advantage if we wrap this method not only for auto-registering the standard Django models, but also for our own.&lt;/p&gt;

&lt;p&gt;We can do this as follows:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;We go through all &lt;code&gt;AppConfigs&lt;/code&gt; in our project and get the admin module from &lt;code&gt;AppConfigs&lt;/code&gt;. Of course, this is the case if the admin module exists.&lt;br&gt;
We then go through all models from this &lt;code&gt;AppConfig&lt;/code&gt;.&lt;br&gt;
There we check if the model has already been registered with &lt;code&gt;SiteAdmin&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If not, we search for &lt;code&gt;ModelAdmin&lt;/code&gt; class with name '*model_name*ModelAdmin' in the admin module. If no such class is defined, we use &lt;code&gt;None&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Finally, we register the model using the found &lt;code&gt;ModelAdmin&lt;/code&gt;on &lt;code&gt;SiteAdmin&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If &lt;code&gt;ModelAdmin&lt;/code&gt; is not defined, the &lt;code&gt;register&lt;/code&gt; method registers the model to &lt;code&gt;ModelAdmin&lt;/code&gt; class by default.&lt;/p&gt;

&lt;p&gt;But why should you do it this anyway?&lt;/p&gt;
&lt;h2&gt;
  
  
  Benefits
&lt;/h2&gt;
&lt;h3&gt;
  
  
  1. Shorter Code
&lt;/h3&gt;

&lt;p&gt;With this approach to registering &lt;code&gt;ModelAdmins&lt;/code&gt; you can multiple  lines of code in one 10-line solution.&lt;/p&gt;

&lt;p&gt;You can say goodbye to the empty &lt;code&gt;ModelAdmin&lt;/code&gt; classes just to register the model, if you done it before. &lt;br&gt;
No more &lt;code&gt;@admin.register(model)&lt;/code&gt; wrappers on any &lt;code&gt;ModelAdmin&lt;/code&gt;.&lt;br&gt;
Most importantly, no more long import lists for your models in the module admin.&lt;/p&gt;

&lt;p&gt;Depending on how many models you have and how many &lt;code&gt;ModelAdmins&lt;/code&gt; need to be registered you can save a lot of lines of code.&lt;/p&gt;
&lt;h3&gt;
  
  
  2. Easier development
&lt;/h3&gt;

&lt;p&gt;Continuing with the idea of the previous point, you no longer need to worry about registering &lt;code&gt;ModelAdmin&lt;/code&gt; during development because everything happens automatically when the server starts up.&lt;/p&gt;
&lt;h3&gt;
  
  
  3. Circular Imports
&lt;/h3&gt;

&lt;p&gt;With the current system with huge import lists in the admin module, it is not that difficult to get circular imports and find a workaround. With this solution, these import lists are gone and you no longer have to worry about models and circular import.&lt;/p&gt;
&lt;h2&gt;
  
  
  Variations
&lt;/h2&gt;

&lt;p&gt;Sometimes you don't want register on the current &lt;code&gt;SiteAdmin&lt;/code&gt; all of your models, so what do you do then?&lt;/p&gt;

&lt;p&gt;Of course you can modify the solution above as you wish, but here I want to give you some ideas for solving the most common problems.&lt;/p&gt;
&lt;h3&gt;
  
  
  Register specific models only
&lt;/h3&gt;

&lt;p&gt;If we want to register only the required models with &lt;code&gt;ModelAdmins&lt;/code&gt;, we can define only the required &lt;code&gt;ModelAdmins&lt;/code&gt; in the admin module and do the following:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;In this solution you need to add in the admin module &lt;code&gt;**ModelName**ModelAdmin&lt;/code&gt; class for each required model.&lt;/p&gt;

&lt;p&gt;Alternatively you can add a flag to the model if it should be auto-registered.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h3&gt;
  
  
  Remove standard registered models
&lt;/h3&gt;

&lt;p&gt;Perhaps you don't need the standard Django models registered in your project. You can remove them with one simple line added to the ready method.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;These are just some of the options for using Django autoregister. I'm sure you can think of other clever ways to use it, and I hope this article was useful.&lt;/p&gt;

&lt;p&gt;I thank Martin Achenrainer, who is an apprentice at my firm, for translating and assisting with the English article. The idea was first &lt;a href="https://www.youtube.com/watch?v=5tJdO0bkb3A" rel="noopener noreferrer"&gt;presented&lt;/a&gt; in September 2021 at PyCon RU&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Some words from Martin Achenrainer.&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I would like to thank Maxim Danilov and his company wP soft for the opportunity to learn and improve my programming skills in the workplace.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>django</category>
      <category>python</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to solve the singleton problem in Django ModelAdmin.</title>
      <dc:creator>Maxim Danilov</dc:creator>
      <pubDate>Tue, 03 May 2022 16:20:29 +0000</pubDate>
      <link>https://dev.to/danilovmy/how-to-solve-the-singleton-problem-in-django-modeladmin-g42</link>
      <guid>https://dev.to/danilovmy/how-to-solve-the-singleton-problem-in-django-modeladmin-g42</guid>
      <description>&lt;p&gt;The &lt;code&gt;ModelAdmin&lt;/code&gt; class from &lt;em&gt;django.contrib.admin.options&lt;/em&gt; has a bad design from the beginning: every registered &lt;code&gt;ModelAdmin&lt;/code&gt; in your project is a singleton.&lt;/p&gt;

&lt;p&gt;This fact creates a big barrier for every developer who uses Django Admin in his project. This slows down the project, creates problems when the same &lt;code&gt;ModelAdmin&lt;/code&gt; is used by several users, and encourages programmers to use hacks to get around the limitations of this (anti) pattern. You can learn how to solve this problem in 5 lines in this article.&lt;/p&gt;

&lt;p&gt;Why the developers of &lt;em&gt;django.contrib.admin&lt;/em&gt; continue to rely on this architecture is a mystery to me.&lt;/p&gt;

&lt;p&gt;Luckily there has been a quick and easy fix for this issue that works from the first version of Django up to the current one  (4.0.3 in april 2022).&lt;/p&gt;

&lt;h3&gt;
  
  
  Table of Content:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The problems.&lt;/strong&gt; I will describe in detail the problems encountered when using the singleton architecture for ModelAdmin.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The solution.&lt;/strong&gt; I will walk you through the fix and explain how and why it works. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Django devs.&lt;/strong&gt; I'm asking Django developers reading this article to consider changing the &lt;em&gt;django.contrib.admin&lt;/em&gt; structure to make life easier for everyone.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Talk from PyCon 2022 about this problem.&lt;/strong&gt; In addition to this article I have a video about this topic from  PyCon DE 2022 in Berlin.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  The problems
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Multiple users can not work normally with the same &lt;code&gt;ModelAdmin&lt;/code&gt; at the same time.
&lt;/h4&gt;

&lt;p&gt;When multiple users are running the admin panel at the same time, the singleton design pattern can allow one user to modify another user's data.&lt;/p&gt;

&lt;p&gt;Let me demonstrate it with the code from my previous article about &lt;a href="https://dev.to/danilovmy/django-admin-dynamic-inline-positioning-3cam"&gt;Django admin dynamic inline positioning&lt;/a&gt;. Right now it is not really important what the code does. We just modify the functions in the admin panel like this:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Now let's open the two tabs of the admin panel to simulate two users. Now let's open the change form for the product with pk=1 on the first tab (/admin/products/product/1/change). After this line, we are stopped by the &lt;code&gt;breakpoint&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;10            self.hello = 'hello this is the first obj'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;If we check the &lt;code&gt;self.hello&lt;/code&gt; attribute, we see the following:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4fa3ggsdhsx8dwalksue.JPG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4fa3ggsdhsx8dwalksue.JPG" alt="Attribute 'hello' of ModelAdmin by GET request, product id=1"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now let's open a change form for a product with pk=2 in another tab ('/admin/products/product/2/change') and see what happens. We get a response from the change form right away because we skipped the &lt;code&gt;breakpoint&lt;/code&gt;. But let's see what happened to our &lt;code&gt;hello&lt;/code&gt; attribute that we set for our &lt;code&gt;ModelAdmin&lt;/code&gt; in the first tab.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx3yeg5enb12drtr5aobl.JPG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx3yeg5enb12drtr5aobl.JPG" alt="Attribute 'hello' in ModelAdmin for GET request pk=1 changed by other request"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our &lt;code&gt;ModelAdmin.hello&lt;/code&gt; attribute for GET request pk=1 has been changed to "this is the second obj", even though we did nothing in our first thread.&lt;/p&gt;

&lt;p&gt;We proved that &lt;code&gt;ModelAdmin&lt;/code&gt; is a singleton, which means that we always get the same instance of &lt;code&gt;ModelAdmin&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is a simple demonstration of the problem. Since there are no real consequences in this example, some might even consider it trivial, but the consequences of this behavior for our project could be dangerous.&lt;/p&gt;

&lt;p&gt;With this behavior, every ModelAdmin's do not guarantee the integrity of the data, because it is impossible to trace who has edited the data. Did this current thread edit our data? Did another request change something without our knowledge? Who knows.&lt;/p&gt;

&lt;p&gt;You might argue that this isn't a problem because the requests have to happen at the same time for this problem to take effect. However, in a project where multiple people are running the admin panel at the same time, the issue is not &lt;strong&gt;if&lt;/strong&gt; someone opens &lt;code&gt;ModelAdmin&lt;/code&gt; at the same time as someone else, but &lt;strong&gt;when&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This causes errors, for which there is no obvious explanation without an in-depth understanding of the admin panel architecture.&lt;/p&gt;

&lt;p&gt;So the easiest way to avoid the problem is not to use the &lt;code&gt;ModelAdmin&lt;/code&gt; instance as a container.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;But not every developer is aware of this, and &lt;code&gt;ModelAdmin&lt;/code&gt; is often used by inexperienced developers to store data.&lt;br&gt;
In this &lt;a href="https://stackoverflow.com/questions/727928/django-admin-how-to-access-the-request-object-in-admin-py-for-list-display-met/23574558#23574558?newreg=fca9027c603a4c18b9f6e584986b3f2a" rel="noopener noreferrer"&gt;example&lt;/a&gt; the highest voted answer does exactly that. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If we can't use &lt;code&gt;ModelAdmin&lt;/code&gt;, then where can we store our data? Django does not give us a clear answer by default.&lt;/p&gt;
&lt;h4&gt;
  
  
  2. Hacks
&lt;/h4&gt;

&lt;p&gt;Since you can't use an instance of ModelAdmin as a container, developers are looking for other options.&lt;/p&gt;

&lt;p&gt;Most of the workarounds &lt;a href="https://gist.github.com/vparitskiy/71bb97b4fd2c3fbd6d6db81546622346" rel="noopener noreferrer"&gt;I've found&lt;/a&gt; are to store the information in a global dictionary and map it to the locals of current thread. Yes, that works, but shouldn't there be another way than that?&lt;/p&gt;
&lt;h4&gt;
  
  
  3. Speed
&lt;/h4&gt;

&lt;p&gt;If it were possible to use &lt;code&gt;ModelAdmin&lt;/code&gt; as a container for the data, Django itself could do it. Currently Django repeatedly calls certain &lt;code&gt;ModelAdmin&lt;/code&gt; methods to get the same result during the same request. All of these results should be cached. If &lt;code&gt;ModelAdmin&lt;/code&gt; behaved like Django-GCBV, we could save valuable computation time.&lt;/p&gt;

&lt;p&gt;The table shows how often the following &lt;code&gt;ModelAdmin&lt;/code&gt; methods are called several times per request:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;changelist GET&lt;/th&gt;
&lt;th&gt;change GET&lt;/th&gt;
&lt;th&gt;change POST&lt;/th&gt;
&lt;th&gt;add GET&lt;/th&gt;
&lt;th&gt;add POST&lt;/th&gt;
&lt;th&gt;delete&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;has_view_permission&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;has_module_permission&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;get_ordering&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;get_preserved_filters&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;has_change_permission&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;get_list_display&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;get_search_fields&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;get_model_perms&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;has_delete_permission&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;get_readonly_fields&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;get_search_results&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;has_add_permission&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;get_empty_value_display&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;variable&lt;/td&gt;
&lt;td&gt;variable&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;variable&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;get_actions&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;_get_base_actions&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The number of calls to some methods depends on the number of &lt;code&gt;AdminForm&lt;/code&gt; or &lt;code&gt;ModelForm&lt;/code&gt; fields.&lt;/p&gt;

&lt;p&gt;Let's compare the response time of the "vanilla" Django admin panel by default and the Django admin panel with cached method of ModelAdmin. As a code example I took the project from my &lt;a href="https://dev.to/danilovmy/django-admin-dynamic-inline-positioning-3cam"&gt;last article&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;I have created a middleware that outputs the time elapsed between the request and the response:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;If the middleware code is executed, we will get the result:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;default django admin panel&lt;/th&gt;
&lt;th&gt;modified admin panel&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff8ki4w9meqdwz7pfcrod.PNG" alt="Time 1 default django admin panel"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fse7nildbtoipm38furn5.PNG" alt="Time 1 cached solution"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe6ikna8xun39nz0kivkx.PNG" alt="Time 2 default django admin panel"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7268fyr7jy5jkr4w2b8v.PNG" alt="Time 2 cached solution"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fngddfpppamflclegx861.PNG" alt="Time 3 default django admin panel"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm19f3z3n1s5skw9b67d9.PNG" alt="Time 3 cached solution"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;average time: 0.031673s&lt;/td&gt;
&lt;td&gt;average time: 0.026001s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;As you can see, even in this simple project the speed increase, due to caching the results of calculating functions, is **almost 20%!&lt;/p&gt;

&lt;p&gt;This speed can be greatly increased by refactoring the entire &lt;code&gt;ModelAdmin&lt;/code&gt; class, since it is currently a bloated piece of spagetty-code.&lt;/p&gt;

&lt;h2&gt;
  
  
  The solution
&lt;/h2&gt;

&lt;p&gt;Let's now take a look at where &lt;code&gt;ModelAdmin&lt;/code&gt; singletons come from in Django and try to fix it.&lt;/p&gt;

&lt;p&gt;Each instance of &lt;code&gt;ModelAdmin&lt;/code&gt; is created when it is registered by instance of &lt;code&gt;AdminSite&lt;/code&gt; from &lt;em&gt;django.contrib.admin.sites&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;In the docstring of the &lt;code&gt;AdminSite&lt;/code&gt; class, we learn that the &lt;code&gt;get_urls&lt;/code&gt; method is used to retrieve views from each registered instance of ModelAdmin. Thanks to the author of this docstring.&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;AdminSite.get_urls&lt;/code&gt; we can find this code snipped:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Here we see that the &lt;code&gt;ModelAdmin.urls&lt;/code&gt; property is called.&lt;br&gt;
This property returns the result of the &lt;code&gt;ModelAdmin.get_urls&lt;/code&gt; method. So, let's explore what this method &lt;code&gt;get_urls&lt;/code&gt; does:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;At first glance it seems like a lot of code, but let's unpack it piece by piece. Let's start exploring this code from the bottom.&lt;/p&gt;

&lt;p&gt;The returned list is created for url-dispatcher. It contains tuples from the &lt;strong&gt;url&lt;/strong&gt;, the &lt;strong&gt;view&lt;/strong&gt; to be called, and the &lt;strong&gt;name&lt;/strong&gt; of the view.&lt;/p&gt;

&lt;p&gt;What matters to us is, what is given as a &lt;strong&gt;view&lt;/strong&gt;. This is a wrapped &lt;strong&gt;bounded method&lt;/strong&gt; of a &lt;strong&gt;ModelAdmin instance&lt;/strong&gt;. So, let's take a look at what this wrapper &lt;code&gt;wrap&lt;/code&gt; does.&lt;/p&gt;

&lt;p&gt;Fortunately, this wrapper &lt;code&gt;wrap&lt;/code&gt; is defined right above.&lt;br&gt;
The &lt;code&gt;update_wrapper&lt;/code&gt; at the end of &lt;code&gt;wrap&lt;/code&gt; is not very important, it just makes the final view behave like a &lt;strong&gt;ModelAdmin instance&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The body of the &lt;code&gt;wrapper&lt;/code&gt; function is crucial for our mission. There we see a call of &lt;code&gt;admin_site.admin_view&lt;/code&gt; with &lt;strong&gt;bounded method&lt;/strong&gt; of &lt;strong&gt;ModelAdmin instance&lt;/strong&gt; as an argument.&lt;br&gt;
&lt;code&gt;admin_site&lt;/code&gt; is the instance of &lt;code&gt;AdminSite&lt;/code&gt; on which the &lt;strong&gt;ModelAdmin instance&lt;/strong&gt; is registered.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This&lt;/strong&gt; method we need to override to rid Django ModelAdmin of the curse of the singleton pattern.&lt;/p&gt;

&lt;p&gt;Pffew, all these explanations are for one simple function that needs to be overridden. Yes, because without knowing how this whole system works, we wouldn't understand how to properly override this function to solve our problem and not break anything.&lt;/p&gt;

&lt;p&gt;Let's create a child class of &lt;code&gt;AdminSite&lt;/code&gt; and override the &lt;code&gt;admin_view&lt;/code&gt; method like this:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Let's ignore all the wrappers and focus on these lines of code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;new_instance = type(instance)(instance.model, instance.admin_site)
return func.__func__(new_instance, *args, **kwargs)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;em&gt;func&lt;/em&gt; is a bounded method of our singleton &lt;em&gt;instance&lt;/em&gt; of ModelAdmin, which is always the same for every query.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;__func__&lt;/code&gt; attribute of &lt;em&gt;func&lt;/em&gt; is a method of the &lt;code&gt;ModelAdmin&lt;/code&gt; class. It is not more associated with any instance of &lt;code&gt;ModelAdmin&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Here I am using python terminology &lt;strong&gt;bound&lt;/strong&gt; and &lt;strong&gt;unbound&lt;/strong&gt; method. &lt;code&gt;func.__func__&lt;/code&gt; is not bound to an instance of &lt;code&gt;func.__self__&lt;/code&gt;, but it is also not a static function, it is a class method. An instance of the same class as &lt;code&gt;func.__self__&lt;/code&gt; is still required as the first argument to call this method.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To create a &lt;strong&gt;new instance&lt;/strong&gt; of &lt;code&gt;ModelAdmin&lt;/code&gt; we need model and admin_site as arguments, which can easily be taken from the old singleton-instance.&lt;/p&gt;

&lt;p&gt;Now we can return '&lt;strong&gt;func&lt;/strong&gt;' call with &lt;strong&gt;new instance&lt;/strong&gt; as self, and arguments *args and **kwargs, that are passed at the time of the call.&lt;/p&gt;

&lt;p&gt;Now the Singleton architecture is successfully bypassed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This means that every time a request is sent to the view a new ModelAdmin instance is created and it's corresponding view function is called&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As mentioned earlier, it was possible to avoid all this agony from the beginning of Django.&lt;/p&gt;

&lt;p&gt;All that remains is to make our child AdminSite as default in our project.&lt;/p&gt;

&lt;p&gt;We can create a child of the &lt;code&gt;AdminConfig&lt;/code&gt; class like this:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;default_site&lt;/code&gt; attribute must match your &lt;code&gt;AdminSite&lt;/code&gt; class.&lt;/p&gt;

&lt;p&gt;Finally, register &lt;code&gt;AdminConfig&lt;/code&gt; in the settings.py in INSTALLED_APPS to complete the changes. Remember to remove the default admin panel.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;This new admin panel in its current form is not faster than the old one. We still need to cache &lt;code&gt;ModelAdmin&lt;/code&gt; methods. To do this, you can create a Mixin for ModelAdmin, and wrap the above methods as follows:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;I haven't had any problems with this caching implementation, but if you're worried about multiple calls to the same method with different arguments, you can wrap the methods with &lt;a href="https://docs.python.org/3/library/functools.html#functools.lru_cache" rel="noopener noreferrer"&gt;memoize wrapper&lt;/a&gt;. This can also reduce the speedboost of our solution.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I love the Django Framework. It's a powerful tool that helps me create great things. I can fix any problem of this framework with just a small piece of code in the right place. But finding that place is not always easy. And Django's documentation can't help. This lack of documentation - This is Django's biggest problem.    &lt;/p&gt;

&lt;h3&gt;
  
  
  Django devs
&lt;/h3&gt;

&lt;p&gt;I hope that after the points I have laid out in this article, you will agree that there are serious problems with Django's implementation of the singleton architecture in the admin panel.&lt;br&gt;
This pattern makes the admin panel experience cumbersome and slow, and something needs to be done to fix it. And I'm writing here how that can be done.&lt;/p&gt;

&lt;p&gt;The fix I've proposed is an important first step to improving the Django admin panel, but unfortunately the next work begins after its implementation. The ModelAdmin class code needs to be greatly improved, i ask about it, for example, &lt;a href="https://code.djangoproject.com/ticket/33028" rel="noopener noreferrer"&gt;in this issue&lt;/a&gt;, but if it can be done, I'm sure the Django admin panel will be a better tool to work with.&lt;/p&gt;
&lt;h3&gt;
  
  
  The Singleton Problem talk at PyCon 2022
&lt;/h3&gt;

&lt;p&gt;I have spoken about this problem at many events. You can see my video from PyCon DE in Berlin in April 2022, I &lt;a href="https://dev.to/danilovmy/the-python-and-django-conferences-you-dont-want-to-miss-in-2022-2ki0"&gt;wrote here&lt;/a&gt; that I will be speaking at that conference.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/Vg8E2fnoR78"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>django</category>
      <category>python</category>
    </item>
    <item>
      <title>The Python and Django conferences you don't want to miss in 2022</title>
      <dc:creator>Maxim Danilov</dc:creator>
      <pubDate>Sun, 10 Apr 2022 18:18:16 +0000</pubDate>
      <link>https://dev.to/danilovmy/the-python-and-django-conferences-you-dont-want-to-miss-in-2022-2ki0</link>
      <guid>https://dev.to/danilovmy/the-python-and-django-conferences-you-dont-want-to-miss-in-2022-2ki0</guid>
      <description>&lt;p&gt;Quick reminder for those, who would like to broaden their horizons: there is “&lt;a href="https://2022.pycon.de/"&gt;PyCon DE Berlin 2022&lt;/a&gt; ” coming up already next week!&lt;/p&gt;

&lt;p&gt;As an invited speaker I will cover three topics there:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;On Monday 11.04. at 16:20, lightning talk about &lt;strong&gt;„Django ModelAdmin Singleton Problem“&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rcTHeJpv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rc0bl2f30atq43hw2z8b.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rcTHeJpv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rc0bl2f30atq43hw2z8b.jpg" alt="Django ModelAdmin Singleton Problem" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
In this talk I will briefly describe the main problems of the &lt;code&gt;ModelAmin&lt;/code&gt; class from the&lt;br&gt;
&lt;code&gt;Django.contrib.admin.options&lt;/code&gt; module and solve this problem once and for all in 4 lines of code, summed up by the additional benefits of this solution.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Followed by &lt;strong&gt;"Django ModelAdmin autoregister on AdminSite"&lt;/strong&gt; lightning talk on Tuesday April 12, 2022 at 16:20. &lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1SQs0x9u--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cuo9wpiwvc20evw8tn1y.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1SQs0x9u--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cuo9wpiwvc20evw8tn1y.jpg" alt="Django ModelAdmin autoregister on AdminSite" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
In this talk I'm going to present the &lt;code&gt;ModelAmin&lt;/code&gt; autoregister on&lt;br&gt;
&lt;code&gt;AdminSite&lt;/code&gt; from &lt;code&gt;Django.contrib.admin.sites&lt;/code&gt; module and how that should have been done originally. Alas, it's not implemented in django yet. I'll fix that in 5 lines of code. I will show you&lt;br&gt;
how this solution will simplify code development, reduce the number of imports, and help you avoid possible circular dependencies.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;On wednesday April 13 at 11:00 am, I will have a 30 minutes presentation named &lt;strong&gt;“Easy Python: lies, damned lies, and metaclasses”&lt;/strong&gt;. &lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gqMi_s5I--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/krmc5shk2pgvvjk8b75c.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gqMi_s5I--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/krmc5shk2pgvvjk8b75c.jpg" alt="Easy Python: lies" width="800" height="450"&gt;&lt;/a&gt;&lt;br&gt;
Here I describe the python's suitability for large projects (spoiler alert), bring up "software complexity problem" and talk about the many levels of abstraction that python has inbox. I will as well talk about how those abstraction levels can&lt;br&gt;
both help and hinder large python projects.&lt;br&gt;
I would appreciate you joining the discussion and sharing your opinion on these topics. &lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you for some reason miss that one, the next conference is coming in September: &lt;strong&gt;&lt;a href="https://2022.djangocon.eu/"&gt;DjangoCon Europe 2022&lt;/a&gt;&lt;/strong&gt; in Portugal. &lt;/p&gt;

&lt;p&gt;I will make some expert talks and workshops there as well, including talk and workshop: &lt;br&gt;
&lt;strong&gt;“Hidden Gems in Django.Contrib.Admin”&lt;/strong&gt;, about effective Django SiteAdmin.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--S7yD6K71--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9kjxzx8ugiuse1tka0da.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--S7yD6K71--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9kjxzx8ugiuse1tka0da.jpg" alt="Hidden Gems in Django.Contrib.Admin" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'll unfold the hidden power of the django.contrib.admin module code, talk about it´s bugs in the code and of course some innovative fixing options.&lt;/p&gt;

&lt;p&gt;The other planned talk and workshop is called &lt;strong&gt;“Creation of true Multilinguale Django Project”&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--39Y4E_71--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t5kcta7igl2jm2uqt4os.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--39Y4E_71--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t5kcta7igl2jm2uqt4os.jpg" alt="Creation of true Multilinguale Django Project" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's about creating a real multi-lingual Django project, its problems, architectural peculiarities and the difficulties of implementation. I will present a new version of the &lt;code&gt;DJANGO-TOF&lt;/code&gt; library, which solves some of the essential problems.&lt;/p&gt;

&lt;h2&gt;
  
  
  In my opinion, expert talks at a Conference are not just the best way to present new ideas, but also the most efficient way to learn new things. It will be my pleasure to answer your questions and exchange opinions after the talks. Feel free to approach and contact me there and...
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;See you soon!&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>django</category>
      <category>conferences</category>
    </item>
    <item>
      <title>Django admin dynamic Inline positioning</title>
      <dc:creator>Maxim Danilov</dc:creator>
      <pubDate>Tue, 05 Apr 2022 09:16:15 +0000</pubDate>
      <link>https://dev.to/danilovmy/django-admin-dynamic-inline-positioning-3cam</link>
      <guid>https://dev.to/danilovmy/django-admin-dynamic-inline-positioning-3cam</guid>
      <description>&lt;p&gt;Recently I've received an interesting request from a client about one of our Django projects.&lt;br&gt;
He asked if it would be possible to show an inline component above other fields in the Django admin panel.&lt;/p&gt;

&lt;p&gt;At the beginning I thought, that there shouldn't be any issue with that.&lt;br&gt;
Though there was no easy solution other then installing another battery to the project. My gut feeling told me, there were another way around that problem.&lt;/p&gt;



&lt;p&gt;The first &lt;a href="https://linevi.ch/en/django-inline-in-fieldset.html" rel="noopener noreferrer"&gt;solution&lt;/a&gt; I found was from 2017. It had too much code for such a simple task.&lt;/p&gt;

&lt;p&gt;Our executive lead programmer, Maxim Danilov found quite a short solution. He &lt;a href="https://habr.com/ru/post/651179/" rel="noopener noreferrer"&gt;published his work online in russian&lt;/a&gt; about a month ago.&lt;/p&gt;

&lt;p&gt;I´d like to share these ideas with englisch speaking Django community in order to help others simplify their code. It might come handy for such a "simple" at first glance issues.&lt;/p&gt;

&lt;p&gt;Long story short, let's dive into the code:&lt;/p&gt;

&lt;p&gt;Imagine you are building an E-commerce project. You have a &lt;code&gt;ProductModel&lt;/code&gt;which have O2M relation to &lt;code&gt;ImageModel&lt;/code&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;You also need &lt;code&gt;ModelAdmins&lt;/code&gt; for given models.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Now let's create a simple inline to put into our &lt;code&gt;ProductModelAdmin&lt;/code&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;So far we have two simple models and basic &lt;code&gt;ModelAdmins&lt;/code&gt; with an &lt;code&gt;InlineModel&lt;/code&gt;. &lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd13w1ijzja145owlg4ho.JPG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd13w1ijzja145owlg4ho.JPG" alt="Normal ModelAdmin form with InlineModel"&gt;&lt;/a&gt;&lt;br&gt;
How should we squeeze that Inline above or in between the two fields of the &lt;code&gt;ProductModelAdmin&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;I suppose, you are familiar with the &lt;a href="https://docs.djangoproject.com/en/4.0/ref/contrib/admin/#django.contrib.admin.ModelAdmin.readonly_fields" rel="noopener noreferrer"&gt;added field&lt;/a&gt; concept in &lt;code&gt;ModelAdminForm&lt;/code&gt;. You can create a method in the &lt;code&gt;ModelAdmin&lt;/code&gt; to display the response of the method in the form as a readonly field.&lt;br&gt;
Keep in mind, that the rendering sequence of the &lt;code&gt;ModelAdmin&lt;/code&gt; will create the &lt;code&gt;InlineModels&lt;/code&gt; first, then render &lt;code&gt;AdminForm&lt;/code&gt; and after that render the &lt;code&gt;InlineForms&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We can use that to rearrange the order of Inlines and fields.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;We use the &lt;code&gt;render_change_form&lt;/code&gt; to get the objects &lt;code&gt;request&lt;/code&gt; and &lt;code&gt;response&lt;/code&gt;.&lt;br&gt;
We use those objects in the &lt;code&gt;image_inline&lt;/code&gt; method to take one &lt;code&gt;inline_formset&lt;/code&gt; from the list of &lt;code&gt;inline_admin_formsets&lt;/code&gt; that have not been processed yet, and render &lt;code&gt;InlineFormset&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;After the &lt;code&gt;change_form&lt;/code&gt; rendering the remaining  &lt;code&gt;inline_admin_formsets&lt;/code&gt; will be rendered, in case if the &lt;code&gt;ModelAdmin&lt;/code&gt; still has some.&lt;/p&gt;

&lt;p&gt;Now we can use the method &lt;code&gt;image_inline&lt;/code&gt; to determine the position of our &lt;code&gt;InlineFormset&lt;/code&gt;.&lt;br&gt;
With the code-snippet above the inline element will be placed above all other fields.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8t35ss63olnlytib03q7.JPG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8t35ss63olnlytib03q7.JPG" alt="Inline on top"&gt;&lt;/a&gt;&lt;br&gt;
When we rearrange the fields this way the inline is rendered between the fields:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Of course Django admin adds a lable infront of the Inline with the name of the method, but that can be easily removed by some simple CSS in &lt;code&gt;Media&lt;/code&gt; attribute of &lt;code&gt;ProductModelAdmin&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbsjiohjczg4gks47esbd.JPG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbsjiohjczg4gks47esbd.JPG" alt="Inline in between"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This solution has one fatal error! Every Django ModelAdmin is singelton, that is why we can not use ModelAdmin.self as a container in &lt;code&gt;render_change_form&lt;/code&gt;!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It is possible to change the ModelAdmins singleton´s behavior with a Mixin, staying inline with the concept of Djangos GCBV. We will take a closer look at it in my next article.&lt;/p&gt;

&lt;p&gt;It simply means, that we can't use the instance of the &lt;code&gt;ModelAdmin&lt;/code&gt; as a container to save our &lt;code&gt;request&lt;/code&gt; and &lt;code&gt;response&lt;/code&gt;.&lt;br&gt;
The solution is to save those objects in the &lt;code&gt;AdminForm&lt;/code&gt; instance.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The argument &lt;code&gt;obj&lt;/code&gt; is not always given in &lt;code&gt;render_change_form&lt;/code&gt; (i.e. add new object). That is why we have to get it from the &lt;code&gt;ModelForm&lt;/code&gt;, which is wrapped into the &lt;code&gt;AdminForm&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now we can set our request and response as attributes of the &lt;code&gt;ModelForm&lt;/code&gt; instance and use those in &lt;code&gt;image_inline&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Summing up the above: you don't have to install another battery to your project to solve a simple problem. Sometimes you need to dig deep enough into the framework that you use, and find a simple, short and quick solution.
&lt;/h4&gt;

&lt;p&gt;I´d like to thank Martin Achenrainer the intern of wPsoft for contributing to this article and translating it.&lt;/p&gt;

</description>
      <category>django</category>
      <category>python</category>
    </item>
  </channel>
</rss>
