Editing property of foreignkey object - python

I am trying to access a ForeignKey object in Django, but only manage to show its values, not to edit them.
class ShippingAddress(models.Model):
name = models.CharField(max_length=63, primary_key=True)
street = models.CharField(max_length=63)
houseNumber = models.CharField(max_length=10)
zipCode = models.CharField(max_length=10)
city = models.CharField(max_length=63)
country = models.CharField(max_length=63)
class MainClass(models.Model):
name = models.CharField(max_length=63)
creationDate = models.DateTimeField(blank=True)
aShippingAddress = models.ForeignKey(ShippingAddress)
this would be an example. I would now like to make the values of the ShippingAddress model directly accesible and editable within the main class. Right now though I manage to only access the object itself, not every value of it directly.
(admin.py)
def editZipCode(self, obj):
return obj.aShippingAddress.zipCode
this way I manage to show each value at least, but that's it.
Any ideas are welcome.

You need to use an inline:
class MainClassInline(admin.TabularInline):
model = MainClass
class ShippingAddressAdmin(admin.ModelAdmin):
...
inlines = (MainClassInline,)

Related

Django, Python inheritance: Exclude some fields from superclass

I have inheritance between Employee and Manager classes. Employee - superclass, Manager - subclass.
class Employee(models.Model):
name = models.CharField(max_length=50, null=False)
address = models.CharField(max_length=50, null=False)
class Manager(Employee):
department = models.CharField(max_length=50)
"""
Here I don't want the 'name' and 'address' fields of Employee class.
(I want other fields of Employee and 'department' field of this
class to be stored in Manager table in database)
"""
How can achieve this. Thanks in advance.
You can make private variables in python class using 2 underscores (__), check this example for more.
However they will store that values in child object as there is no such thing as private or protected in Python.
But another approach can work for Django. In Django model fields are stored depending on their value (CharField, DateField and etc.) but if you will make item value None or any other static value (ex. "string"), that should solve your problem:
class Manager(Employee):
name = None
address = None
# other_stuffs.
In that example, Manager should not have name and address columns in database and when you will try to access them, you will get None. And if you want to get AttributeError (Django raises that when object hasn't requested key) then you can also add property:
class Manager(Employee):
name = None
#property
def name(self):
raise AttributeError("'Manager' object has no attribute 'name'")
I'd use 3 classes:
class BaseEmployee(models.Model):
# All your common fields
class Employee(BaseEmployee):
name = models.CharField(max_length=50, null=False)
address = models.CharField(max_length=50, null=False)
class Manager(BaseEmployee):
department = models.CharField(max_length=50)
I think that achieves what you wanted.
You need to use 3 classes "AbstractEmployee" with "abstract = True", "Employee" and "Manager" as shown below. "abstract = True" makes "AbstractEmployee" class an abstract class so a table is not created from "AbstractEmployee" class while each table is created from "Employee" and "Manager" classes and to remove the inherited fields "name" and "address" from "Manager" class, set "None" to them:
class AbstractEmployee(models.Model):
name = models.CharField(max_length=50, null=False)
address = models.CharField(max_length=50, null=False)
class Meta:
abstract = True # Here
class Employee(AbstractEmployee):
pass
class Manager(AbstractEmployee):
name = None # Here
address = None # Here
department = models.CharField(max_length=50)

How to add queryset to ManyToMany relationship?

I have following models:
class EnMovielist(models.Model):
content_ID = models.CharField(max_length=30)
release_date = models.CharField(max_length=30)
running_time = models.CharField(max_length=10)
actress = models.CharField(max_length=300)
series = models.CharField(max_length=30)
studio = models.CharField(max_length=30, null=True)
director = models.CharField(max_length=30)
def __str__(self):
return self.content_ID
class EnActress(models.Model):
name = models.CharField(max_length=100, null=True)
movielist = models.ManyToManyField(EnMovielist, related_name='movies')
def __str__(self):
return self.name
I got error when I try to this in Django shell,
b = EnActress.objects.values_list('name', flat=True)
a = EnMovielist.objects.filter(actress__contains=b).values_list('content_ID')
b.movielist.add(a)
AttributeError: 'QuerySet' object has no attribute 'movielist'
How can I django queryset add into many-to-many field?
I have no idea why this is happening.. Any help appreciated! :)
You should not be using values_list if you intend to add a new relation afterwards. From the docs:
values() and values_list() are both intended as optimizations for
a specific use case: retrieving a subset of data without the
overhead of creating a model instance
[Emphasis mine]
It's hard to tell what you're up to without having a good description of what you want to achieve.
You should call m2m add from instance and adding entity should be also model instance. Otherwise your expression doesn't make sense.
b = EnActress.objects.get(pk=some_pk) # get an instance, not queryset
a = EnMovielist.objects.get(pk=some_pk) # also instance
b.movielist.add(a)

Is it possible/sensible to customize Django's auto-through tables to include other fields...through-factory?

I know that django will helpfully generate a through table for simple many-to-many tables. However if you want to add information about the relationship, you need a 'linker' or through table. This example from the docs gives an example:
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=128)
def __str__(self): # __unicode__ on Python 2
return self.name
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(Person, through='Membership')
def __str__(self): # __unicode__ on Python 2
return self.name
class Membership(models.Model):
person = models.ForeignKey(Person)
group = models.ForeignKey(Group)
date_joined = models.DateField()
invite_reason = models.CharField(max_length=64)
I have in my design several tables/models like group, that vary mostly just by their choices attribute. And I'll be adding more later.
Is it possible to customize what sort of through table is generated by Django's magic? If so is this sensible?
The sort of thing I'm talking about is this:
class CharacterSkillLink(models.Model):
character = models.ForeignKey('NWODCharacter', related_name='%(class)s_by_skill')
skill = models.ForeignKey('Skill', choices = SKILL_CHOICES)
value = models.IntegerRangeField(min_value=1, max_value=5)
speciality = models.CharField(max_length=200)
class CharacterAttributeLink(models.Model):
character = models.ForeignKey('NWODCharacter', related_name='%(class)s_by_skill')
attribute = models.ForeignKey('Attribute', choices = ATTRIBUTE_CHOICES)
value = model.IntegerRangeField(min_value=1, max_value=5
class CharacterArcanaLink(models.Model):
character = models.ForeignKey('Mage', related_name='%(class)s_by_skill')
arcana = models.ForeignKey('Arcana', choices = ARCANA_CHOICES)
value = model.IntegerRangeField(min_value=1, max_value=5
In the future there'll be more like these. It's be handy if there was some way to django, much like with the through_field attribute, which defines keys on the through table to use, that there should be extra values to add to it (e.g. extra_field=value).
Is this possible/sensible?
IMO, adding fields to a "through" table is a great pattern for many possible uses. I'm not sure that Django needs new syntax to handle this case, but if you think you're creating lots of these tables and mixing/matching different tables, perhaps some abstract mixins will simplify things. For Example:
class CharacterLink(models.Model):
character = models.ForeignKey('NWODCharacter')
class Meta:
abstract = True
class SkillLink(models.Model):
skill = models.ForeignKey('Skill', choices = SKILL_CHOICES)
class Meta:
abstract = True
class AttributeLink(models.Model):
attribute = models.ForeignKey('Attribute', choices = ATTRIBUTE_CHOICES)
class Meta:
abstract = True
class CharacterSkillLink(CharacterLink, SkillLink):
value = models.IntegerRangeField(min_value=1, max_value=5)
speciality = models.CharField(max_length=200)
class CharacterAttributeLink(CharacterLink, AttributeLink):
value = model.IntegerRangeField(min_value=1, max_value=5)

django tables 2 - add custom column

I'm using django-tables-2 for a project. I have a table that uses a model for displaying data but I need to add one more column to display some informations from another table. Can I do that?
Have you tried the following?
# models.py
class Person(models.Model):
" This is your regular model "
first_name = models.CharField(max_length=200)
last_name = models.CharField(max_length=200)
user = models.ForeignKey("auth.User")
dob = models.DateField()
class PersonTable(tables.Table):
id = tables.Column(name="id") # just add a field here
class Meta:
model = Person
You map the column either by having the same name of the model's attribute, either using the accessor property.
I guess in your case it would be:
class UsersTable(tables.Table):
custom = Column(_("Custom"), accessor='id', orderable=False) # Any attr will do, dont mind it
def render_custom(self, record):
return services.get_some_info(record)
class Meta:
model = User
fields = (b'username', )

How to model a m2m relation where the related table can be a city, a region (state) or a country

In Django I have theses models:
class Artist(models.Model):
name = models.CharField(max_length=128)
born_place = models.ForeignKey(???)
dead_place = models.ForeignKey(???)
live_places = models.ManyToManyField(???)
work_places = models.ManyToManyField(???)
class Country(models.Model):
iso = models.CharField(max_length=2, primary_key=True)
name = models.CharField(max_length=50)
class Region(models.Model):
iso = models.CharField(max_length=2, blank=True)
name = models.CharField(max_length=150)
country = models.ForeignKey('Country')
class City(models.Model):
name = models.CharField(max_length=150)
region = models.ForeignKey('Region')
All the places (born_place, dead_place, live_places, work_places) can be a City or a Region or a Country. And a City should necessarily have a Region, and a Region should necessarily have a Country.
How can I achieve that?
You can also use model inheritance
class Territory(models.Model):
name = models.CharField(max_length=150)
class Country(Territory):
iso = models.CharField(max_length=2, primary_key=True)
class Region(Territory):
iso = models.CharField(max_length=2, blank=True)
country = models.ForeignKey('Country')
class City(Territory):
region = models.ForeignKey('Region')
class Artist(models.Model):
name = models.CharField(max_length=128)
born_place = models.ForeignKey(Territory)
dead_place = models.ForeignKey(Territory)
live_places = models.ManyToManyField(Territory)
work_places = models.ManyToManyField(Territory)
Best regards!
All the places (born_place, dead_place, live_places, work_places) can be a City or a Region or a Country.
What you need in this case is a generic foreign key. In Django this can be achieved through the handy contenttypes framework.
From the documentation:
There are three parts to setting up a GenericForeignKey:
Give your model a ForeignKey to ContentType.
Give your model a field that can store a primary-key value from the models you'll be relating to. (For most models, this means an IntegerField or PositiveIntegerField.) This field must be of the same type as the primary key of the models that will be involved in the generic relation. For example, if you use IntegerField, you won't be able to form a generic relation with a model that uses a CharField as a primary key.
Give your model a GenericForeignKey, and pass it the names of the two fields described above. If these fields are named "content_type" and "object_id", you can omit this -- those are the default field names GenericForeignKey will look for.
well.. yea maybe you could use generic relations. But i think that you could solve you some problems by thinking outside the box.
i'd say that you could create a Territory model instead of Country,Region and City; and then use a recursive relationship
class Territory(models.Model):
iso = models.CharField(max_length=2, blank=True)
name = models.CharField(max_length=150)
parent = models.ForeignKey('self')
this will create a hierarchy structure for your territory, so now you could use as many divisions as you like (for exemple, Continents, Planets,Community) and you wont have to change your models. As for the Artist, you could do something like:
class Artist(models.Model):
name = models.CharField(max_length=128)
born_place = models.ForeignKey(Territory)
dead_place = models.ForeignKey(Territory)
live_places = models.ManyToManyField(Territory)
work_places = models.ManyToManyField(Territory)
so now... the born_place can be a City, a Region, a Planet... anything you want! i guess that was your question. I'm no expert in django, this is just a generic way to solve this kind of problems in O.O.P.
Take a look at Django's Generic Relations here and here, which will let you key to various types of object, rather than only a specific one.

Categories

Resources