Django: Single model for multiple tables - django-models

I have a main table
Slideshow
then a site specific table that captures a few extra details for that site.
Site1_Slideshow
In a web app (specific to a site) i want a single model i.e. Slideshow that combines the 2 tables above.
Currently i have the code below, but i dont think this is correct. I cant do things like
s = Slideshow.objects.get(slideshowId=1) as Slideshows only has the properties featurecategory and slideshow. So how can i have an model called Slideshow that is composed of these 2 tables but looks like it was a single db table.
class SlideshowAbstract(models.Model):
slideshowid = models.IntegerField(primary_key=True, db_column=u'SlideshowId') # Field name made lowercase.
headline = models.TextField(db_column=u'Headline') # Field name made lowercase.
class Meta:
db_table = u'Slideshow'
class Slideshow(models.Model):
slideshow = models.OneToOneField(SlideshowAbstract, primary_key=True,db_column=u'SlideshowId')
def __unicode__(self):
return self.slideshow.headline
class Meta:
db_table = u'Site1_Slideshow'

Think i found the solution.
On the Site1_Slideshow you need to add a column for django to use, that i presume is always the same as primary key value.
Its name is SlideshowAbstract_ptr_id
Once that is added you can change the Slideshow model to be
class Slideshow(SlideshowAbstract):
featureCategory = models.ForeignKey(Featurecategory,db_column=u'FeatureCategoryId')
def __unicode__(self):
return self.headline
class Meta:
db_table = u'Site1_Slideshow'
So doable but not the nicest if you are not doing "model first" and already have the schema. Would be good to be able to override the name of the _ptr_id column.
I did try adding the following to Slideshow too see if i could map this ptr col to the primary key
slideshowabstract_ptr_id = models.IntegerField(primary_key=True, db_column=u'SlideshowId')
but no cigar.
I havent tested inserts either but ...objects.all() works

Related

Django Rest returning related items for each item

I was trying to find answer in similiar questions, but none was meeting my expectations.
I have 2 models:
class Artist(models.Model):
name = models.CharField(max_length=255)
music_type = models.CharField(max_lenght=50)
def __str__(self):
return self.name
class Event(models.Model):
event_name = models.CharField(max_length=255)
...
artists = models.ManyToManyField(Artist)
def __str__(self):
return self.event_name
I also have serializers.py file:
class EventSerializer(serializers.ModelSerializer):
class Meta:
model = Event
fields = '__all__'
class ArtistSerializer(serializers.ModelSerializer):
events = EventSerializer(source='event_set', many=True)
class Meta:
model = Artist
fields ='__all__'
The event in ArtistSerializer allows me to return all events where artist takes part.
Now for each artist I would like to get list of all artists if they ever were taking part in the same event.
For example I have 5 Artists (A1...A5) and 3 Events (E1...E3)
In Event 1: [A1,A3]
In Event 2: [A3,A4,A5,A2]
In Event 3: [A2, A3]
So for A3 I would like to get list [A1,A4,A5,A2]
For A1: [A3]
For A2: [A3,A4,A5]
Unfortunately I have huge problem to create this query as SQL-query and ORM mechanism looks more complicated in this situation. Can somebody help me with this problem or give hints how to solve this?
If it's needed I'm gonna share more code
You can query the through model to get the artists related to an event. This is the intermediate model which django will have created to make that M2M relationship.
Where you have a ManyToManyField it has an attribute of through which is the M2M model.
So from your event model you could do something like Event.artists.through.objects.all() and you'd see all the instances in your M2M model.
So to find out the artists which are linked to a given event you could query that same table;
Event.artists.through.objects.filter(event_id=1).select_related('artist')
This would then return all the objects in the M2M which belong to Event 1. You could then get the artists from there, or just grab the artist IDs Event.artists.through.objects.filter(event_id=1).values_list('artist_id, flat=True)
Given the scenario in your comment...
If you have an artist, then you can run a query to get the events they've been in, and then run another query with those event ids. In that second query you are then looking to get the artist ids that aren't the current artist you're already looking at.
# First get the events that the current artist has been in
event_ids = Event.artists.through.objects.filter(artist_id=1).values_list('event_id, flat=True)
# Then get the other artists who have been in the same events
other_artist_ids = Event.artists.through.objects.filter(event_id__in =event_ids).exclude(artist_id=1).values_list('artist_id, flat=True)
# or the full instances
other_artists = Event.artists.through.objects.filter(event_id__in =event_ids).exclude(artist_id=1).select_related('artist')

How to use hyperlinks to represent relationships instead of primary keys in Django REST framework

I want to get my object index as a "resource_uri" instead id
I take the usual way I make a model , views , serializers :
class User(BaseModel):
user = models.ForeignKey(settings.AUTH_USER_MODEL)
models.CharField()
class UserSerailizers(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id','user','formatted_address')
classclass UserList(generics.ListCreateAPIView):
queryset = Image.objects.all()
serializer_class = UserSerializer
when i call < my_domain/user/ > I get this response
{
id:1,
name:'toto'
}
but I want to have an answer to this form:
{
'url': my_domain/user/1/
'name': 'toto'
}
Any thoughts?
If you want a hyperlink instead of a primary key in your model representations, you have to use either HyperlinkedModelSerializer or more generic Serializer along with HyperlinkedIdentityField and/or HyperlinkedRelatedField. The former is probably what you are looking for.
The HyperlinkedModelSerializer class is similar to the ModelSerializer class except that it uses hyperlinks to represent relationships, rather than primary keys.
See Django REST framework documentation for more details.
As already commented, you need to use the HyperlinkedModelSerializer as you've shown.
The lookup_field attribute should be inside the Meta class.
And the latest and this is a guess: You just have a ListView for your User model. In order to show the detail for the user, you need also the retrieve method. I would recommend you using the ModelViewset so it automatically implements all methods.

Django, autogenerate one-to-many tables, and database structure

I am using django for a website where I have a database with users, people, locations, items and so on. Know i find that I need some extra information that requires one-to-many relations like Aliases for most of these tables.
Should I (1) create a common alias table for all of these by using the content type framework (will probably end up with billions of rows), or should I (2) create a alias table for each of these. If the latter one, how do I auto-create one-to-many table like this by just adding a single line like this
"alias = Ailias()"
in each model. I`m sure I saw an app doing something like that way a while ago, I think is was a reversion app of some kind. Even if the second method is not suited i would love tho understand how to do it. I do not know what to search after to find an explanation of this.
I plan to add Haystack with Solr to this, so method 2 might add much extra work there. But I do not have much experience with it jet, so I might be wrong.
PS: ended up wih method one.
Manage to do what I wanted in method 2, easily generate one-to-many fields. Not sure if this is the easiest way, or the best way. If someone has a better way of doing it, I would love to learn it. I am a long way from a django expert, so I might have meddled with some unnecessary complex stuff to do what I wanted.
This example creates an easy way of adding a one-to-many alias relationship.
Alias Managers
class AliasManagerDescriptor(object):
def __init__(self, model,fkName):
self.model = model
self.fkName = fkName
def __get__(self, instance, owner):
if instance is None:
return AliasManager(self.model,self.fkName)
return AliasManager(self.model, self.fkName, instance)
class AliasManager(models.Manager):
def __init__(self, model,fkName, instance=None):
super(AliasManager, self).__init__()
self.model = model
self.instance = instance
#Name of FK linking this model to linked model
self.fkName=fkName
def get_query_set(self):
"""
Get query set, or only get instances from this model that is linked
to the chosen instance from the linked model if one is chosen
"""
if self.instance is None:
return super(AliasManager, self).get_query_set()
if isinstance(self.instance._meta.pk, models.OneToOneField):
#TODO: Checkif this part works, not checked
filter = {self.instance._meta.pk.name+"_id":self.instance.pk}
else:
filter = {self.fkName: self.instance.pk}
return super(AliasManager, self).get_query_set().filter(**filter)
def create(self,**kwargs):
"""
Create alias instances. If FK is not given then it is automatically set
to the chosen instance from the linked model
"""
if self.fkName not in kwargs:
kwargs[self.fkName]=self.instance
print kwargs
super(AliasManager, self).create(**kwargs)
Alias Models
class Alias(object):
def contribute_to_class(self, cls, name):
self.manager_name = name
aliasModel = self.create_alias_model(cls)
descriptor = AliasManagerDescriptor(aliasModel,cls._meta.object_name.lower())
setattr(cls, self.manager_name, descriptor)
def create_alias_model(self, model):
"""
Creates a alias model to associate with the model provided.
"""
attrs = {
#'id': models.AutoField(primary_key=True),
"name": models.CharField(max_length=255),
#Not sure which to use of the two next methods
model._meta.object_name.lower(): models.ForeignKey(model),
#model._meta.object_name.lower(): AliasObjectDescriptor(model),
'__unicode__': lambda self: u'%s' % self.name,
'__module__': model.__module__
}
attrs.update(Meta=type('Meta', (), self.get_meta_options(model)))
name = '%s_alias' % model._meta.object_name
return type(name, (models.Model,), attrs)
def get_meta_options(self, model):
"""
Returns a dictionary of fields that will be added to
the Meta inner class.
"""
return {
}
"""class AliasObjectDescriptor(object):
def __init__(self, model):
self.model = model
def __get__(self, instance, owner):
values = (getattr(instance, f.attname) for f in self.model._meta.fields)
return self.model(*values)"""
Person Model - Only need to add "alias = Alias()" to a model to add a one-to-many alias field.
class Person(models.Model):
name = models.CharField(max_length=30,blank=True,null=True)
age = models.IntegerField(blank=True,null=True)
alias = Alias()
Now you I can do something like this:
per = Person(name="Per",age=99)
per.save()
per.alias.create(name="Mr.P")
per_alias = per.alias.all().values_list("name",flat=True)

Django subclassing UserProfile problem

Given the code:
from django.contrib.auth.models import User
class UserProfile(models.Model):
# project userprofile, also set as AUTH_PROFILE_MODULE
user = models.ForeignKey(User, unique=True)
class AppUserProfile(UserProfile):
# some app specific extension
and the test:
user = User.objects.create()
profile = UserProfile.objects.get_or_create(user=user)
AppUserProfile.objects.create(user=user)
it fails on the last line, saying:
IntegrityError: column user_id is not unique
What I suspect is that Django uses the same table for user-userprofile and user-anotheruserprofile relationship defined by ForeignKey.
How can I solve this problem?
The cause of the error is the fact that you are creating two UserProfile-s with the same user_id. You are using "multi-table inheritance", so you only have to call AppUserProfile.objects.get_or_create(user=user) and it will work as expected.
Documentation for Django Models explains it pretty good.

How do I relate a Django model from a related table back to anoher record first model?

I have a course catalogue and am trying to include pre-requisits.
A course has 0 to n pre-requisits and a course can be the pre-quesit for 0 to n courses.
The course class is as follows
class Course(models.Model):
class Meta:
ordering = ['course_code', 'title']
course_id = models.AutoField(primary_key=True)
course_code = models.SlugField(max_length=20, null=False, blank=False)
....
....
class Pre_requisit(models.Model)
course = models.ForeignKey(Course, course_id')
pre_req = ???????
I have tried the pre_req field as a ForeginKey and MamyToManyField but cant find a solution.
Django will not allow 2 ForeignKeys from Pre_requisit class to the Course class.
With the ManyToMany field evn through another table I still get errors.
Can anyone let me know how to acheive this relationship.
I wish to ensure the pre-requisit course exists and be able to link to it so it can be displayed.
Many thanks.
class Course(models.Model):
....
pre_req = models.ManyToManyField("self")
read more at http://docs.djangoproject.com/en/dev/ref/models/fields/#manytomanyfield
If you wish to store extra info you can specify a "through" table also ( info at http://docs.djangoproject.com/en/dev/topics/db/models/#intermediary-manytomany) such as hard pre-requisite or recommended etc.

Resources