Django is best suited to the so-called green-field development, that is, a project from the ground up, just as you have built a building from scratch on a piece of land that still has grass. However, it is still possible to integrate this framework with legacy databases and applications despite Django's preference for a project from the beginning. This chapter describes some integration techniques. Django is best suited to the so-called green-field development, that is, a project from the ground up, just as you have built a building from scratch on a piece of land that still has grass. However, it is still possible to integrate this framework with legacy databases and applications despite Django's preference for a project from the beginning. This chapter describes some integration techniques.
Integration with legacy databases
Django database layer generates SQL from Python code
Schemas-but for legacy databases, you already have SQL schemas. in this case, you need to write a model for your existing database table (due to performance reasons, django's database layer does not support non-working object-relational ing of databases during runtime introspection. to use database APIs, you need to write model code.) Fortunately, django comes with an auxiliary tool that generates model code by reading your database table plan. this auxiliary tool is called manage. py
Inspectdb
Use inspectdb
The inspectdb tool internally checks The database pointed to by your configuration file (setting file) and generates a Django
Model, and then the Python model code is displayed in the standard output of the system.
The following is an integration process for a typical legacy database from the beginning.
Create a Django project by running the django-admin.py startproject mysite (here mysite is the name of your project. Okay. In this example, we will use this mysite as the project name.
Edit the configuration file in the project,
Mysite/settings. py tells Django about your database connection parameters and database name. Specifically, you need to provide configuration information such as DATABASE_NAME, DATABASE_ENGINE, DATABASE_USER, DATABASE_PASSWORD, DATABASE_HOST, and DATABASE_PORT.
Run pythonmysite/manage. pystartappmyapp (here myapp is your app name) to create a Django App. then, we will use myapp as the app name.
Run the command pythonmysite/manage. pyinspectdb. this will check all the tables in the DATABASE_NAME database and print the model generated for each table.
Class. Take a look at the output results and think about what inspectdb can do.
Rewrite the standard shell output and save it to the models. py file of your application:
Python mysite/manage. py inspectdb> mysite/myapp/models. py
Edit the mysite/myapp/models. py file to clear the generated models and customize them. The next section provides some suggestions.
Clear the generated Models
As you may expect, database introspection is not perfect. you need to clean up the generated model code. Here is a reminder of the key points for processing the generated models:
Every table in the database is converted into a model class (that is, one-to-one ING is performed between the database table and the model class ). This means that you need to reconstruct the models of a multi-to-multi-join table as the ManyToManyField object.
Each field in each generated model has its own attributes, including the id primary key field. However, note that if a model does not have a primary key, Django automatically adds an Id primary key field to it. In this way, you may want to use the following code to delete any row:
Id = models. IntegerField (primary_key = True)
This is not just because these rows are redundant, and if your application needs to add new records to these tables, these rows cause some problems. The inspectdb command cannot detect whether a field is auto-incrementing. Therefore, you must change it to AutoField when necessary.
Each field type, such as CharField and DateField, is determined by searching for database column types such as VARCHAR and DATE. If inspectdb cannot map a model field type to the database column type, it will use TextField instead, in addition, the Python comment "This field type is guessed" is added after the generated model field ". Therefore, pay special attention to this and modify the field types as necessary.
If a field in your database cannot find an appropriate counterpart in Django, you can skip it with confidence because the Django layer does not require that each field in your table be included.
If the name of a column in the database is a reserved word of Python, such as pass, class, or for, inspectdb attaches _ field after each attribute name, set the db_column attribute to a real field name, such as pass, class, or.
For example, if a table contains an INT-type column named for, the generated model will contain the following field:
For_field = models. IntegerField (db_column = 'for ')
Inspectdb adds 'field rename because it is a reserved word' after this field '.
If a table in the database references other tables (as most database systems do), you need to modify the order of the generated model to make the reference correctly mapped. For example, the model Book has
The foreign key of Author, the latter should be defined before the former. If you need to create a link for a model that has not yet been defined, you can use the model name instead of the model object itself.
For PostgreSQL, MySQL, and SQLite database systems, inspectdb can automatically detect primary key relationships. That is, it inserts primary_key = True in the appropriate position. For other database systems, you must insert such a statement for at least one field in each model, because Django's model requires a field with primary_key = True.
Foreign key detection only applies to PostgreSQL, and some specific types in MySQL tables take effect. As for other databases, foreign key fields will be automatically generated as IntegerField if they are assumed to be INT columns.
Integration with the certification system
You can integrate Django with the usernames, passwords, and authentication methods of other existing authentication systems.
For example, your company may have installed LDAP and stored the username and password for each employee. If you have an independent account on LDAP and Django-based applications, it is a headache for network administrators and users themselves.
To solve this problem, the Django authentication system allows you to interact with other authentication resources through plug-ins. You can override the default database-based mode of Diangos. you can also use the default system to interact with other systems.
Specify the authentication backend
In the background, Django maintains a list of backend servers used for authentication check. When someone calls django. contrib. auth. authenticate () (as described in chapter 12), Django tries to traverse and authenticate its authentication background. If the first authentication method fails, Django will try to authenticate the second one, and so on until the attempt is complete.
The authentication backend list is specified in the AUTHENTICATION_BACKENDS setting. it should be an array of names pointing to the Python path of the Python class that knows how to authenticate, these classes can be placed anywhere in your Python path.
By default, AUTHENTICATION_BACKENDS is set as follows:
('Django. contrib. auth. backends. modelbackend ',)
This is the basic authentication mode for detecting Django user databases.
For AUTHENTICATION_BACKENDS in multiple sequential combinations, if the user name and password are valid in multiple backgrounds, Django will stop further processing after the first correct authentication.
How to write an authentication background
An authentication background is actually a class that implements the following two methods: get_user (id) and authenticate (** credentials ).
The get_user method requires a parameter id, which can be the User name, Database id, or any other value. this method returns a User object.
Method authenticate uses the certificate as the key parameter. In most cases, the method looks as follows:
class MyBackend(object):def authenticate(self, username=None, password=None):# Check the username/password and return a User.
But sometimes it can also authenticate a token, for example:
class MyBackend(object):def authenticate(self, token=None):# Check the token and return a User.
In each method, authenticate should check the certificate it obtains, and when the certificate is valid, return a User object that matches the certificate, if the certificate is invalid, then return None.
As described in Django sessions, users, and registration, the Django management system is closely connected to the User objects in its own background database. The best way to implement this function is to create a corresponding Django for each user in your background database (such as the LDAP directory and external sqldatabase ).
User object. You can write a script in advance to complete this job, or implement it in the authenticate method when a user logs on for the first time.
The following is an example background program. The background is used to authenticate the username and password variables defined in the setting. py file, and create a corresponding DjangoUser object when the user authenticates for the first time.
from django.conf import settingsfrom django.contrib.auth.models import User, check_passwordclass SettingsBackend(object):"""Authenticate against the settings ADMIN_LOGIN and ADMIN_PASSWORD.Use the login name, and a hash of the password. For example:ADMIN_LOGIN = 'admin'ADMIN_PASSWORD = 'sha1$4e987$afbcf42e21bd417fb71db8c66b321e9fc33051de'"""def authenticate(self, username=None, password=None):login_valid = (settings.ADMIN_LOGIN == username)pwd_valid = check_password(password, settings.ADMIN_PASSWORD)if login_valid and pwd_valid:try:user = User.objects.get(username=username)except User.DoesNotExist:# Create a new user. Note that we can set password# to anything, because it won't be checked; the password# from settings.py will.user = User(username=username, password='get from settings.py')user.is_staff = Trueuser.is_superuser = Trueuser.save()return userreturn Nonedef get_user(self, user_id):try:return User.objects.get(pk=user_id)except User.DoesNotExist:
Return None integration with legacy Web applications
Similar to applications driven by other technologies, running Django applications on the same Web server is also feasible. The simplest and most direct method is to use the httpd. conf configuration file of Apaches to proxy different URL types to different technologies.
The key is that Django will activate a driver of a specific URL type only after relevant definitions are made in your httpd. conf file. The default deployment scheme described in chapter 20th assumes that you need Django to drive every page in a specific domain.
SetHandler python-programPythonHandler django.core.handlers.modpythonSetEnv DJANGO_SETTINGS_MODULE mysite.settingsPythonDebug On
Here, This line indicates that Django is used to process each URL starting with a root.
What's more, Django adds The command value is limited to a specific directory tree. For example, you have a legacy PHP application that drives most pages in a domain, and you want to keep PHP code running without interrupting .. install a Django domain at/admin. To do this, you just need Set the value to/admin.
SetHandler python-programPythonHandler django.core.handlers.modpythonSetEnv DJANGO_SETTINGS_MODULE mysite.settingsPythonDebug On
With this setting, only the URLs starting with/admin/will trigger Django to process them, and any other pages will still be processed according to the previous settings.
Please note that letting Diango process those qualified URLs (for example,/admin/in this chapter) does not affect its URL resolution. Absolute paths are valid for Django (for example,/admin/people/person/add /), instead of removing the/admin/URL (for example, ''/people/person/add /). This means that your root URLconf must contain the previous/admin /.
The preceding section describes how Django integrates existing databases and applications. For more information, see The PHP Chinese website (www.php1.cn )!