{"@attributes":{"version":"2.0"},"channel":{"title":"DEV Community: U\u011fur \"vigo\" \u00d6zy\u0131lmazel","description":"The latest articles on DEV Community by U\u011fur \"vigo\" \u00d6zy\u0131lmazel (@vigo).","link":"https:\/\/dev.to\/vigo","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%2F34257%2F009ea4cb-cc58-41d6-af32-a223001cdef9.jpg","title":"DEV Community: U\u011fur \"vigo\" \u00d6zy\u0131lmazel","link":"https:\/\/dev.to\/vigo"},"language":"en","item":[{"title":"rmate with sudo","pubDate":"Fri, 03 Oct 2025 17:00:00 +0000","link":"https:\/\/dev.to\/vigo\/rmate-with-sudo-4cl0","guid":"https:\/\/dev.to\/vigo\/rmate-with-sudo-4cl0","description":"<p>I honestly don\u2019t know if there are still any dinosaurs like me using <strong>TextMate<\/strong><br>\nin 2025. But if you\u2019re a die-hard TextMate fan like I am, then I\u2019ve got some<br>\nexciting news for you. Have you ever heard of <code>rmate<\/code>?<\/p>\n\n<p><code>rmate<\/code> is actually a Ruby gem. What does it do? It lets you open a file from<br>\na remote server (via SSH) directly in your local TextMate editor\u2014just as if<br>\nyou had run <code>mate \/path\/to\/file<\/code> on your own machine.<\/p>\n\n<p>In TextMate, under <strong>Settings &gt; Terminal<\/strong>, there\u2019s an option called <strong>Accept rmate connections<\/strong>\u2014make sure that\u2019s checked first.  <\/p>\n\n<p><a href=\"https:\/\/media2.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%2F5709jiu8xqd97rr17npl.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media2.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%2F5709jiu8xqd97rr17npl.png\" alt=\"TextMate &gt; Settings &gt; Terminal\" width=\"800\" height=\"652\"><\/a><\/p>\n\n<p>Next, connect to your VPS via SSH and install Ruby, followed by <code>rmate<\/code>, using the commands below. Let\u2019s assume you\u2019re using <strong>Ubuntu<\/strong> as your VPS operating system:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code><span class=\"nb\">sudo <\/span>apt <span class=\"nb\">install <\/span>ruby <span class=\"nt\">-y<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Now, find the location for user installation directory for<br>\nruby gems:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>gem environment | <span class=\"nb\">grep<\/span> <span class=\"s2\">\"USER INSTALLATION DIRECTORY\"<\/span> | <span class=\"nb\">awk<\/span> <span class=\"nt\">-F<\/span><span class=\"s1\">': '<\/span> <span class=\"s1\">'{print $2}'<\/span>\n<span class=\"c\"># something like:<\/span>\n<span class=\"c\"># \/home\/ubuntu\/.local\/share\/gem\/ruby\/3.2.0\/bin<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Now, edit your <code>~\/.bashrc<\/code> and add this path to your <code>PATH<\/code> environment<br>\nvariable:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code><span class=\"c\"># set PATH if local ruby gems bin exists<\/span>\n<span class=\"nv\">PATH<\/span><span class=\"o\">=<\/span><span class=\"s2\">\"<\/span><span class=\"k\">${<\/span><span class=\"nv\">PATH<\/span><span class=\"k\">}<\/span><span class=\"s2\">:<\/span><span class=\"k\">${<\/span><span class=\"nv\">HOME<\/span><span class=\"k\">}<\/span><span class=\"s2\">\/.local\/share\/gem\/ruby\/3.2.0\/bin\"<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Save and exit from <code>nano<\/code>. Now install <code>rmate<\/code>:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>gem <span class=\"nb\">install<\/span> <span class=\"nt\">--user-install<\/span> rmate\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Now, restart your shell, logout\/login works fine. Now run:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code><span class=\"nb\">sudo <\/span>visudo\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Edit your sudo configuration, Two changes, add <code>env_keep<\/code> and append<br>\n<code>\/home\/ubuntu\/.local\/share\/gem\/ruby\/3.2.0\/bin<\/code> to <code>secure_path<\/code> under the line<br>\nof <code>Defaults env_reset<\/code>:<\/p>\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>Defaults        env_reset\nDefaults        env_keep +=\"RMATE_HOST\"\nDefaults        secure_path=\"\/usr\/local\/sbin:\/usr\/local\/bin:\/usr\/sbin:\/usr\/bin:\/sbin:\/bin:\/snap\/bin:\/home\/ubuntu\/.local\/share\/gem\/ruby\/3.2.0\/bin\"\n<\/code><\/pre>\n\n<\/div>\n<p>Now, restart your shell, logout\/login works fine. Now open (as an example):<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code><span class=\"nb\">sudo<\/span> <span class=\"nt\">-E<\/span> rmate \/etc\/nginx\/nginx.conf\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><code>sudo -E<\/code> does the trick! <code>-E<\/code> keeps environment variables which are defined<br>\nin <code>env_keep<\/code>.<\/p>\n\n<p>Thats all! Keep the <strong>TextMate<\/strong> spirit alive! (<em>macOS only<\/em>)<\/p>\n\n","category":["textmate","macos","vps","ssh"]},{"title":"Django Model Best Practices","pubDate":"Thu, 26 Aug 2021 11:13:31 +0000","link":"https:\/\/dev.to\/vigo\/django-model-best-practices-3e8e","guid":"https:\/\/dev.to\/vigo\/django-model-best-practices-3e8e","description":"<p>I've been writing Django apps since 2008. Here are some Django Model tips that I've collected, applied over the years.<\/p>\n\n<h2>\n  \n  \n  Model Writing Rules\n<\/h2>\n\n<p>Before you do anything, please <a href=\"https:\/\/docs.djangoproject.com\/en\/3.2\/internals\/contributing\/writing-code\/coding-style\/#model-style\">visit and read this doc<\/a>. Django documentation is your friend!<\/p>\n\n<p>Doc tells that, there is a rule\/order in the Model class:<\/p>\n\n<ol>\n<li>All field declarations <\/li>\n<li>Custom manager attributes<\/li>\n<li><code>class Meta<\/code><\/li>\n<li><code>def __str__()<\/code><\/li>\n<li><code>def save()<\/code><\/li>\n<li><code>def get_absolute_url()<\/code><\/li>\n<li>You custom methods, properties etc...<\/li>\n<\/ol>\n\n<p>Here is an example:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"k\">def<\/span> <span class=\"nf\">get_group_creator_sentinel<\/span><span class=\"p\">():<\/span>\n    <span class=\"n\">payload<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">dict<\/span><span class=\"p\">(<\/span>\n        <span class=\"n\">email<\/span><span class=\"o\">=<\/span><span class=\"sh\">'<\/span><span class=\"s\">deleted@xxx.com<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n        <span class=\"n\">first_name<\/span><span class=\"o\">=<\/span><span class=\"sh\">'<\/span><span class=\"s\">Sentinel<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n        <span class=\"n\">last_name<\/span><span class=\"o\">=<\/span><span class=\"sh\">'<\/span><span class=\"s\">User<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n    <span class=\"p\">)<\/span>\n    <span class=\"k\">return<\/span> <span class=\"nf\">get_user_model<\/span><span class=\"p\">().<\/span><span class=\"n\">objects<\/span><span class=\"p\">.<\/span><span class=\"nf\">get_or_create<\/span><span class=\"p\">(<\/span><span class=\"o\">**<\/span><span class=\"n\">payload<\/span><span class=\"p\">,<\/span> <span class=\"n\">defaults<\/span><span class=\"o\">=<\/span><span class=\"n\">payload<\/span><span class=\"p\">)[<\/span><span class=\"mi\">0<\/span><span class=\"p\">]<\/span>\n\n<span class=\"k\">class<\/span> <span class=\"nc\">Group<\/span><span class=\"p\">(<\/span><span class=\"n\">models<\/span><span class=\"p\">.<\/span><span class=\"n\">Model<\/span><span class=\"p\">):<\/span>\n    <span class=\"sh\">\"\"\"<\/span><span class=\"s\">\n    User.objects.filter(group__name=...)\n    Permission.objects.filter(group__name=...)\n    <\/span><span class=\"sh\">\"\"\"<\/span>\n\n    <span class=\"n\">name<\/span> <span class=\"o\">=<\/span> <span class=\"n\">models<\/span><span class=\"p\">.<\/span><span class=\"nc\">CharField<\/span><span class=\"p\">(<\/span>\n        <span class=\"n\">max_length<\/span><span class=\"o\">=<\/span><span class=\"mi\">150<\/span><span class=\"p\">,<\/span> \n        <span class=\"n\">unique<\/span><span class=\"o\">=<\/span><span class=\"bp\">True<\/span><span class=\"p\">,<\/span> \n        <span class=\"n\">verbose_name<\/span><span class=\"o\">=<\/span><span class=\"nf\">_<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">name<\/span><span class=\"sh\">'<\/span><span class=\"p\">),<\/span>\n    <span class=\"p\">)<\/span>\n    <span class=\"n\">creator<\/span> <span class=\"o\">=<\/span> <span class=\"n\">models<\/span><span class=\"p\">.<\/span><span class=\"nc\">ForeignKey<\/span><span class=\"p\">(<\/span>\n        <span class=\"n\">to<\/span><span class=\"o\">=<\/span><span class=\"n\">settings<\/span><span class=\"p\">.<\/span><span class=\"n\">AUTH_USER_MODEL<\/span><span class=\"p\">,<\/span>\n        <span class=\"n\">on_delete<\/span><span class=\"o\">=<\/span><span class=\"n\">models<\/span><span class=\"p\">.<\/span><span class=\"nc\">SET<\/span><span class=\"p\">(<\/span><span class=\"n\">get_group_creator_sentinel<\/span><span class=\"p\">),<\/span>\n        <span class=\"n\">related_name<\/span><span class=\"o\">=<\/span><span class=\"sh\">'<\/span><span class=\"s\">creator_groups<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n        <span class=\"n\">related_query_name<\/span><span class=\"o\">=<\/span><span class=\"sh\">'<\/span><span class=\"s\">group<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n        <span class=\"n\">verbose_name<\/span><span class=\"o\">=<\/span><span class=\"nf\">_<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">creator<\/span><span class=\"sh\">'<\/span><span class=\"p\">),<\/span>\n    <span class=\"p\">)<\/span>\n    <span class=\"n\">permissions<\/span> <span class=\"o\">=<\/span> <span class=\"n\">models<\/span><span class=\"p\">.<\/span><span class=\"nc\">ManyToManyField<\/span><span class=\"p\">(<\/span>\n        <span class=\"n\">to<\/span><span class=\"o\">=<\/span><span class=\"n\">Permission<\/span><span class=\"p\">,<\/span>\n        <span class=\"n\">related_name<\/span><span class=\"o\">=<\/span><span class=\"sh\">'<\/span><span class=\"s\">permissions_groups<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n        <span class=\"n\">related_query_name<\/span><span class=\"o\">=<\/span><span class=\"sh\">'<\/span><span class=\"s\">group<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n        <span class=\"n\">verbose_name<\/span><span class=\"o\">=<\/span><span class=\"nf\">_<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">permissions<\/span><span class=\"sh\">'<\/span><span class=\"p\">),<\/span>\n        <span class=\"n\">blank<\/span><span class=\"o\">=<\/span><span class=\"bp\">True<\/span><span class=\"p\">,<\/span>\n    <span class=\"p\">)<\/span>\n    <span class=\"n\">objects<\/span> <span class=\"o\">=<\/span> <span class=\"nc\">GroupManager<\/span><span class=\"p\">()<\/span>\n\n    <span class=\"k\">class<\/span> <span class=\"nc\">Meta<\/span><span class=\"p\">:<\/span>\n        <span class=\"n\">app_label<\/span> <span class=\"o\">=<\/span> <span class=\"sh\">'<\/span><span class=\"s\">core<\/span><span class=\"sh\">'<\/span>\n        <span class=\"n\">verbose_name<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">_<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">group<\/span><span class=\"sh\">'<\/span><span class=\"p\">)<\/span>\n        <span class=\"n\">verbose_name_plural<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">_<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">groups<\/span><span class=\"sh\">'<\/span><span class=\"p\">)<\/span>\n\n    <span class=\"k\">def<\/span> <span class=\"nf\">__str__<\/span><span class=\"p\">(<\/span><span class=\"n\">self<\/span><span class=\"p\">):<\/span>\n        <span class=\"k\">return<\/span> <span class=\"n\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">name<\/span>\n\n    <span class=\"k\">def<\/span> <span class=\"nf\">natural_key<\/span><span class=\"p\">(<\/span><span class=\"n\">self<\/span><span class=\"p\">):<\/span>\n        <span class=\"nf\">return <\/span><span class=\"p\">(<\/span><span class=\"n\">self<\/span><span class=\"p\">.<\/span><span class=\"n\">name<\/span><span class=\"p\">,)<\/span>\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h2>\n  \n  \n  Correct Model Name\n<\/h2>\n\n<p>Model stands for a single element in the database. Model name should be singular. In some cases, Model name can be plural if you are building intermediate relations table since this is a different situation. <\/p>\n\n<p>Some good model name examples:<\/p>\n\n<ul>\n<li><code>Post<\/code><\/li>\n<li><code>Article<\/code><\/li>\n<li><code>User<\/code><\/li>\n<li><code>Person<\/code><\/li>\n<\/ul>\n\n<h2>\n  \n  \n  Set Table Names Manually\n<\/h2>\n\n<p>If possible, set the table name by hand in <code>Meta<\/code> class. This helps you to have smaller table names and allows you to know database better.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"k\">class<\/span> <span class=\"nc\">Customer<\/span><span class=\"p\">(<\/span><span class=\"n\">models<\/span><span class=\"p\">.<\/span><span class=\"n\">Model<\/span><span class=\"p\">):<\/span>\n    <span class=\"p\">:<\/span>\n    <span class=\"k\">class<\/span> <span class=\"nc\">Meta<\/span><span class=\"p\">:<\/span>\n        <span class=\"n\">app_label<\/span> <span class=\"o\">=<\/span> <span class=\"sh\">'<\/span><span class=\"s\">core<\/span><span class=\"sh\">'<\/span>\n        <span class=\"n\">db_table<\/span> <span class=\"o\">=<\/span> <span class=\"sh\">'<\/span><span class=\"s\">customer<\/span><span class=\"sh\">'<\/span>\n        <span class=\"n\">verbose_name<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">_<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">customer<\/span><span class=\"sh\">'<\/span><span class=\"p\">)<\/span>\n        <span class=\"n\">verbose_name_plural<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">_<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">customers<\/span><span class=\"sh\">'<\/span><span class=\"p\">)<\/span>\n    <span class=\"p\">:<\/span>\n    <span class=\"p\">:<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h2>\n  \n  \n  Don't Forget to Add <code>created_at<\/code> and <code>updated_at<\/code> Fields\n<\/h2>\n\n<p>In my projects, I always use a <code>base.py<\/code> and put an abstract class for common usage:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"k\">class<\/span> <span class=\"nc\">MyBaseModel<\/span><span class=\"p\">(<\/span><span class=\"n\">models<\/span><span class=\"p\">.<\/span><span class=\"n\">Model<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">created_at<\/span> <span class=\"o\">=<\/span> <span class=\"n\">models<\/span><span class=\"p\">.<\/span><span class=\"nc\">DateTimeField<\/span><span class=\"p\">(<\/span><span class=\"n\">auto_now_add<\/span><span class=\"o\">=<\/span><span class=\"bp\">True<\/span><span class=\"p\">,<\/span> <span class=\"n\">verbose_name<\/span><span class=\"o\">=<\/span><span class=\"nf\">_<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">created at<\/span><span class=\"sh\">'<\/span><span class=\"p\">))<\/span>\n    <span class=\"n\">updated_at<\/span> <span class=\"o\">=<\/span> <span class=\"n\">models<\/span><span class=\"p\">.<\/span><span class=\"nc\">DateTimeField<\/span><span class=\"p\">(<\/span><span class=\"n\">auto_now<\/span><span class=\"o\">=<\/span><span class=\"bp\">True<\/span><span class=\"p\">,<\/span> <span class=\"n\">verbose_name<\/span><span class=\"o\">=<\/span><span class=\"nf\">_<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">updated at<\/span><span class=\"sh\">'<\/span><span class=\"p\">))<\/span>\n\n    <span class=\"k\">class<\/span> <span class=\"nc\">Meta<\/span><span class=\"p\">:<\/span>\n        <span class=\"n\">abstract<\/span> <span class=\"o\">=<\/span> <span class=\"bp\">True<\/span>\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>I sometimes add <code>deleted_at<\/code> or <code>is_active<\/code> if required.<\/p>\n\n<h2>\n  \n  \n  Related Field Definition\n<\/h2>\n\n<p>I mostly collect all my models under a single app. This helps me to use <strong>short hand reference<\/strong> and keeps me avoiding circular imports.<\/p>\n\n<p>With this usage style, I don't need to import models all the time! I use <code>to='ModelName'<\/code> convention.<\/p>\n\n<p>Let's say we have an <code>Article<\/code> model and <code>Article<\/code> model has a user field:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"kn\">from<\/span> <span class=\"n\">django.conf<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">settings<\/span>\n\n<span class=\"k\">class<\/span> <span class=\"nc\">Article<\/span><span class=\"p\">(<\/span><span class=\"n\">models<\/span><span class=\"p\">.<\/span><span class=\"n\">Model<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">user<\/span> <span class=\"o\">=<\/span> <span class=\"n\">models<\/span><span class=\"p\">.<\/span><span class=\"nc\">ForeignKey<\/span><span class=\"p\">(<\/span>\n        <span class=\"n\">to<\/span><span class=\"o\">=<\/span><span class=\"n\">settings<\/span><span class=\"p\">.<\/span><span class=\"n\">AUTH_USER_MODEL<\/span><span class=\"p\">,<\/span>\n        <span class=\"n\">on_delete<\/span><span class=\"o\">=<\/span><span class=\"n\">models<\/span><span class=\"p\">.<\/span><span class=\"n\">CASCADE<\/span><span class=\"p\">,<\/span>\n        <span class=\"p\">:<\/span>\n        <span class=\"p\">:<\/span>\n    <span class=\"p\">)<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>or I have a <code>City<\/code> model and <code>City<\/code> has <code>Country<\/code> model relation;<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"k\">class<\/span> <span class=\"nc\">City<\/span><span class=\"p\">(<\/span><span class=\"n\">models<\/span><span class=\"p\">.<\/span><span class=\"n\">Model<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">country<\/span> <span class=\"o\">=<\/span> <span class=\"n\">models<\/span><span class=\"p\">.<\/span><span class=\"nc\">ForeignKey<\/span><span class=\"p\">(<\/span>\n        <span class=\"n\">to<\/span><span class=\"o\">=<\/span><span class=\"sh\">'<\/span><span class=\"s\">Country<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n        <span class=\"n\">on_delete<\/span><span class=\"o\">=<\/span><span class=\"n\">models<\/span><span class=\"p\">.<\/span><span class=\"n\">CASCADE<\/span><span class=\"p\">,<\/span>\n        <span class=\"n\">related_name<\/span><span class=\"o\">=<\/span><span class=\"sh\">'<\/span><span class=\"s\">cities<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n        <span class=\"n\">related_query_name<\/span><span class=\"o\">=<\/span><span class=\"sh\">'<\/span><span class=\"s\">city<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n        <span class=\"n\">verbose_name<\/span><span class=\"o\">=<\/span><span class=\"nf\">_<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">country<\/span><span class=\"sh\">'<\/span><span class=\"p\">),<\/span>\n    <span class=\"p\">)<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>If you don't want to collect all models in a same app, you use <code>to='app_name.Model'<\/code> too. Such as <code>to='auth.Group'<\/code>...<\/p>\n\n<h2>\n  \n  \n  Always Add <code>related_name<\/code> and <code>related_query_name<\/code> Options\n<\/h2>\n\n<p>If you <code>ForeignKey<\/code> or <code>ManyToMany<\/code> field, always set <code>related_name<\/code> and <code>related_query_name<\/code>:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"k\">class<\/span> <span class=\"nc\">City<\/span><span class=\"p\">(<\/span><span class=\"n\">models<\/span><span class=\"p\">.<\/span><span class=\"n\">Model<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">country<\/span> <span class=\"o\">=<\/span> <span class=\"n\">models<\/span><span class=\"p\">.<\/span><span class=\"nc\">ForeignKey<\/span><span class=\"p\">(<\/span>\n        <span class=\"n\">to<\/span><span class=\"o\">=<\/span><span class=\"sh\">'<\/span><span class=\"s\">Country<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n        <span class=\"n\">on_delete<\/span><span class=\"o\">=<\/span><span class=\"n\">models<\/span><span class=\"p\">.<\/span><span class=\"n\">CASCADE<\/span><span class=\"p\">,<\/span>\n        <span class=\"n\">related_name<\/span><span class=\"o\">=<\/span><span class=\"sh\">'<\/span><span class=\"s\">cities<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n        <span class=\"n\">related_query_name<\/span><span class=\"o\">=<\/span><span class=\"sh\">'<\/span><span class=\"s\">city<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n        <span class=\"n\">verbose_name<\/span><span class=\"o\">=<\/span><span class=\"nf\">_<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">country<\/span><span class=\"sh\">'<\/span><span class=\"p\">),<\/span>\n    <span class=\"p\">)<\/span>\n    <span class=\"p\">:<\/span>\n    <span class=\"p\">:<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>From <code>Country<\/code> instance, you can query cities via <code>country.cities.filter()<\/code>. You can use in the lookups too: <code>Country.objects.filter(city__name='xxx')<\/code>.<\/p>\n\n<h2>\n  \n  \n  Never Use <code>unique=True<\/code> for <code>ForeignKey<\/code>\n<\/h2>\n\n<p>Why? Because you have <code>OneToOneField<\/code> for that!<\/p>\n\n<h2>\n  \n  \n  Use <code>NullBooleanField<\/code>\n<\/h2>\n\n<p>Instead of <code>models.BooleanField(null=True)<\/code><\/p>\n\n<h2>\n  \n  \n  Use <code>Model.DoesNotExist<\/code>\n<\/h2>\n\n<p>Instead of <code>ObjectDoesNotExist<\/code>:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"p\">:<\/span>\n<span class=\"p\">:<\/span>\n<span class=\"k\">try<\/span><span class=\"p\">:<\/span>\n    <span class=\"n\">creator<\/span> <span class=\"o\">=<\/span> <span class=\"n\">user_model<\/span><span class=\"p\">.<\/span><span class=\"n\">objects<\/span><span class=\"p\">.<\/span><span class=\"nf\">get<\/span><span class=\"p\">(<\/span><span class=\"n\">email<\/span><span class=\"o\">=<\/span><span class=\"n\">email<\/span><span class=\"p\">)<\/span>\n<span class=\"k\">except<\/span> <span class=\"n\">user_model<\/span><span class=\"p\">.<\/span><span class=\"n\">DoesNotExist<\/span> <span class=\"k\">as<\/span> <span class=\"n\">exc<\/span><span class=\"p\">:<\/span>\n    <span class=\"k\">raise<\/span> <span class=\"nc\">CommandError<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">email (%s) does not exists<\/span><span class=\"sh\">'<\/span> <span class=\"o\">%<\/span> <span class=\"n\">email<\/span><span class=\"p\">)<\/span> <span class=\"k\">from<\/span> <span class=\"n\">exc<\/span>\n<span class=\"p\">:<\/span>\n<span class=\"p\">:<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><code>ObjectDoesNotExist<\/code> is useful when checking relational lookups over <code>OneToOneField<\/code>!<\/p>\n\n<h2>\n  \n  \n  <code>choices<\/code> Usage\n<\/h2>\n\n<p>If you are oldskool like me, use this convention.<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"kn\">from<\/span> <span class=\"n\">django.utils.translation<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">gettext_lazy<\/span> <span class=\"k\">as<\/span> <span class=\"n\">_<\/span>\n<span class=\"kn\">from<\/span> <span class=\"n\">django.db<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">models<\/span>\n\n<span class=\"k\">class<\/span> <span class=\"nc\">Post<\/span><span class=\"p\">(<\/span><span class=\"n\">models<\/span><span class=\"p\">.<\/span><span class=\"n\">Model<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">STATUS_OFFLINE<\/span> <span class=\"o\">=<\/span> <span class=\"mi\">0<\/span>\n    <span class=\"n\">STATUS_ONLINE<\/span> <span class=\"o\">=<\/span> <span class=\"mi\">1<\/span>\n    <span class=\"n\">STATUS_DELETED<\/span> <span class=\"o\">=<\/span> <span class=\"mi\">2<\/span>\n    <span class=\"n\">STATUS_DRAFT<\/span> <span class=\"o\">=<\/span> <span class=\"mi\">3<\/span>\n    <span class=\"n\">STATUS_CHOICES<\/span> <span class=\"o\">=<\/span> <span class=\"p\">(<\/span>\n        <span class=\"p\">(<\/span><span class=\"n\">STATUS_OFFLINE<\/span><span class=\"p\">,<\/span> <span class=\"nf\">_<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">offline<\/span><span class=\"sh\">'<\/span><span class=\"p\">)),<\/span>\n        <span class=\"p\">(<\/span><span class=\"n\">STATUS_ONLINE<\/span><span class=\"p\">,<\/span> <span class=\"nf\">_<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">online<\/span><span class=\"sh\">'<\/span><span class=\"p\">)),<\/span>\n        <span class=\"p\">(<\/span><span class=\"n\">STATUS_DELETED<\/span><span class=\"p\">,<\/span> <span class=\"nf\">_<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">deleted<\/span><span class=\"sh\">'<\/span><span class=\"p\">)),<\/span>\n        <span class=\"p\">(<\/span><span class=\"n\">STATUS_DRAFT<\/span><span class=\"p\">,<\/span> <span class=\"nf\">_<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">draft<\/span><span class=\"sh\">'<\/span><span class=\"p\">)),<\/span>\n    <span class=\"p\">)<\/span>\n\n    <span class=\"n\">status<\/span> <span class=\"o\">=<\/span> <span class=\"n\">models<\/span><span class=\"p\">.<\/span><span class=\"nc\">IntegerField<\/span><span class=\"p\">(<\/span>\n        <span class=\"n\">choices<\/span><span class=\"o\">=<\/span><span class=\"n\">STATUS_CHOICES<\/span><span class=\"p\">,<\/span>\n        <span class=\"n\">default<\/span><span class=\"o\">=<\/span><span class=\"n\">STATUS_ONLINE<\/span><span class=\"p\">,<\/span>\n        <span class=\"n\">verbose_name<\/span><span class=\"o\">=<\/span><span class=\"nf\">_<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">status<\/span><span class=\"sh\">'<\/span><span class=\"p\">),<\/span>\n    <span class=\"p\">)<\/span>\n    <span class=\"p\">:<\/span>\n    <span class=\"p\">:<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Django has <a href=\"https:\/\/docs.djangoproject.com\/en\/3.2\/ref\/models\/fields\/#enumeration-types\">enumeration types<\/a> now, you can take a look at it for different approach.<\/p>\n\n<h2>\n  \n  \n  Better Field Names\n<\/h2>\n\n<p>If you have a <code>User<\/code> model, do not add <code>user_status<\/code> field. Make it shorter, just <code>status<\/code>. No need to repeat <code>user<\/code> word.<\/p>\n\n<h2>\n  \n  \n  <code>models\/<\/code> Package Instead of <code>models.py<\/code>\n<\/h2>\n\n<p>When project grows, <code>models.py<\/code> file becomes too long. I always put my models separately in a models package:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>models\/\n    __init__.py\n    user.py\n    post.py\n    comment.py\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>In the <code>__init__.py<\/code> file:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"kn\">from<\/span> <span class=\"n\">.user<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">User<\/span>\n<span class=\"kn\">from<\/span> <span class=\"n\">.post<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">Post<\/span>\n<span class=\"p\">:<\/span>\n<span class=\"p\">:<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>In the model file, I add <code>__all__ = ['ModelName']<\/code>;<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"kn\">from<\/span> <span class=\"n\">django.db<\/span> <span class=\"kn\">import<\/span> <span class=\"n\">models<\/span>\n\n<span class=\"n\">__all__<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">City<\/span><span class=\"sh\">'<\/span><span class=\"p\">]<\/span>\n\n<span class=\"k\">class<\/span> <span class=\"nc\">City<\/span><span class=\"p\">(<\/span><span class=\"n\">models<\/span><span class=\"p\">.<\/span><span class=\"n\">Model<\/span><span class=\"p\">):<\/span>\n    <span class=\"p\">:<\/span>\n    <span class=\"p\">:<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h2>\n  \n  \n  Always Use Your Own <code>ManyToMany<\/code> Table\n<\/h2>\n\n<p>If you have <code>ManyToMany<\/code> field in your model, Django handles everything for you. You have no control over that extra table, model, model's save method or migration.<\/p>\n\n<p>What happens when you need to keep extra fields in that intermediate table? <code>through<\/code> and <code>through_fields<\/code> is your friend:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"k\">class<\/span> <span class=\"nc\">Customer<\/span><span class=\"p\">(<\/span><span class=\"n\">models<\/span><span class=\"p\">.<\/span><span class=\"n\">Model<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">name<\/span> <span class=\"o\">=<\/span> <span class=\"n\">models<\/span><span class=\"p\">.<\/span><span class=\"nc\">CharField<\/span><span class=\"p\">(<\/span><span class=\"n\">max_length<\/span><span class=\"o\">=<\/span><span class=\"mi\">100<\/span><span class=\"p\">,<\/span> <span class=\"n\">verbose_name<\/span><span class=\"o\">=<\/span><span class=\"nf\">_<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">name<\/span><span class=\"sh\">'<\/span><span class=\"p\">))<\/span>\n    <span class=\"n\">users<\/span> <span class=\"o\">=<\/span> <span class=\"n\">models<\/span><span class=\"p\">.<\/span><span class=\"nc\">ManyToManyField<\/span><span class=\"p\">(<\/span>\n        <span class=\"n\">to<\/span><span class=\"o\">=<\/span><span class=\"n\">settings<\/span><span class=\"p\">.<\/span><span class=\"n\">AUTH_USER_MODEL<\/span><span class=\"p\">,<\/span>\n        <span class=\"n\">through<\/span><span class=\"o\">=<\/span><span class=\"sh\">'<\/span><span class=\"s\">CustomerMembership<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n        <span class=\"n\">through_fields<\/span><span class=\"o\">=<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">customer<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"sh\">'<\/span><span class=\"s\">user<\/span><span class=\"sh\">'<\/span><span class=\"p\">),<\/span>\n        <span class=\"n\">related_name<\/span><span class=\"o\">=<\/span><span class=\"sh\">'<\/span><span class=\"s\">customers<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n        <span class=\"n\">related_query_name<\/span><span class=\"o\">=<\/span><span class=\"sh\">'<\/span><span class=\"s\">customer<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n        <span class=\"n\">blank<\/span><span class=\"o\">=<\/span><span class=\"bp\">True<\/span><span class=\"p\">,<\/span>\n        <span class=\"n\">verbose_name<\/span><span class=\"o\">=<\/span><span class=\"nf\">_<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">users<\/span><span class=\"sh\">'<\/span><span class=\"p\">),<\/span>\n    <span class=\"p\">)<\/span>\n    <span class=\"p\">:<\/span>\n    <span class=\"p\">:<\/span>\n\n<span class=\"k\">class<\/span> <span class=\"nc\">CustomerMembership<\/span><span class=\"p\">(<\/span><span class=\"n\">models<\/span><span class=\"p\">.<\/span><span class=\"n\">Model<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">customer<\/span> <span class=\"o\">=<\/span> <span class=\"n\">models<\/span><span class=\"p\">.<\/span><span class=\"nc\">ForeignKey<\/span><span class=\"p\">(<\/span>\n        <span class=\"n\">to<\/span><span class=\"o\">=<\/span><span class=\"sh\">'<\/span><span class=\"s\">Customer<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span>\n        <span class=\"n\">on_delete<\/span><span class=\"o\">=<\/span><span class=\"n\">models<\/span><span class=\"p\">.<\/span><span class=\"n\">CASCADE<\/span><span class=\"p\">,<\/span>\n    <span class=\"p\">)<\/span>\n    <span class=\"n\">user<\/span> <span class=\"o\">=<\/span> <span class=\"n\">models<\/span><span class=\"p\">.<\/span><span class=\"nc\">ForeignKey<\/span><span class=\"p\">(<\/span>\n        <span class=\"n\">to<\/span><span class=\"o\">=<\/span><span class=\"n\">settings<\/span><span class=\"p\">.<\/span><span class=\"n\">AUTH_USER_MODEL<\/span><span class=\"p\">,<\/span>\n        <span class=\"n\">on_delete<\/span><span class=\"o\">=<\/span><span class=\"n\">models<\/span><span class=\"p\">.<\/span><span class=\"n\">CASCADE<\/span><span class=\"p\">,<\/span>\n    <span class=\"p\">)<\/span>\n    <span class=\"n\">is_admin<\/span> <span class=\"o\">=<\/span> <span class=\"n\">models<\/span><span class=\"p\">.<\/span><span class=\"nc\">BooleanField<\/span><span class=\"p\">(<\/span>\n        <span class=\"n\">default<\/span><span class=\"o\">=<\/span><span class=\"bp\">False<\/span><span class=\"p\">,<\/span>\n        <span class=\"n\">verbose_name<\/span><span class=\"o\">=<\/span><span class=\"nf\">_<\/span><span class=\"p\">(<\/span><span class=\"sh\">'<\/span><span class=\"s\">customer admin status<\/span><span class=\"sh\">'<\/span><span class=\"p\">),<\/span>\n    <span class=\"p\">)<\/span>\n    <span class=\"p\">:<\/span>\n    <span class=\"p\">:<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Now we have full control over <code>CustomerMembership<\/code> model. It's a regular model now! Django Admin also have great support for through operations:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight python\"><code><span class=\"k\">class<\/span> <span class=\"nc\">CustomerInlineAdmin<\/span><span class=\"p\">(<\/span><span class=\"n\">models<\/span><span class=\"p\">.<\/span><span class=\"n\">TabularInlineAdmin<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">model<\/span> <span class=\"o\">=<\/span> <span class=\"n\">Customer<\/span><span class=\"p\">.<\/span><span class=\"n\">users<\/span><span class=\"p\">.<\/span><span class=\"n\">through<\/span>\n    <span class=\"n\">extra<\/span> <span class=\"o\">=<\/span> <span class=\"mi\">0<\/span>\n    <span class=\"n\">autocomplete_fields<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">customer<\/span><span class=\"sh\">'<\/span><span class=\"p\">,<\/span> <span class=\"sh\">'<\/span><span class=\"s\">user<\/span><span class=\"sh\">'<\/span><span class=\"p\">]<\/span>\n    <span class=\"p\">:<\/span>\n    <span class=\"p\">:<\/span>\n\n<span class=\"k\">class<\/span> <span class=\"nc\">CustomerAdmin<\/span><span class=\"p\">(<\/span><span class=\"n\">admin<\/span><span class=\"p\">.<\/span><span class=\"n\">ModelAdmin<\/span><span class=\"p\">):<\/span>\n    <span class=\"n\">list_display<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">__str__<\/span><span class=\"sh\">'<\/span><span class=\"p\">]<\/span>\n    <span class=\"n\">autocomplete_fields<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">users<\/span><span class=\"sh\">'<\/span><span class=\"p\">]<\/span>\n    <span class=\"n\">ordering<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span><span class=\"sh\">'<\/span><span class=\"s\">name<\/span><span class=\"sh\">'<\/span><span class=\"p\">]<\/span>\n    <span class=\"n\">inlines<\/span> <span class=\"o\">=<\/span> <span class=\"p\">[<\/span><span class=\"n\">CustomerInlineAdmin<\/span><span class=\"p\">]<\/span>\n    <span class=\"p\">:<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Lastly, always consider\/plan about your upcoming queries. Design your model against your future lookups. Maybe you need to filter\/report your model for YEAR only. You need to make date lookup such as <code>created_at__year=2021<\/code> or against <code>month<\/code> or <code>day<\/code>. Maybe it's better to add an integer field to hold year or month or day value? Querying an integer field will always be easy if you compare to date query...<\/p>\n\n<p>I hope you enjoyed these tips &amp; tricks! Happy programming!<\/p>\n\n","category":"django"}]}}