I have a model that requires quite a few BooleanFields, they could be considered preferences in some way. What I'm currently doing is adding all the fields to the model itself and hardcoding the labels to the HTML. So my model looks somewhat like this:
class Project(models.Model):
...some fields...
Check1=models.BooleanField()
....many of these...
Check19=models.BooleanField()
I feel this is a very dumb way of doing it and am looking for a more Pythonic solution. Maybe ManyToMany fields? Any ideas?
I would rather give the boolean fields some meaningful names and would put verbose_name to the field description, e.g.
class Project(models.Model):
# ...
featured = models.BooleanField(_("Featured"))
published = models.BooleanField(_("Published"))
# ...
If they are all of the same type, it would probably make sense to make it a M2M, e.g. phone1, phone2, phone3, etc. would be more appropriate as phones pointing to a Phone model.
However, since these are booleans, I doubt that's the case. Having a lot of fields on a model is not a problem, if they all make sense there. It would be wrong, in fact, to abstract them away, when they have no relation to each other.
Take a look at the zen of python:
Especially:
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Related
I have a django model that looks something like this:
class MyModel(models.Model):
a = models.BooleanField(default=False)
b = models.CharField(max_length=33, blank=False)
c = models.CharField(max_length=40, blank=True)
and a corresponding form
class MyForm(ModelForm):
class Meta:
model = MyModel
Asking the user to fill in the form is a two phase process. First I ask whether a is True or False. After a submit (would be better maybe with ajax, but keep it simple at first) I can fill in a dropdown list with choices for b and decide whether or not to show c as an option. No need to show a as a choice any more, it's descriptive text.
So I want to present a form twice, and the same model is behind it, slowly being filled in. First choose a, then be reminded that a is True and be asked about b and c. Or that a is False and be asked about only b. After submitting this second form, I save the object.
I'm not clear how best to do this in django. One way is to make two separate form classes, one of which has hidden fields. But if the same model is behind both and the model has required fields, I'm anticipating this will get me in trouble, since the first form won't have satisified the requirement that b be non-empty. In addition, there's a small amount of fragility introduced, since updating the model requires updating two forms (and a probably at least one view).
Alternatively, I could use non-model forms and have full freedom, but I'd love to believe that django has foreseen this need and I can do it easier.
Any suggestions on what the right idiom is?
You can use Form Wizard from form-tools for that: https://django-formtools.readthedocs.io/en/latest/wizard.html
It works rather simple by defining multiple forms and combining them. Then in the end, you can use the data to your liking with a custom done() form. The docs tell you everything. You can use JS to hide some of your fields for the super quick approach (utilize localStorage for example).
I need to make a model that has 15 similar fields (let's call them field_01, field_02, field_03, etc.). I also need these fields to be easily available (e.g. to be able to do things like obj.field_01). Because I wanted to get something off the ground really quickly, I just created them the stupid way:
class M (models.Model):
....
field_01 = models.NullBooleanField()
field_02 = models.NullBooleanField()
....
I searched online for a better way to do this. Some people say use setattr, but as far as I could tell from reading and trying some stuff out, this adds attributes to an instance of a class, not the class itself, which means that when I try to attach a model form to this model, it will not see the fields added with setattr. Then I tried overriding the __new__ function, which would allow me to add properties to a class before an instance of that class is created. But I wasn't able to figure out how to do this exactly.
So, what's a way to generate these fields without breaking South and model forms and without copy-paste?
It's hard to say definitively without a concrete example of what your doing, but generally, if you find yourself repeating a field, then it's a clear sign for a one-to-many or many-to-many relationship, instead:
One-to-Many
class Field(models.Model):
m = models.ForeignKey(M, related_name='fields')
field = models.NullBooleanField()
Many-to-Many
class Field(models.Model):
field = models.NullBooleanField()
class M(models.Model):
fields = models.ManyToManyField(Field)
Django models have an add_to_class method you could (ab)use for monkey-patching models the way you would like to do.
for i in range(1, 10):
M.add_to_class('field_%s' % s, NullBooleanField())
It sounds like you are looking to have an EAV style database. You should try a library instead of rolling your own. To that end, Django EAV looks pretty awesome. https://github.com/mvpdev/django-eav
To read more about pros and cons of a bunch of libraries to accomplish this check out: https://stackoverflow.com/a/7934577/884453
I'm curious if there's a best practice, or recommended way to accomplish this?
Say I have a model like this:
class Cat(models.Model):
field1=models.CharField(...)
field2=models.CharField(...)
evil=models.BooleanField(...)
What I'm trying to accomplish is I want no views to ever be able to access Cat records where evil is True.
Do I really need to add .filter(evil=False) to every Cat.objects.filter call, or is there some way to do it once in the class and make the evil cats never show up anywhere?
Ok, a custom manager could fit in here. Just have a look into the docs. And like Chris Pratt said, keep in mind that the first manager becomes the default one.
Hope this leads into the right direction.
Update (maybe you could do it like this):
from django.db import models
class EvilCategoryManager(models.Manager):
def get_query_set(self):
return super(EvilCategoryManager, self).get_query_set().filter(evil=False)
class Cat(models.Model):
#.... atrributes here
objects = models.Manager()
no_evil_cats = EvilCategoryManager()
I have a reasonably complex custom Django model method. It's visible in the admin interface, and I would now like to make it sortable in the admin interface too.
I've added admin_order_field as recommended in this previous question, but I don't fully understand what else I need to do.
class Book(models.Model):
id = models.IntegerField(primary_key=True)
title = models.CharField(max_length=200)
library_id = models.CharField(max_length=200, unique=True)
def current_owner(self):
latest_transaction = Transaction.objects.filter(book=self)[:1]
if latest_transaction:
if latest_transaction[0].transaction_type==0:
return latest_transaction[0].user.windows_id
return None
current_owner.admin_order_field = 'current_owner'
Currently, when I click on the current_owner field in the admin interface, Django gives me
FieldError at /admin/books/book/
Cannot resolve keyword 'current_owner' into field
Do I need to make a BookManager too? If so, what code should I use? This isn't a simple Count like the example in the previous question, so help would be appreciated :)
Thanks!
The Django admin won't order models by the result of a method or any other property that isn't a model field (i.e. a database column). The ordering must be done in the database query, to keep things simple and efficient.
The purpose of admin_order_field is to equate the ordering of a non-field property to the ordering of something that is a field.
For example, a valid values current_owner.admin_order_field could be id, title or library_id. Obviously none of these makes sense for your purpose.
One solution would be to denormalise and always store current_owner as a model field on Book; this could be done automatically using a signal.
You can't do this. admin_order_field has to be a field, not a method - it's meant for when you have a method that returns a custom representation of an underlying field, not when you do dynamic calculations to provide the value. Django's admin uses the ORM for sorting, and that can't sort on custom methods.
What is the preferred naming convention for Django model classes?
Django models are just Python classes, so the Python naming conventions detailed in PEP-8 apply.
For example:
Person
Category
ZipCode
If Django fails to pluralize the class name properly when creating the corresponding table, you can easily override the pluralization by setting a custom verbose_name_plural field in an inner META class. For example:
class Story(models.Model):
...
class Meta:
verbose_name_plural = "stories"
As far as I know, the idea is that the class name should be singular and should use SentenceCase with no spaces. So you'd have names like:
Person
TelephoneNumber
Then the Django admin tool knows how to pluralise them. Doesn't work so nicely for names like:
Category
which gets pluralised as Categorys, but there we go...
Apart from that, just give it a name that means something to you and succinctly sums up what the class is meant to represent.
Ben
In most of programming languages, people prefer give a singular names to the objects/models because these models are also represented by tables in your database system. The minimalism is a good choice everytime to avoid some meaning conflicts in the future.
To exemplify;
https://stackoverflow.com/a/5841297/2643226
In adition, when you need related objects for a Model of more than one word, you can use the _set attribute. Example:
class ProcessRoom(models.Model):
...
plant = models.ForeignKey("Plant", verbose_name='planta', on_delete=models.CASCADE)
Then, related objects will be:
plant = Plant.object.get(id=1)
process_rooms = plant.processroom_set.all