I have 2 abstract models:
class AdditionalModel(models.Model):
x = models.CharField(max_length=20)
class Meta:
abstract = True
class BaseModel(models.Model):
y = models.CharField(max_length=20)
class Meta:
abstract = True
Now I have my models.py:
class MainModel(BaseModel):
z = models.CharField(max_length=20)
On migration, I need to create two tables, one for MainModel which extends the BaseModel and another for "mainmodel_additional_model" which gets additionally created for MainModel.
I was trying to achieve this using save() method. Not quite getting there, also what are the standard ways to do this.
Related
I have 2 models that look like this:
models.py
class Client(models.Model):
deal = models.ManyToManyField('Deal', related_name="clients")
class Deal(models.Model):
client = models.ManyToManyField(Client, related_name="deals")
Then in the admin, I have inlined the related models to make it easy to make changes regardless of the object type you have open.
admin.py
class ClientInline(admin.TabularInline):
model = Deal.client.through
class DealAdmin(admin.ModelAdmin):
inlines = [ClientInline]
class DealInline(admin.TabularInline):
model = Client.deal.through
class ClientAdmin(admin.ModelAdmin):
inlines = [DealInline]
However, if you add a Client to a Deal and then open the Client detail page, the corresponding deal does not appear. Is there something I'm not connecting?
It is enough to have relation define only in one model. Otherwise you'll have 2 separate tables for separate ManyToMany relation: ClientDeal and DealClient.
What you need to do is to choose which one you need to leave. And probably update Admin inlines according to Django Admin documentation
class Client(models.Model):
deals = models.ManyToManyField('Deal', related_name="clients")
class Deal(models.Model):
pass
Yes, If you're using models.manytoMany() , you have to put it only in one model. no the two
But there's a very good attribute you should use: through
with through attribute you can create a intermediate model. here there's an example:
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=200)
groups = models.ManyToManyField('Group', through='GroupMember', related_name='people')
class Meta:
ordering = ['name']
def __unicode__(self):
return self.name
class Group(models.Model):
name = models.CharField(max_length=200)
class Meta:
ordering = ['name']
def __unicode__(self):
return self.name
class GroupMember(models.Model):
person = models.ForeignKey(Person, related_name='membership')
group = models.ForeignKey(Group, related_name='membership')
type = models.CharField(max_length=100)
def __unicode__(self):
return "%s is in group %s (as %s)" % (self.person, self.group, self.type))
later, you can use your inline admin class!
I just tested this an you were actually really close.
First, #wowkin2 said, you don't want to define a ManyToManyField in both models so I would probably just define it in your Deal model.
Second, replace this:
class DealInline(admin.TabularInline):
model = Client.deal.through
with this:
class DealInline(admin.TabularInline):
model = Deal.client.through
And everything should work.
So, this is what your files should now look like:
models.py
class Deal(models.Model):
client = models.ManyToManyField(Client, related_name="deals")
admin.py
class ClientInline(admin.TabularInline):
model = Deal.client.through
class DealAdmin(admin.ModelAdmin):
inlines = [ClientInline]
class DealInline(admin.TabularInline):
model = Deal.client.through
class ClientAdmin(admin.ModelAdmin):
inlines = [DealInline]
I am running into an issue with prefetch_related on a property of an inherited model.
In models.py I have:
class Security(models.Model):
name = models.TextField()
...other fields
class Fund(Security):
...other fields
#property
def underlying_security(self):
return self.maps_when_mapped.get().original_security
class SecurityToSecurityMap(models.Model):
original_security = models.ForeignKey(Security, related_name="maps_when_original")
mapped_security = models.ForeignKey(Security, related_name="maps_when_mapped")
and in serializers.py
class UnderlyingSecuritySerializer(serializers.Serializer):
id = serializers.IntegerField()
name = serializers.CharField()
class FundSerializer(serializers.ModelSerializer):
underlying_security = UnderlyingSecuritySerializer(read_only=True, allow_null=True)
class Meta:
model = Fund
fields = ("id", "name", "underlying_security")
Now, I when I am querying fund objects:
queryset = Fund.objects.prefetch_related("maps_when_mapped__original_security")
Django ignores prefetching. Experimented with `Prefetch, tried moving property to the parent - no luck, still getting hundreds on queries. Any way this can be optimised?
I am using Django 2.2 with Postgres 11
UPDATE 1
After looking at the question, I suspect that problem is when I use .get() in property, it is immediately evaluated but then not sure how to fetch it without evaluation
I am using django 1.10 with mysql.
I am willing to have two tables in my db with the same fields.
class Ticket(models.Model):
listing = models.ForeignKey(Listing)
ticketId = models.CharField(max_length=32)
dateOfPosting = models.DateTimeField()
seatNumber = models.PositiveIntegerField(null=True, blank=True)
class SoldTicket(models.Model):
### same fields here
What is the best way to do it?
Having two identical tables in your database suggests that you don't need them, a boolean field or some foreign key would most likely do the job.
Hovewer, if you really want to have two identical models, you should look at abstract models.
class AbstractBase(models.Model):
listing = models.ForeignKey(Listing)
ticketId = models.CharField(max_length=32)
...
class Meta:
abstract = True
class Model1(AbstractBase):
pass
class Model1(AbstractBase):
pass
That way Model1 and Model2 will have same fields.
models.py:
class Station(models.Model):
station = models.CharField()
class Flat(models.Model):
station = models.ForeignKey(Station, related_name="metro")
# another fields
Then in serializers.py:
class StationSerializer(serializers.ModelSerializer):
station = serializers.RelatedField(read_only=True)
class Meta:
model = Station
class FlatSerializer(serializers.ModelSerializer):
station_name = serializers.RelatedField(source='station', read_only=True)
class Meta:
model = Flat
fields = ('station_name',)
And I have an error:
NotImplementedError: RelatedField.to_representation() must be implemented.
If you are upgrading from REST framework version 2 you might want ReadOnlyField.
I read this, but it does not help me.
How to fix that?
Thanks!
RelatedField is the base class for all fields which work on relations. Usually you should not use it unless you are subclassing it for a custom field.
In your case, you don't even need a related field at all. You are only looking for a read-only single foreign key representation, so you can just use a CharField.
class StationSerializer(serializers.ModelSerializer):
station = serializers.CharField(read_only=True)
class Meta:
model = Station
class FlatSerializer(serializers.ModelSerializer):
station_name = serializers.CharField(source='station.name', read_only=True)
class Meta:
model = Flat
fields = ('station_name', )
You also appear to want the name of the Station object in your FlatSerializer. You should have the source point to the exact field, so I updated it to station.name for you.
I want to define two model fields: created_by, modified_by in a parent model, they will be acting as common fields for the child models.
class ExtendedModel(models.Model):
created_by = models.ForeignKey(User,related_name='r_created_by')
modified_by = models.ForeignKey(User,related_name='r_modified_by')
class Meta:
abstract = True
class ChildModel1(ExtendedModel):
pass
class ChildModel2(ExtendedModel):
pass
this gives errors as ChildModel1 and ChildModel2 has related_name clashed with each other on their created_by and modified_by fields.
The Django docs explain how to work around this: http://docs.djangoproject.com/en/dev/topics/db/models/#abstract-related-name
class ExtendedModel(models.Model):
created_by = models.ForeignKey(User,related_name='"%(app_label)s_%(class)s_created_by')
modified_by = models.ForeignKey(User,related_name='"%(app_label)s_%(class)s_modified_by')
class Meta:
abstract = True
class ChildModel1(ExtendedModel):
pass
class ChildModel2(ExtendedModel):
pass