Understanding definition of Django's model class - python

If we create a new model as follows,
from django.db import models
class Book(models.Model):
title = models.CharField(max_length=200)
author = models.CharField(max_length=200)
and run the database migrations, then I understand that
the corresponding table is created with column names and field types, and I understand that we can do the following:
>>> from myapp.models import Book
>>> book = Book(title="Matilda", author="Roald Dahl")
>>> book.save()
>>> print book.title
Matilda
However I am struggling a little to understand the python code
in the class definition, just in terms of how I understood classes to work, and was hoping someone could help
my understanding with the following questions:
In the definition of the class Book, title seems to be a
class attribute. This class attribute is set to an instance of
the CharField class? In which case when we create an instance of
the Book class, if we do not pass in an argument, would title
be set to this same instance of CharField?
When we pass in title='Matilda' on creating this instance of Book, is this then overriding the attribute title?
How do we know that Book takes in title as an argument?
I hope these make sense. Thank you for any help.
Lizzie

When you make a model class in Django, consider that class the data-table, each individual instance of that class the table rows, and the attributes(e.g: title) of each table the columns.
In the definition of the class Book, title seems to be a class attribute. This class attribute is set to an instance of the CharField class? In which case when we create an instance of the Book class, if we do not pass in an argument, would title be set to this same instance of CharField?
‘title’ would be a field in the data table and the ‘CharField’ would be a type of field; each field is assigned a type by you using classes like ‘CharField’, ‘TexrField’, etc. You don’t necessarily have to pass in a value for ‘title’ (or any field) if you give a default value when describing the type, example:
title = models.CharField(max_length=50, default=‘unknown’)
When we pass in title='Matilda' on creating this instance of Book, is this then overriding the attribute title?
You are giving it a value of ‘Matilda’ as it doesn’t have a title until you give it one (or provide a default when making the field).
How do we know that Book takes in title as an argument?
Because you wrote it in the model class; it really depends on how you’re going to input the data really. If you’re making some kind of page that takes input from a user, display the ‘title’ field in a form and make it mandatory. You can make fields optional when you assign the type of field, like
title = models.CharField(max_length=200, null=true, blank=true)

Related

How to display a list of children objects on detail view for Django Admin?

I have two models: Setting and SettingsGroup.
When someone clicks on a specific SettingsGroup in the Django Admin and the edit/detail page appears I'd like for the child Setting objects to be displayed but as a list not a form.
I know that Django has InlineModelAdmin but this displays the children as editable forms.
My concern isn't with the child objects being editable from the parent object but rather the amount of space it consumes. I'd rather have a list with either a link to the appropriate child record or that changes a particular object to be inline editable.
Here is my Setting model:
class Setting(models.Model):
key = models.CharField(max_length=255, blank=False)
value = models.TextField(blank=True)
group = models.ForeignKey('SettingsGroup', blank=True,
on_delete=models.SET_NULL, null=True)
def __str__(self):
return str(self.key)
And the SettingsGroup model:
class SettingsGroup(models.Model):
name = models.CharField(max_length=255)
description = models.TextField(blank=True)
def __str__(self):
return str(self.name)
The method I don't want to use (or need to find a different way to use) is InlineModelAdmin which appears in my admin.py currently as:
class SettingsGroupInline(admin.StackedInlin):
model = Setting
fk_name = 'group'
#admin.register(SettingsGroup)
class SettingsGroupAdmin(admin.ModelAdmin):
inlines = [ SettingGroupsInline, ]
Here is an example of how I'd like it to work:
There is a MySettings object, an instance of the SettingsGroup model.
There is a CoolSetting object and a BoringSetting object, each an instance of the Setting model.
The CoolSetting object has its group set to the MySettings object.
The BoringSetting object does not have a group set.
When I open the detail/edit view of the Django Admin for the MySettings object I see the normal edit form for the MySettings object and below it the CoolSetting object (but not as a form).
I do not see the BoringSetting object because it is not a child/member/related of/to MySettings.
I have some ideas on how this could be accomplished but this seems like fairly basic functionality and I don't want to go building something if Django (or other existing code) provides a way to accomplish this.
Any ideas?
Why can't you just access the children using something like Setting.objects.filter(group=SettingsGroup.objects.get(name={name}))
If being presented in a template you could pass the SettingsGroup name to the context and iterate over the children and present them however you like.
I may not understand your question exactly so if this is not what you're looking for let me know!

Using abstract class in template for generic class based DetailView in Django

I just started working with generic class based views and love it. I do have one struggle that I still can't solve.
I have one abstract class called group, and two childs Company and Bond. (I simplified my example). This is my models.py:
models.py
class Group(BaseModel):
name = models.CharField(max_length=30, unique=True)
class Meta:
abstract = True
class Company(Group):
def __str__(self):
return "Company " + self.name
class Bond(Group):
def __str__(self):
return "Bond " + self.name
Now when displaying one of my objects with the generic class based detail view, I want to have one group_detail.html template, and call group.name. This doesn't work however, I need to call company.name or bond.name, depending on the object type. Since my original model has a lot more attributes, this is undesirable because it results in a lot of duplicate code. Do you guys know a workaround for this?
Group has no instances in the database as it's an abstract class so you can't query it. You have to query Company or Bond and so pass Company or Bond objects to a template.
If your Company and Bond models have the same attributes you can pass their object to a template with a single context name, this will let you use one template. But, actually, I think your Company and Bond models are different so you can't create one template for both of them, they will differ, so there is no code duplication at all.
Just use the same template for both views, and use the automatically passed object variable to the context, like {{ object.name }}.

How to replace choices list for TypedChoiceField in Django form?

I have a class which includes a field with a choice list:
class Game(models.Model):
track = models.CharField(max_length=5,
choices=AllTracks.TRACK_CHOICES)
I want to use a form based on this model, but I want to pass it a subset of the choice list, PublicTracks.TRACK_CHOICES.
I've looked at the structure of the form. In the base_fields dictionary, track is a TypedChoiceField object. That object has an attribute choices, which is list(AllTracks.TRACK_CHOICES). I've tried replacing it with list(AllTracks.TRACK_CHOICES) but it doesn't seem to take.
Any suggestions on how I might override the list from the model definition would be appreciated.
You can define a completely custom field on your form class, overriding the one that would be auto-generated from your model otherwise, as described in Overriding the default fields:
class GameForm(forms.ModelForm):
track = forms.ChoiceField(choices=WHATEVER, ...)
class Meta(object):
model = Game

Can't use an inheriting Django model's Meta class to configure a field defined in an inherited abstract model

I would like to use properties from an inheriting model's Meta class to configure a field defined in an abstract model higher up the inheritance tree:
class NamedModel(models.Model):
class Meta:
abstract = True
verbose_name = 'object'
name = models.CharField("Name",
max_length=200,
db_index=True,
help_text="A meaningful name for this %s." % Meta.verbose_name)
# see what I'm trying to do here?
)
...
class OwnedModel(NamedModel):
class Meta(NamedModel.Meta):
verbose_name = 'owned object'
I would like the help text on the name field of OwnedModel forms to say 'A meaningful name for this owned object'. But it does not: the word 'owned' is missing, which would suggest that the verbose_name from the NamedModel.Meta is used when the model is set up, not OwnedModel.Meta.
This isn't quite what I expect from an inheritance point of view: is there some way to get the field to be created whereby Meta.verbose_name refers to the value on the non-abstract model class, not the abstract one on which the field was defined?
Or am I being daft?
(This may seem like a trivial example, and it is: but it's just to illustrate the point of something more important and complex I am trying to do)
Many thanks in advance.
Why don't you try to make a class.
class BaseNamedModelMeta:
abstract = True
verbose_name = "your text"
And then inherit and override whatever you want like this:
class OwnedModel(NamedModel):
class Meta(BaseNamedModelMeta):
verbose_name = 'owned object'
I think this happens because Meta.verbose_name is used and NamedModel.name is created when class NamedModel is parsed. So later, when class OwnedModel gets parsed, there is no chance to change anything.
Maybe you can set the help_text property on OwnedModel.name later on, but this may change NamedModel.name also.
In similar situations I have put the variable parts in class attribute of the model (not Meta) and then used the by run time methods/properties to generate the texts I need.
In fact I ended up doing the following. The base model gets given a dynamic_field_definition() class method, which can be used to patch up the fields, with the cls argument being the correct (inheriting) class. That means that that cls' Meta attributes are of that correct child, not the original base.
I then wire up that method to get called on the class_prepared signal, so that you know everything's otherwise ready.
class NamedModel(models.Model):
...
#classmethod
def dynamic_field_definition(cls):
pass
def dynamic_field_definition(sender, **kwargs):
if issubclass(sender, NamedModel):
sender.dynamic_field_definition()
class_prepared.connect(dynamic_field_definition)
Then the field properties that vary with model class are simply reconfigured by that class method (or more likely the method as overridden in derived classes).
It's a slightly hacky way to bring a last little bit of OO-ness to Django models, but it works fine for my purpose.

How do Django model fields work?

First of all,I'm not into web programming. I bumped into django and read a bit about models. I was intrigued by the following code ( from djangoproject.com ) :
class Person(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
def __str__(self):
# Note use of django.utils.encoding.smart_str() here because
# first_name and last_name will be unicode strings.
return smart_str('%s %s' % (self.first_name, self.last_name))
By my understanding of python , first_name and last_name are class variables , right ? How is that used in code ( because I guess that setting Person.first_name or Person.last_name will affect all Person instances ) ? Why is it used that way ?
The essence of your question is "how come these class variables (which I assign Field objects to) suddenly become instance variables (which I assign data to) in Django's ORM"? The answer to that is the magic of Python metaclasses.
A metaclass allows you to hook into and modify the process of creating a Python class (not the creation of an instance of that class, the creation of the class itself).
Django's Model object (and thus also your models, which are subclasses) has a ModelBase metaclass. It looks through all the class attributes of your model, and any that are instances of a Field subclass it moves into a fields list. That list is assigned as an attribute of the _meta object, which is a class attribute of the model. Thus you can always get to the actual Field objects via MyModel._meta.fields, or MyModel._meta.get_field('field_name').
The Model.__init__ method is then able to use the _meta.fields list to determine what instance attributes should be initialized when a model instance is created.
Don't be afraid to dive into the Django source code; it's a great source of education!
Yes, first_name and last_name are class variables. They define fields that will be created in a database table. There is a Person table that has first_name and last_name columns, so it makes sense for them to be at Class level at this point.
For more on models, see:
http://docs.djangoproject.com/en/dev/topics/db/models/
When it comes to accessing instances of a Person in code, you are typically doing this via Django's ORM, and at this point they essentially behave as instance variables.
For more on model instances, see:
http://docs.djangoproject.com/en/dev/ref/models/instances/?from=olddocs
Not a real answer, but for enrichment:
Person.first_name
won't work
p = Person.objects.get(pk=x)
p.first_name
will work. so an object instance of person has a first and last name, but static context Person does not.
Also note: Django has Model Managers which are allow "Person" to do static queryset operations. (https://docs.djangoproject.com/en/dev/topics/db/managers/#managers).
so for example
peoples = Person.objects.all()

Categories

Resources