Pregunta

I am in the middle of a development in Django and we got some doubts about if we should use or not constants in the project. Exactly the situation is to use constants everywhere or not (we know constants in Django are not really read-only).

There are 2 scenarios and I would like to get your opinion about which one is better for you and why:

Scenario 1 (using constants)

constants.py

class CONST():
    def NAME(): return "name"
    def SURNAME(): return "surname"
    def ZIPCODE(): return "zipcode"
    def CITY(): return "city"
    def CREATED(): return "created"

admin.py

from constants import CONST
class RegisterAdmin(admin.ModelAdmin):
    list_display = (CONST.NAME(),CONST.SURNAME(),CONS.ZIPCODE())
    list_filter = [CONST.ZIPCODE(),CONST.CITY()]
    search_fields = [CONST.NAME(), CONST.SURNAME()]
    date_hierarchy = CONST.CREATED()

models.py

from constants import CONST
class Register(models.Model):
    name = models.CharField(CONST.NAME(), max_length=25)
    surname = models.CharField(CONST.SURNAME(), max_length=25)
    zipcode = models.IntegerField(CONST.ZIPCODE())
    city = models.CharField(CONST.CITY(),max_length=20)

... and any view etc where you use text will be using contants ...

Scenario 2 (without constants)

admin.py

class RegisterAdmin(admin.ModelAdmin):
    list_display = ("name","surname","zipcode")
    list_filter = ["zipcode","city"]
    search_fields = ["name","surname"]

models.py

class Register(models.Model):
    name = models.CharField("name", max_length=25)
    surname = models.CharField("surname", max_length=25)
    zipcode = models.IntegerField("zipcode")
    city = models.CharField("city",max_length=20)

I like the most the second scenario (I have been programming python from 2004), for me it looks more efficient, clear and easy to understand. The first scenario (proposed from Java/PHP programmers that now writes Python code) has the advantage that it helps the developer to detect that it made a mistake writing the "constant" so it is easier to detect errors and also it makes easier and quicker "massive changes" on this kind of texts without refactorizing the source code.

I would like to know which source code you would write or use and why.

Thank you,

¿Fue útil?

Solución 2

Scenario 1 doesn't make sense. You're using the constants to specify the verbose_name of the fields, and you're using them in the list_display option. The list_display option takes a list of fieldnames and NOT the verbose_name of the fields.

So you don't need constants at all for this. The field names are your "constants".

And IF you would need some "constants" in some case, you shouldn't use methods, just use properties, and just use normal class/attribute name conventions (so no uppercases):

class SomeConstants():
    name = "name"
    surname = "surname"
    zipcode = "zipcode"
    city = "city"
    created = "created"

The Java/PHP guys might say something like "Yeah but what if one of the constants needs to be generated? Then you need a method!". Well, sure, so you make it a property:

class SomeConstants():

    @property
    def full_name(self):
        return "{} {}".format(self.name, self.surname)

Because of the @property line above the method, it will execute and return the result of this method if you call SomeConstants().full_name.

Otros consejos

Scenario 1 is awful. Unfortunately I know all too well the problems of working with Java/PHP developers who are learning python.

Perhaps you can compromise with those guys by proposing the use of python enums to address their concern. These are built-in in python 3.4+, and have been backported as far back as 2.4.

from enum import Enum

class Constant(Enum):
    name = "name"
    surname = "surname"
    zipcode = "zipcode"
    city = "city"
    created = "created"

Now you can change the "values", say for example changing zipcode to be "potato" in the enum definition, whilst still using the name Constant.zipcode.value everywhere else in source code.

Use of constants is sometimes good, but not here.

One, the first argument of a field is its verbose name, if it's missing then the name of the field is used by default. So using the same constant for its verbose name as for the field name is exactly the scenario in which the verbose name is completely unnecessary.

Just do

name = CharField(max_length=25)

or

name = CharField("A beautiful description for a name field", max_length=25)

but putting "name" there is completely redundant and thus wrong. Don't repeat yourself.

Second, your constant is actually used for two different things that you don't want to change at the same time: you use the same constant for the attribute name in admin.py, but for verbose name in models.py. They aren't going to stay the same thing.

Third, using constants is only really helpful if the value might change one day, or if it's not immediately obvious what it may mean, for e.g. PI=3.14.

But NAME = "name" does not make anything more obvious, and if it ever changes to NAME = "description" it immediately becomes actively misleading. You'd probably want to change the name of the constant in that case as well, won't you? Why did you ever use a constant then?

And it means that changing something in const.py changes the database structure that Django expects. Some day a developer is going to trip over that; keep field names in models.py.

Finally, at every place where you use the models, you need the actual field anyway. A Register instance is simply a class instance, after all, and you'll probably want to use fields like register.name anywhere. You don't put the names of attributes of other classes in constants, do you?

Just use the string.

What about something more straight-forward like:

constants.py

NAME = "name"
SURNAME = "surname"

admin.py

import constants
class RegisterAdmin(admin.ModelAdmin):
    list_display = (constants.NAME, constants.SURNAME,constants.ZIPCODE)

This provides a unique place for the values in contrast to repeating them as in Scenario 2 and thus I would prefer it. It seems more clear than Scenario 1 to me. The "encapsulation" is performed by the module name, i.e. by using constants.xxx, so don't from constants import *.

The values here are obviously not constant, but neither are they in Scenario 1.

Everyone is in agreement that its a bad idea, but it could be that your Java friends are trying to implement the equivalent of a Java resource bundle, perhaps because they fondly remember how easy it is to work with .properties files.

This results in the use of keys in place of actual names and then later on the system will retrieve the correct resource from the bundle. This technique is used for translations and localization of applications.

A typical resource key looks like key.trx.hist.term.transfer.completed.success and at runtime the equivalent resource is rendered by the application.

If this is the case, in Python the approach is a bit different:

  1. You start with a base language. This is what you write your code in.
  2. All strings that need to be localized or translated are marked for translation, with the gettext library. For convenience this library provides a shortcut method _() which is used to mark strings for translation.
  3. These strings are then extracted to a message file; which is forwarded to translators. The message file contains the file names where the string is used. Its a plain text file, much like the .properties file.
  4. This message file is then compiled into an optimized format.
  5. Based on the language/locale of the client, the correct translated strings are displayed.

You can read more on how this is implemented in django at the translation documentation.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top