How to Implement ManyToManyField in Django - django-models

I am trying to create a small django project of a football application to show the stats & stuff.. to start with I created two classes in my models.py.. with a many to many relation.. but for some reason it's throwing a strange Database Error: no such table: football_league_team
please any help is appreciated, thanks in advance.
from django.db import models
# Create your models here.
class Team(models.Model):
team_name = models.CharField(max_length=30, unique=True)
team_code = models.CharField(max_length=4, unique=True)
team_home = models.CharField(max_length=30, unique=True)
team_registry_date = models.DateTimeField('Date of Registry')
def __unicode__(self):
return self.team_name
class League(models.Model):
league_name = models.CharField(max_length=30)
league_code = models.CharField(max_length=4)
league_division = models.IntegerField()
team = models.ManyToManyField(Team)
def __unicode__(self):
return self.league_name

You removed the field football_league_team in one of your model. Django doesn't know it and is still expecting said field. Depending your Django version, there are several ways to reset the corresponding model.
Django 1.4 and lower
> ./manage.py reset <appname>
I believe it works for earlier versions of Django, not sure though. Keep in mind that this option will reset each models of your application as opposed to the below method which allow single table drops.
Django 1.5 and higher
> ./manage.py sqlclear <appname>
will print out the commands to clear the database from the application's models.
> ./manage.py dbshell
Will allow you to use the sqlclear commands in order to drop the tables yopu want to be reseted.

Related

Customizing Profile Model in Pinax: Integrity error in admin when OnetoOneField is added

I'm new to Pinax and Django. I'm trying to extend the Pinax Profile model by having a OneToOneField that pulls from another application I plugged in (in this case, django-swingtime : http://code.google.com/p/django-swingtime/). I've got all of my models to show up in the django admin interface, but I cannot add new Users (which I want to do in the process of adding new Profiles). I get the following error:
IntegrityError at /admin/auth/user/add/
profiles_profile.event_type_id may not be NULL
Request Method: POST
Request URL: http://localhost:8000/admin/auth/user/add/
Django Version: 1.3.1
Exception Type: IntegrityError
Exception Value:
profiles_profile.event_type_id may not be NULL
My Pinax version is 0.9a2. EventType is a model from django-swingtime. I get this error when I'm trying to add a User from anywhere within the Django admin.
Here's the my Profiles/models.py (changed lines have comments next to them)
from django.db import models
from django.utils.translation import ugettext_lazy as _
from idios.models import ProfileBase
from swingtime.models import EventType #ADDED HERE
class Profile(ProfileBase):
name = models.CharField(_("name"), max_length=50, null=True, blank=True)
about = models.TextField(_("about"), null=True, blank=True)
location = models.CharField(_("location"), max_length=40, null=True, blank=True)
website = models.URLField(_("website"), null=True, blank=True, verify_exists=False)
event_type = models.OneToOneField(EventType) #ADDED HERE
def __unicode__(self):
return "Name: %s -- %s" % (self.name, self.about) #ADDED HERE
Perhaps if someone could explain the relationship between accounts, profiles, and users and what files are OK to edit and which ones are inadvisable to edit (for instance, I don't think I want to be changing anything around in my Pinax site packages...), I can make some progress. Also, I assume this idios plugin is involved in the process, but the link to documentation I've found will load (http://oss.eldarion.com/idios/docs/0.1/).
Thank you!
I've solved my error, though I'm interested in other answers and additional information since some of this is speculation/still unclear to me. I think the error stems from Pinax accounts automatically creating a "blank" idios profile for every new user created (speculation). Since I had said every profile must have a OneToOne foreign field associated with it and had not allowed for this OneToOne field to be null, there was a problem.
This question describes some of the differences between the idios profile app, Pinax account and the standard django User accounts:
Difference between pinax.apps.accounts, idios profiles, and django.auth.User
What I did to solve this problem was using the Django's signalling capabilities to make sure that as soon as a Profile is generated, so is an instance of the foreign field. This is described here:
https://docs.djangoproject.com/en/1.3/topics/signals/
Make sure to read the bit about double signalling, since this has caused trouble for some other people:
https://docs.djangoproject.com/en/1.3/topics/signals/#preventing-duplicate-signals
The final modification to my code that got rid of the error was this. Note that besides adding signalling I also explicitly said that the OnetoOneField was allowed to be null.
from django.db import models
from django.utils.translation import ugettext_lazy as _
from idios.models import ProfileBase
from swingtime.models import EventType
#for signals
from django.db.models.signals import post_save
from django.dispatch import receiver
class Profile(ProfileBase):
name = models.CharField(_("name"), max_length=50, null=True, blank=True)
about = models.TextField(_("about"), null=True, blank=True)
event_type = models.OneToOneField(EventType, null=True)
def __unicode__(self):
return "Name: %s -- %s" % (self.name, self.about)
def create_User_EventType(sender, instance, created, **kwargs):
print "checking creation of profile"
if created:
print "User event type is being created"
event_label = "%s_hours" % (instance.name)
print "the event label is" + event_label
EventType.objects.create(abbr=instance.name,label=event_label)
post_save.connect(create_User_EventType,sender=Profile,dispatch_uid="event_post_save_for_profile")

Django: Single model for multiple tables

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

Getting unmanaged models

I seem to have a problem after creating an unmanaged model (syncdb):
class Client_jobs(models.Model):
job_id = models.IntegerField(primary_key=True)
status = models.IntegerField()
class Meta:
db_table = 'client_jobs'
managed=False
in one of my def views, it calls the database view(Client_jobs)
def listjobs(request):
# if user is authenticated
if request.user.is_authenticated():
jobsArr = Client_jobs.objects.get.all()
The page returned me an error of
(1146, "Table 'table1.client_jobs' doesn't exist")
I know I'm missing something but I can't figure out. How does django detect this unmanaged model? Thank you.
as I know the db_table option will get precedence over the existing convention of app name_model name. If you set it explicitly you will have to prefix the application name yourself.
try client_jobs.client_jobs

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.

Method to migrate App Engine models

Database migrations are a popular pattern, particularly with Ruby on Rails. Since migrations specify how to mold old data to fit a new schema, they can be helpful when you have production data that must be converted quickly and reliably.
But migrating models in App Engine is difficult since processing all entities sequentially is difficult, and there is no offline operation to migrate everything effectively in one big transaction.
What are your techniques for modifying a db.Model "schema" and migrating the data to fit the new schema?
Here is what I do.
I have a MigratingModel class, which all of my models inherit from. Here is migrating_model.py:
"""Models which know how to migrate themselves"""
import logging
from google.appengine.ext import db
from google.appengine.api import memcache
class MigrationError(Exception):
"""Error migrating"""
class MigratingModel(db.Model):
"""A model which knows how to migrate itself.
Subclasses must define a class-level migration_version integer attribute.
"""
current_migration_version = db.IntegerProperty(required=True, default=0)
def __init__(self, *args, **kw):
if not kw.get('_from_entity'):
# Assume newly-created entities needn't migrate.
try:
kw.setdefault('current_migration_version',
self.__class__.migration_version)
except AttributeError:
msg = ('migration_version required for %s'
% self.__class__.__name__)
logging.critical(msg)
raise MigrationError, msg
super(MigratingModel, self).__init__(*args, **kw)
#classmethod
def from_entity(cls, *args, **kw):
# From_entity() calls __init__() with _from_entity=True
obj = super(MigratingModel, cls).from_entity(*args, **kw)
return obj.migrate()
def migrate(self):
target_version = self.__class__.migration_version
if self.current_migration_version < target_version:
migrations = range(self.current_migration_version+1, target_version+1)
for self.current_migration_version in migrations:
method_name = 'migrate_%d' % self.current_migration_version
logging.debug('%s migrating to %d: %s'
% (self.__class__.__name__,
self.current_migration_version, method_name))
getattr(self, method_name)()
db.put(self)
return self
MigratingModel intercepts the conversion from the raw datastore entity to the full db.Model instance. If current_migration_version has fallen behind the class's latest migration_version, then it runs a series of migrate_N() methods which do the heavy lifting.
For example:
"""Migrating model example"""
# ...imports...
class User(MigratingModel):
migration_version = 3
name = db.StringProperty() # deprecated: use first_name and last_name
first_name = db.StringProperty()
last_name = db.StringProperty()
age = db.IntegerProperty()
invalid = db.BooleanProperty() # to search for bad users
def migrate_1(self):
"""Convert the unified name to dedicated first/last properties."""
self.first_name, self.last_name = self.name.split()
def migrate_2(self):
"""Ensure the users' names are capitalized."""
self.first_name = self.first_name.capitalize()
self.last_name = self.last_name.capitalize()
def migrate_3(self):
"""Detect invalid accounts"""
if self.age < 0 or self.age > 85:
self.invalid = True
On a busy site, the migrate() method should retry if db.put() fails, and possibly log a critical error if the migration didn't work.
I haven't gotten there yet, but at some point I would probably mix-in my migrations from a separate file.
Final thoughts
It is hard to test on App Engine. It's hard to get access to your production data in a test environment, and at this time it is difficult-to-impossible to make a coherent snapshot backup. Therefore, for major changes, consider making a new version that uses a completely different model name which imports from the old model and migrates as it needs. (For example, User2 instead of User). That way, if you need to fall back to the previous version, you have an effective backup of the data.

Resources