Automatic solution for "Add a related_name argument to the definition for 'XXX'."?
I'm plugging Django 开发者_如何学编程into an existing system. I have been given a legacy schema, and I have to work with it.
I have generated models with inspectdb
, but I'm getting hundreds of:
ABC>DEF: Accessor for field 'HIJ' clashes with related field 'KLM'. Add a related_name argument to the definition for 'HIJ'.
I wouldn't have a problem with this if it were only a small number. But it isn't.
Is there any automatic way to fix this by adding unique related_name
s?
EDIT: For clarification, I do am looking for an automatic solution to the problem, not one that involves editing each field by hand.
Occasionally I find myself in this situation. Modifying inspectdb
has worked for me in several instances but I can't promise it'll be appropriate in every situation. Here's what I've done:
#Original inspectdb
121 if rel_to in known_models:
122 field_type = 'ForeignKey(%s' % rel_to
123 else:
124 field_type = "ForeignKey('%s'" % rel_to
#Modified inspectdb
121 if rel_to in known_models:
122 field_type = 'ForeignKey(%s' % rel_to
123 else:
124 field_type = "ForeignKey('%s'" % rel_to
125 extra_params['related_name'] = '%s_%s' % (table2model(table_name),column_to_field_name[column_name])
This will automatically add a related_name
argument to every generated model that isn't likely to collide with any others. Again, it depends on the situation, but this single line modification has saved me tons of work.
If you don't need the related name, you can set it to "+".
If you don't want to disable them completely or cannot use "+" in your django version (I can't remember when it was added), you may use something like the following:
_no_related_name_counter = 0
def no_related_name():
_no_related_name_counter += 1
return "_norn_%%(class)s_%i" % _no_related_name_counter
ForeignKey(..., related_name=no_related_name())
But if you insert related names with a regexp search and replace, you may as well set them to something readable, e.g. replace (\s*(\w+)\s*=\s*models\.ForeignKey\(.*)\)(\s*)$
with $1, related_name="%(class)s_$2_reverse")$3
You should check the foreign key relationships by specifying the related_name, like this:
user = models.ForeignKey(User, related_name='user')
admin = models.ForeignKey(User, related_name='user1') #you need to use a different related_name here
Hope it helps.
If you want to deal with large legacy database and dont want to use '+' you can run a simple script to modify the generated models.py file as follows:
import fileinput
textToSearch = "models.DO_NOTHING"
_no_related_name_counter = 1000
with fileinput.FileInput('models.py', inplace=True, backup='.bak') as file:
for line in file:
_no_related_name_counter += 1
textToReplace = 'models.DO_NOTHING, related_name="%(class)s_{}"'.format(_no_related_name_counter)
print(line.replace(textToSearch, textToReplace), end='')
精彩评论