Custom South migration with custom fields - Django - database

I am pretty new to Django and just got a job that involves maintaining and adding features to a site I did not design, so I am still kind of confused about the structure and what not of the project. The site is using South for database migrations and I've got a hang of using it to add new applications to the project. The trouble I am having now is that I need to delete a certain field in a model because it is no longer needed and on the admin page it is required to be filled out. From my understanding of Django so far it appears to be a custom field. It is defined like this in its own separate library application(still not sure if thats the right lingo).
class Genre(models.Model):
name = models.CharField(max_length=255)
def __unicode__(self):
return u"%s" % self.name
Here is the models that uses the custom field if that helps out any.
class Entry(models.Model):
artist = d51fields.ForeignKey(Artist, instantiate_fn=instant_artist)
album = d51fields.ForeignKey(Album, js_methods=['match_artist_and_startswith'], instantiate_fn=instant_album)
track = d51fields.ForeignKey(Track, js_methods=['match_album_and_startswith'], instantiate_fn=instant_track)
genre = models.ForeignKey(Genre)
submitted = models.DateTimeField(auto_now_add=True)
is_rotation = models.BooleanField()
dj = models.ForeignKey(DJ)
show = models.ForeignKey(Show, null=True, blank=True)
objects = EntryManager()
def __unicode__(self):
return "%s [%s]" % (self.artist, self.track)
class Meta:
verbose_name = "entry"
verbose_name_plural = "entries"
I've looked at the documentation for migrating custom fields but it is all really confusing for me, so I am looking for some more help. I just want to get rid of the table holding the Genre field and clean up the dependencies with the foreign keys associated with it. Do you think I should write some custom rules for South and use a migration or just try and do it manually in Postgresql. I tried doing it with just Postgres and I failed miserably.
Any guidance would be greatly appreciated. If you want more info about the situation just ask and I can add it to the post. I have a feeling there is a lot of dependencies I will have to deal with, but hopefully there is a simple fix.
Also if some one knows how to get a good view of the database structure that would be great.
Thanks so much. All of you guys are great.
Edit1
Here what I got when I removed the ForeignKeys and then ran
manage.py schemamigration logs --auto
! Cannot freeze field 'logs.entry.artist'
! (this field has class d51_admin_autofk.fields.ForeignKey)
! Cannot freeze field 'logs.entry.album'
! (this field has class d51_admin_autofk.fields.ForeignKey)
! Cannot freeze field 'logs.entry.track'
! (this field has class d51_admin_autofk.fields.ForeignKey)
! South cannot introspect some fields; this is probably because they are custom
! fields. If they worked in 0.6 or below, this is because we have removed the
! models parser (it often broke things).
I am not totally sure what sort of action I should take next. I looked into the South documentation and it wasn't too clear about how to write the rules for migrating things like this.

I don't see any custom field anywhere in the code you posted. All I see is two models, all containing standard fields shipped with Django.
If I understand correctly, you can just delete all ForeignKey references to your Genre model. Then run ./manage.py schemamigration <yourappname> --auto. This will ask you for a default value for the genre field in the Entry model, provide an ID of some kind. (This is because migrations can be applied both forwards and backwards, so if you try to undo the migration, this is the value that will get inserted in all your model instances.)
Finally, just applying the migration should make it happen: ./manage.py migrate <yourappname>.
After that you should be safe to drop the table storing your Genre model.
Be sure to try this on a development server though, just to make sure it doesn't blow up. (-;

Related

Django ownership foreign key to User or UserExtenstion

I'm quite new with Django, and so far I have a pretty basic setup where I attach an extra model to the default User model from (django.contrib.auth.models). In my accounts.models.py I have something in the line of:
class UserExtension(models.Model):
user = models.OneToOneField(User, primary_key=True)
# more code
I also have another model which needs to be specified an owner. My question is: Which is the better (more django-ish, more readable, more efficient, more flexible) way to signify the owner:
class Owned(models.Model):
# code
owner = models.ForeignKey(User)
# more code
or:
class Owned(models.Model)
# code
owner = models.ForeignKey(UserExtension)
# more code
I'll really appreciate if you mention pros and cons of those approaches.
I'd recommend the first option. The user model is the nontrivial model in the sense that an owned object should not be able to exist without a user, but could exist without a UserExtension.
Also consider that in Django 1.5 you are able to create custom user model, eliminating the need for the UserExtension class. See the documentation for more information.
Consider using UserProfile for any per user add-on information. Check out this blog to see how to do it. Then you can be assured that you are creating UserProfile object every time you create the User.
Now whether you FK on User or UserProfile depends logically on what you are doing within Owned. If Owned works with User's data/field, FK on User; if it works with UserProfile's data, FK on UserProfile.

How to use Yii with a multilingual database model?

I’m having a problem getting the data from my database which I created to be completely multilingual, and I hope someone here can help me.
I’ve split up all my tables in 2 parts; the “universal” table (does not contain any text that needs to be translated) and the table which contains all the fields that need to be translated with their translations.
Example tables:
base_material
id
picture
base_material_i18n
base_material_id
localization_id
name
description
review_status
review_notes
localization
id
language_name
Query to get the translations (using English (en) as a fall-back language if there is no translation available):
SELECT o.id
, o.type
, o.code
, o.position
, ifnull(t.name,d.name) name
, ifnull(t.description,d.description) description
FROM base_material o
INNER JOIN base_material_i18n d
ON ( o.id=d.base_material_id)
LEFT OUTER JOIN base_material_i18n t
ON ( d.base_material_id=t.base_material_id AND t.localization_id='nl' )
WHERE d.localization_id='en'
My question is how I can automatically get those translations (with the fall-back language as in this query) attached to my model in Yii when I’m searching for the base_material objects? (This is only 1 example table, but almost all my tables (20+) are built in this way, so if possible I would be needing something flexible)
An example of an existing system using what I would need is Propel: http://propel.posterous.com/propel-gets-i18n-behavior-and-why-it-matters
Any ideas how to go about doing that? I’ve checked the existing Yii extensions regarding multilingual sites (like Multilingual Active Record), but they all use a different database design (general information+fall-back language in the main table, translations in the i18n table), and I’m not sure how to change those extensions to use my kind of DB model.
If someone knows of a way to change that existing extension so it can use my kind of DB scheme, then that would be absolutely brilliant and probably the best way to do this.
Edit: I've added a bounty because I still can't find anything on how to let Propel work with Yii (there does exist an extension for Doctrine, but Doctrine doesn't support this kind of DB model with translations either), nor any more information as to how to deal with this using an existing Yii extension or with scopes.
Edit: 98 times viewed but only 3 upvotes and 1 comment. I can't help feeling like I'm doing something wrong here, be it in my question or application/database design; either that or my problem is just very unique (which would surprise me, as I don't think my multilingual database design is that absurd ;-). So, if anyone knows of a better all-round solution for multilingual sites with Yii and/or Propel (apart from the current extensions which I really don't like due to the duplication of text fields) or something similar, please let me know as well.
Thanks in advance!
Have you tried http://www.yiiframework.com/extension/i18n-columns/ (based on http://www.yiiframework.com/extension/stranslateablebehavior/)?
It is an alternate, simpler, approach by adding new table fields in the style of {field}_{language code}, and then setting the translated field in the original model to the current language's translation on afterFind.
In essence, it will get you up and running with translatable fields with the translated content being fetched "automatically", for good and bad :). Adding and removing languages (=columns) is done using migrations.
I am also looking for a generic solution to implement i18n into Yii models.
Recently I chose a very similar database schema for a project like you.
The only difference is, that I am not using a separate language table, I store the language information in the i18n table.
The following solution is without a custom SQL statement, but I think this could be implemented with relation params, anyway, if you're working with foreign key in your database (eg. MySQL InnoDB) gii will create relations between your base_material and base_material_i18n table, like
class BaseMaterial extends CActiveRecord
public function relations()
{
return array(
'baseMaterialI18ns' => array(self::HAS_MANY, 'base_material_i18n', 'id'),
);
}
class BaseMaterialI18n extends CActiveRecord
public function relations()
{
return array(
'baseMaterial' => array(self::BELONGS_TO, 'base_material', 'id'),
);
}
Now you'd be able to access your translations by using the object notation for relations.
$model = BaseMaterial::model()->with('baseMaterialI18ns')->findByPk(1);
foreach($model->baseMaterialI18ns AS $translation) {
if ($translation->language != "the language I need") continue:
// do something with translation data ...
}
I thought about creating a behavior or base class for those models which would act a as helper for managing the translations - pseudo code:
I18nActiveRecord extends CActiveRecord
protected $_attributesI18n;
// populate _attributesI18n on query ...
public function __get($name) {
if(isset($this->_attributesI18n['language_I_need'][$name]))
return $this->_attributesI18n[$name];
else if(isset($this->_attributesI18n['fallback_language'][$name]))
return $this->_attributesI18n[$name];
else
parent::__get();
}
CActiveRecord __get() source
There is more work to be done to find the needed i18n record, also you could further limit the with() option to improve performance and reduce parsing on the PHP side.
But there may be different use cases how to determine the value, e.g. all translations, translation or fallback, no fallback (empty value).
Scenarios could be helpful here.
PS: I would be up for a github project!
You can try to use a simple multilingual CRUD extension.
it is very simple to use and modificate. you just need to add language field to your table.
just watch description here: http://all-of.me/yii-multilingual-crud/
it is in alpha state, but tried on a few projects. you can easily modificate it or contact author to fix or add features

Django, db update, south and sqliteman: a confirmation. Not really a question. Is it better?

I have seen that actually, after asking in stackoverflow.com, there might be a lot of equivalent questions.. But I got the box where to write already and my google searches
are not any better. (I was testing blekko.com for a while.. as a search engine.. give it a try)
Back to the question:
If I have: models.py
class someclass(models.Model):
title = models.CharField(max_length=200)
And I run all the stuff till the site is working...
Now I do (models.py):
class someclass(models.Model):
title = models.CharField(max_length=200)
sub_title = models.CharField(max_length=200)
And I use sqliteman or phpmyadmin to add a column named 'sub_title' which will get some
default value, namely NULL. (regardless of some django constrains, like not NULL)
Would I brake something within django?
I guess I would always have the possibility to dump the db and read it back.
Not sure yet how to do it in django in a clean way but there should be a way.
Is there such a way?
My question stops here.
But as additional hint, I did check south which didn't work for me 'right out of the box',
in particular for an existing project. Before to get into some other problems,
I realized that I only need columns updates while developing the site.
I present to my customer (this is at present a free/free no money situation)
the stages of development... and I do not want to reset the DB at every version.

Django ModelForm save using db_alias param "using"

Is it possible to save ModelForm object data with db_alias different than "default"
my_form = MyModelForm(request.POST)
my_form.save(commit=True,using="db_alias")
as well as saving data with model instance?
Thank you.
Short Answer: Unfortunately ,you can't save the form that way. If you form doesn't contain ForeignKey or m2m fields (or you are controlling them yourself, for example using an autocompletefield, etc.), you can handle the object after the form:
_obj = _form.save(commit=False)
_obj.save(using=_db_alias)
Long answer: If you want the modelform to behave like a normal one with ForeignKeys and m2m-fields, something like:
# The form's foreign_keys and m2m-fields get the data from the db_alias database
# and evertyhing is sdisplayed correctly on the template.
_form = myModelForm(request, db_alias=_db_alias)
# The form saves to the correct DB and foreigns & M2ms are matched correctly in this DB
# _form.save()
Although this would be ideal, you just can't use this behaviour. There are many DB hooks that you need to alter in Django code to get this working. What I have done is to create a new modelform class from the base modelform, and get the (partial) functionality described before.
Hope this helps, and also hopping a better solution comes soon.

Can not Bake table model, controller and view

I developed small CakePHP application, and now I want to add one more table (in fact, model/controller/view) into system, named notes. I had already created a table of course.
But when I run command cake bake model, I do not get table Notes on the list. I can add it manually, but after that I get some errors when running cake bake controller and cake bake view.
Can you give me some clue why I have those problems, and how to add that new model?
I would also check your app/config/database.php to ensure that you are using the correct database configuration. You may well have added the table to a different database perhaps and the bake is picking up the other database. Also, and this may be obvious, but check you are in the right project, it's easy to be in a different folder and not realise, especially if you have lots of projects.
I'm not aware of a limit on the bake listing. I would check your database to make sure the table exists and has some columns. You can always open up the console bake script and check for a limit and increase it if needs be.
I found solution!
I had to delete all from cache directory, /app/tmp/cache/models
Now it works!
:-)
When you say added it manually, do you mean added the note.php model? If not, you may want to try that. Verify that the model name is correct for the following:
file name: note.php
class name: class Note extends AppModel
table name: notes
Also, be sure the notes table has the id column and it is set to primary key.
If this does not push you in the right direction, please post your notes table schema here. Also, have you had success in baking other things in your app? Have you upgraded anything?
Please change the following farameters to bake:
For Controller:
/cake/console/libs/tasks/controller.php
function listAll($useDbConfig = 'default') {
change to :
function listAll($useDbConfig = 'YOUR DB CONFIG NAME') {
NOW DO CAKE BAKE for CONTROLLER! ENJOY!

Resources