{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Databases\n", "## 1. Introduction to Databases\n", "\n", "In the digital world, data is ubiquitous and forms the backbone of most applications, especially web applications. This section introduces databases, their importance in web development, and the various types of databases.\n", "\n", "### 1.1 What is a Database?\n", "\n", "A database is a structured set of data. It serves as an \"electronic filing system,\" organized in such a way that it allows developers to store, retrieve, add, delete, and update data efficiently. Databases are crucial for maintaining the persistent state of an application, and for providing a means to interact with the data that drives the application logic.\n", "\n", "```python\n", "# A simplified example of a database could be a Python dictionary\n", "# where data is stored in key-value pairs.\n", "database = {\n", " \"user1\": \"password1\",\n", " \"user2\": \"password2\",\n", " \"user3\": \"password3\"\n", "}\n", "```\n", "\n", "### 1.2 Importance of Databases in Web Development\n", "\n", "In web development, databases play an essential role. They store the data generated by web applications, such as user information, posts on social media, transactions in online stores, and more. A web application uses a database to create (insert), read, update, and delete (collectively known as CRUD operations) data.\n", "\n", "### 1.3 Types of Databases: Relational (SQL) vs. Non-Relational (NoSQL)\n", "\n", "There are two main types of databases: relational databases and non-relational databases.\n", "\n", "- **Relational Databases:** Also known as SQL databases, relational databases store data in a structured format using rows and columns (much like a spreadsheet). They are ideal for applications that require complex queries, transactions, and predefined relationships between tables.\n", "\n", "- **Non-Relational Databases:** Non-relational databases, also known as NoSQL databases, are more flexible than their relational counterparts. They store data in a variety of formats including document, key-value, wide-column, or graph stores. They are ideal for applications that require flexibility, scalability, and speed.\n", "\n", "In the following sections, we will delve deeper into these two types of databases and their usage in web development.\n", "\n", "## 2. Understanding Relational Databases\n", "\n", "Relational databases, also known as SQL databases, are one of the most common types of databases used in web development. They organize data in a structured way, using tables, rows, and columns. This section will delve into the structure of a relational database, key concepts such as primary keys and foreign keys, an overview of SQL, and examples of relational databases.\n", "\n", "### 2.1 Structure of a Relational Database: Tables, Rows, and Columns\n", "\n", "A relational database organizes data into one or more tables. Each table is associated with a particular topic, such as users or orders, and each row in the table represents a single record related to that topic. Columns within the table represent different attributes of the records.\n", "\n", "For example, a `users` table might have columns for `id`, `username`, `email`, and `password`.\n", "\n", "```sql\n", "CREATE TABLE users (\n", " id INT PRIMARY KEY,\n", " username VARCHAR(50),\n", " email VARCHAR(50),\n", " password VARCHAR(50)\n", ");\n", "```\n", "\n", "### 2.2 Key Concepts: Primary Key, Foreign Key, Index\n", "\n", "- **Primary Key:** A primary key is a unique identifier for a row in a table. No two rows in a table can have the same primary key. In the `users` table example above, the `id` column serves as the primary key.\n", "\n", "- **Foreign Key:** A foreign key is a field in one table, that uniquely identifies a row of another table. It is used to establish and enforce a link between the data in two tables.\n", "\n", "- **Index:** An index in a database is similar to an index in a book. It is a pointer to data in a table. An index in a database is used to speed up the performance of searches and queries.\n", "\n", "### 2.3 Overview of SQL (Structured Query Language)\n", "\n", "SQL (Structured Query Language) is a programming language used to communicate with and manipulate databases. Most of the SQL database systems use SQL, but most of them also have their own additional proprietary extensions that are usually only used on their system. However, the standard SQL commands such as \"Select\", \"Insert\", \"Update\", \"Delete\", \"Create\", and \"Drop\" can be used to accomplish almost everything that one needs to do with a database.\n", "\n", "```sql\n", "SELECT username FROM users WHERE id = 1;\n", "```\n", "\n", "### 2.4 Examples of Relational Databases\n", "\n", "Some popular examples of relational databases include:\n", "\n", "- **MySQL:** An open-source relational database known for its speed and reliability. MySQL is used by many large organizations, including Facebook and YouTube.\n", "\n", "- **PostgreSQL:** An open-source object-relational database system that uses and extends the SQL language combined with many features that safely store and scale complicated data workloads.\n", "\n", "- **SQLite:** A self-contained, high-reliability, embedded, full-featured, public-domain, SQL database engine. It is the most used database engine in the world, largely due to its use in mobile phones and browsers.\n", "\n", "In the following sections, we'll explore how to design databases, how to interact with them, and how they're used in web development.\n", "\n", "## 3. Understanding Non-Relational Databases\n", "\n", "Non-relational databases, also known as NoSQL databases, are a type of database that can store and retrieve data that is modeled in means other than tabular relations used in relational databases. They're designed to be flexible, scalable, and capable of handling large amounts of data. This section will cover the types of non-relational databases, when to use them, and examples of non-relational databases.\n", "\n", "### 3.1 Types of Non-Relational Databases\n", "\n", "There are four main types of non-relational databases:\n", "\n", "- **Document Databases:** Store data in documents similar to JSON (JavaScript Object Notation) objects. Each document contains pairs of fields and values. The values can typically be a variety of types including things like strings, numbers, booleans, arrays, or objects, and their structures typically align with objects developers are working with in code.\n", "\n", "- **Key-Value Stores:** Data is stored as a collection of key-value pairs. The key is a unique identifier, and the value is the data that is associated with the key.\n", "\n", "- **Wide-Column Stores:** These databases store data in columns instead of rows. They're designed to store and process large amounts of data distributed across many machines.\n", "\n", "- **Graph Stores:** These databases are used to store information about networks, such as social connections. They include Neo4j and Giraph.\n", "\n", "### 3.2 When to Use Non-Relational Databases\n", "\n", "Non-relational databases are ideal for applications that require flexibility, scalability, and speed. They're particularly useful when dealing with:\n", "\n", "- **Large amounts of data:** Non-relational databases can handle large volumes of data because they're designed to scale out by distributing the data across many servers.\n", "\n", "- **Flexible data models:** Non-relational databases don't require a fixed schema like relational databases do. This allows you to be flexible with the data you store.\n", "\n", "- **Real-time insights:** Non-relational databases often support horizontal scaling, which can provide the infrastructure for real-time analytics and high-speed transactions and app behaviors.\n", "\n", "### 3.3 Examples of Non-Relational Databases\n", "\n", "Some popular examples of non-relational databases include:\n", "\n", "- **MongoDB:** An open-source document database known for its flexibility and scalability. MongoDB stores data in a binary representation called BSON (Binary JSON).\n", "\n", "- **Cassandra:** A wide-column store modelled on Google's Bigtable. Designed to handle large amounts of data across many commodity servers, providing high availability with no single point of failure.\n", "\n", "- **Redis:** An open-source, in-memory data structure store, used as a database, cache and message broker. It supports various data structures such as Strings, Hashes, Lists, Sets, etc.\n", "\n", "- **Neo4j:** An open-source graph database, implemented in Java. The developers describe Neo4j as an ACID-compliant transactional database with native graph storage and processing.\n", "\n", "In the next sections, we'll explore how to design databases, how to interact with them, and how they're used in web development.\n", "\n", "## 4. Database Design Principles\n", "\n", "Designing a database is a crucial step in the development of a web application. A well-designed database ensures that your application is efficient, reliable, and scalable. In this section, we'll explore data normalization, entity-relationship diagrams, and the importance of good database design.\n", "\n", "### 4.1 Data Normalization\n", "\n", "Normalization is the process of structuring a relational database in accordance with a series of so-called normal forms in order to reduce data redundancy and improve data integrity. It involves decomposing a table into less redundant (and smaller) tables without losing information; defining foreign keys in the old table referencing the primary keys of the new ones.\n", "\n", "The objectives of normalization were stated as follows by Codd:\n", "\n", "- To free the collection of relations from undesirable insertion, update and deletion dependencies.\n", "- To reduce the need for restructuring the collection of relations, as new types of data are introduced, and thus increase the life span of application programs.\n", "- To make the relational model more informative to users.\n", "- To make the collection of relations neutral to the query statistics, where these statistics are liable to change as time goes by.\n", "\n", "### 4.2 Entity-Relationship Diagrams\n", "\n", "An entity-relationship diagram (ERD) is a data modeling technique that graphically illustrates an information system’s entities and the relationships between those entities. An ERD is a conceptual and representational model of data used to represent the entity framework infrastructure.\n", "\n", "Designed by Peter Chen in 1976, the ERD is comprised of several components:\n", "\n", "- Entity: An entity can be a person, place, event, or object that is relevant to a given system. For example, a school system may include entities such as students, teachers, courses, assignments, etc.\n", "\n", "- Attribute: An attribute is a property, trait, or characteristic of an entity, relationship, or another attribute.\n", "\n", "- Relationship: A relationship is the manner in which entities associate with each other. Relationships are mapped with entities in various ways.\n", "\n", "### 4.3 Importance of Good Database Design\n", "\n", "Good database design is crucial for a number of reasons:\n", "\n", "- **Efficiency:** A well-designed database promotes efficient data access and manipulation, and reduces the storage space required.\n", "\n", "- **Integrity:** Database design also affects data integrity, or the accuracy and consistency of the data. Good database design helps to ensure that your data is accurate, consistent, and reliable.\n", "\n", "- **Scalability:** As your web application grows, so too will the amount of data it handles. A well-designed database is easier to scale and can handle increases in workload without a significant drop in performance.\n", "\n", "- **Security:** Good database design can also help to protect your data by making it easier to manage user permissions and control access to sensitive information.\n", "\n", "In the following sections, we'll explore how to perform CRUD operations, how to connect a database to a web application, and more.\n", "\n", "## 5. CRUD Operations in Databases\n", "\n", "In the context of databases, CRUD refers to the basic operations that form the foundation of any persistent storage application: Create, Read, Update, and Delete. These operations are integral to the interaction between a web application and its database. This section will cover what each operation entails and provide examples using SQL for a relational database and MongoDB for a non-relational database.\n", "\n", "### 5.1 Create\n", "\n", "The Create operation involves adding new data to the database.\n", "\n", "For a SQL database, this might involve using an INSERT statement:\n", "```sql\n", "INSERT INTO users (username, email, password)\n", "VALUES ('johndoe', 'johndoe@example.com', 'password123');\n", "```\n", "\n", "For a MongoDB database, this might involve using the insertOne() method:\n", "```javascript\n", "db.users.insertOne({ username: 'johndoe', email: 'johndoe@example.com', password: 'password123' });\n", "```\n", "\n", "### 5.2 Read\n", "\n", "The Read operation retrieves data from the database.\n", "\n", "For a SQL database, this might involve using a SELECT statement:\n", "```sql\n", "SELECT * FROM users WHERE username = 'johndoe';\n", "```\n", "\n", "For a MongoDB database, this might involve using the findOne() method:\n", "```javascript\n", "db.users.findOne({ username: 'johndoe' });\n", "```\n", "\n", "### 5.3 Update\n", "\n", "The Update operation modifies existing data in the database.\n", "\n", "For a SQL database, this might involve using an UPDATE statement:\n", "```sql\n", "UPDATE users SET email = 'newemail@example.com' WHERE username = 'johndoe';\n", "```\n", "\n", "For a MongoDB database, this might involve using the updateOne() method:\n", "```javascript\n", "db.users.updateOne({ username: 'johndoe' }, { $set: { email: 'newemail@example.com' } });\n", "```\n", "\n", "### 5.4 Delete\n", "\n", "The Delete operation removes data from the database.\n", "\n", "For a SQL database, this might involve using a DELETE statement:\n", "```sql\n", "DELETE FROM users WHERE username = 'johndoe';\n", "```\n", "\n", "For a MongoDB database, this might involve using the deleteOne() method:\n", "```javascript\n", "db.users.deleteOne({ username: 'johndoe' });\n", "```\n", "\n", "Understanding CRUD operations is fundamental to interacting with a database from a web application. The specific syntax and methods used will depend on the specific database you're working with.\n", "\n", "## 6. Connecting a Database to a Web Application\n", "\n", "Regardless of the type of web application you're building, if it involves storing and retrieving data, you'll need to connect your application to a database. This section will cover the basics of how this is done, with examples using Python's SQLAlchemy for a SQL database and Python's PyMongo for a MongoDB database.\n", "\n", "### 6.1 SQL Databases with SQLAlchemy\n", "\n", "SQLAlchemy is a SQL toolkit and Object-Relational Mapping (ORM) system for Python, which provides a full suite of well known enterprise-level persistence patterns. It allows application developers to work with SQL databases in a more Pythonic way, abstracting away many of the direct SQL commands.\n", "\n", "To connect a Flask application to a SQLite database, you might do something like this:\n", "\n", "```python\n", "from flask import Flask\n", "from flask_sqlalchemy import SQLAlchemy\n", "\n", "app = Flask(__name__)\n", "app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db'\n", "db = SQLAlchemy(app)\n", "```\n", "\n", "This creates a Flask application and configures it to connect to a SQLite database located at `/tmp/test.db`.\n", "\n", "### 6.2 NoSQL Databases with PyMongo\n", "\n", "PyMongo is a Python distribution containing tools for working with MongoDB, and is the recommended way to work with MongoDB from Python.\n", "\n", "To connect a Flask application to a MongoDB database, you might do something like this:\n", "\n", "```python\n", "from flask import Flask\n", "from flask_pymongo import PyMongo\n", "\n", "app = Flask(__name__)\n", "app.config[\"MONGO_URI\"] = \"mongodb://localhost:27017/myDatabase\"\n", "mongo = PyMongo(app)\n", "```\n", "\n", "This creates a Flask application and configures it to connect to a MongoDB database running on localhost on port 27017.\n", "\n", "After you've established a connection to your database, you can then use this connection to perform CRUD operations and interact with your data. In the next section, we'll explore how to use databases in the context of web development, including sessions, user authentication, and more.\n", "\n", "## 7. Using Databases in Web Development\n", "\n", "Databases play a crucial role in web development, enabling the persistence and manipulation of data. They underpin many of the features we take for granted on the web, from user accounts to content management systems. In this section, we will explore some common use cases for databases in web development, including sessions, user authentication, and content management.\n", "\n", "### 7.1 Sessions and Cookies\n", "\n", "In web development, a session refers to a series of related interactions between a user and a web application that take place within a given timeframe. Sessions are used to maintain state between requests, which is important because HTTP is a stateless protocol.\n", "\n", "Cookies are often used in conjunction with sessions to identify a user between requests. When a user logs in, a session is created on the server, and a cookie containing a session identifier is sent to the user's browser. This session identifier is then included in subsequent requests, allowing the server to recognize the user and remember their state.\n", "\n", "Databases can be used to store session data, such as user preferences, shopping cart contents, or the current stage in a multi-step process.\n", "\n", "### 7.2 User Authentication\n", "\n", "User authentication is the process of verifying a user's identity. This typically involves a user providing a username and password, which are then checked against stored data in a database. If the provided data matches the stored data, the user is authenticated.\n", "\n", "In addition to storing usernames and passwords (always hashed and salted for security), databases can store other user-related data, such as email addresses, profile information, and user roles and permissions.\n", "\n", "### 7.3 Content Management\n", "\n", "Many websites are powered by content management systems (CMS), which allow users to manage the content of their websites without needing to know how to code. At the core of every CMS is a database.\n", "\n", "The database stores all the content for the website, as well as metadata, user data, and more. When a user visits a website, the CMS retrieves the requested content from the database, builds a webpage with that content, and sends the webpage to the user's browser.\n", "\n", "## 8. Database Security\n", "\n", "As a web developer, one of your responsibilities is to ensure that the data in your database is secure and that your application is safe from common threats. This section will cover some basic database security principles, including data encryption, user privileges and permissions, and protection against SQL injection attacks.\n", "\n", "### 8.1 Data Encryption\n", "\n", "Data encryption involves encoding your data in such a way that only authorized parties can read it. This is particularly important for sensitive data, such as user passwords or credit card information.\n", "\n", "In many databases, you can encrypt your data at rest (i.e., while it's stored in the database) and in transit (i.e., while it's being sent between your application and the database). The exact method of encryption will depend on the specific database you're using.\n", "\n", "### 8.2 User Privileges and Permissions\n", "\n", "Most databases allow you to control which users have access to what data. By carefully managing user privileges and permissions, you can ensure that users can only access the data they need to, and that they can't perform actions they shouldn't be able to.\n", "\n", "For example, a user might have permission to read data from a table but not to modify or delete it. Or a user might have permission to access one database but not another.\n", "\n", "### 8.3 Protection Against SQL Injection\n", "\n", "SQL injection is a common security vulnerability in which an attacker is able to execute arbitrary SQL code in your database. This can result in data being leaked, modified, or deleted.\n", "\n", "To protect against SQL injection, it's important to sanitize any user input that is incorporated into a SQL query. Most modern database libraries provide functions for safely incorporating user input into SQL queries.\n", "\n", "In conclusion, while databases are a powerful tool for web development, they also come with their own set of security considerations. By keeping these principles in mind, you can help ensure that your application's data is secure.\n", "\n", "## 9. Hands-On Exercise: Building a Simple Database-Backed Web Application\n", "\n", "Now that we've covered the theory of databases and their use in web development, it's time for some practical application. In this exercise, we'll guide you through the process of building a simple database-backed web application using Flask and SQLAlchemy.\n", "\n", "### 9.1 Setting Up the Application and Database\n", "\n", "First, let's create a new Flask application and set up a SQLite database:\n", "\n", "```python\n", "from flask import Flask\n", "from flask_sqlalchemy import SQLAlchemy\n", "\n", "app = Flask(__name__)\n", "app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///mydatabase.db'\n", "db = SQLAlchemy(app)\n", "```\n", "\n", "### 9.2 Defining a Model\n", "\n", "Next, we'll define a model for our data. For this exercise, let's create a simple blog, with a model for blog posts:\n", "\n", "```python\n", "class Post(db.Model):\n", " id = db.Column(db.Integer, primary_key=True)\n", " title = db.Column(db.String(80), nullable=False)\n", " content = db.Column(db.Text, nullable=False)\n", "\n", " def __repr__(self):\n", " return '' % self.title\n", "```\n", "\n", "### 9.3 Creating Routes for CRUD Operations\n", "\n", "Next, we'll create some routes for our CRUD operations. For simplicity, we'll just create routes for creating and viewing posts:\n", "\n", "```python\n", "from flask import render_template, request, redirect, url_for\n", "\n", "@app.route('/post', methods=['GET', 'POST'])\n", "def post():\n", " if request.method == 'POST':\n", " title = request.form['title']\n", " content = request.form['content']\n", " new_post = Post(title=title, content=content)\n", " db.session.add(new_post)\n", " db.session.commit()\n", " return redirect(url_for('index'))\n", " return render_template('post.html')\n", "\n", "@app.route('/')\n", "def index():\n", " posts = Post.query.all()\n", " return render_template('index.html', posts=posts)\n", "```\n", "\n", "### 9.4 Creating Templates\n", "\n", "Finally, we'll create some simple Jinja templates for our routes. For simplicity, we'll just create basic HTML forms for creating posts and a simple list for viewing them:\n", "\n", "`post.html`:\n", "\n", "```html\n", "
\n", "
\n", "
\n", "
\n", "
\n", " \n", "
\n", "```\n", "\n", "`index.html`:\n", "\n", "```html\n", "{% for post in posts %}\n", "

{{ post.title }}

\n", "

{{ post.content }}

\n", "{% endfor %}\n", "Create a new post\n", "```\n", "\n", "That's it! You've built a simple database-backed web application. From here, you can expand on this foundation with user authentication, more complex models and relationships, and more.\n", "\n", "## 10. Working with SQLite and Flask\n", "\n", "SQLite is a self-contained, serverless, and zero-configuration database engine. It is often the database of choice for small to medium web applications and perfect for getting started due to its simplicity. In this section, we will explore how to use SQLite with Flask using SQLAlchemy.\n", "\n", "### 10.1 Setting Up SQLite with Flask\n", "\n", "The first step is to configure Flask to use SQLite as the database. We use SQLAlchemy, which is a Python SQL toolkit that provides an Object-Relational Mapping (ORM) for SQL databases, including SQLite:\n", "\n", "```python\n", "from flask import Flask\n", "from flask_sqlalchemy import SQLAlchemy\n", "\n", "app = Flask(__name__)\n", "app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db'\n", "db = SQLAlchemy(app)\n", "```\n", "\n", "In this setup, SQLAlchemy is configured to interact with a SQLite database located at `/tmp/test.db`.\n", "\n", "### 10.2 Defining a Model\n", "\n", "Next, let's define a simple model. Models in SQLAlchemy are Python classes that represent database tables:\n", "\n", "```python\n", "class User(db.Model):\n", " id = db.Column(db.Integer, primary_key=True)\n", " username = db.Column(db.String(80), unique=True, nullable=False)\n", " email = db.Column(db.String(120), unique=True, nullable=False)\n", "\n", " def __repr__(self):\n", " return '' % self.username\n", "```\n", "\n", "This model represents a `User` table with `id`, `username`, and `email` columns.\n", "\n", "### 10.3 Performing CRUD Operations\n", "\n", "With our model in place, we can now perform CRUD operations.\n", "\n", "#### Creating Records\n", "\n", "To create a new record, instantiate the model class and add it to the session:\n", "\n", "```python\n", "from flask import Flask\n", "\n", "app = Flask(__name__)\n", "\n", "@app.route('/')\n", "def index():\n", " new_user = User(username='john', email='john@example.com')\n", " db.session.add(new_user)\n", " db.session.commit()\n", " return \"User added.\"\n", "```\n", "\n", "#### Reading Records\n", "\n", "To read records from the database, use the query attribute provided by SQLAlchemy:\n", "\n", "```python\n", "@app.route('/')\n", "def index():\n", " user = User.query.filter_by(username='john').first()\n", " return 'User %s' % user.username\n", "```\n", "\n", "#### Updating Records\n", "\n", "To update a record, query the record, update the attributes, and commit the session:\n", "\n", "```python\n", "@app.route('/')\n", "def index():\n", " user = User.query.filter_by(username='john').first()\n", " user.email = 'john@newexample.com'\n", " db.session.commit()\n", " return 'Email updated.'\n", "```\n", "\n", "#### Deleting Records\n", "\n", "To delete a record, query the record, pass it to `db.session.delete()`, and commit the session:\n", "\n", "```python\n", "@app.route('/')\n", "def index():\n", " user = User.query.filter_by(username='john').first()\n", " db.session.delete(user)\n", " db.session.commit()\n", " return 'User deleted.'\n", "```\n", "\n", "This section provides a brief introduction to using SQLite with Flask. For more complex scenarios, such as relationships between models, consult the Flask-SQLAlchemy documentation.\n", "\n", "\n", "## 11. Key Takeaways\n", "\n", "In this chapter, we have explored the fundamentals of databases as they pertain to web development. Let's recap some of the most important points:\n", "\n", "1. **Understanding Databases**: Databases are organized collections of data. The two main types of databases are SQL (relational) and NoSQL (non-relational), each with its strengths and use-cases.\n", "\n", "2. **CRUD Operations**: The four basic functions of persistent storage are Create, Read, Update, and Delete (CRUD). These functions form the basis of interacting with data stored in a database.\n", "\n", "3. **Database Models and Relationships**: Data in a database is organized into tables (for SQL databases) or collections (for NoSQL databases). Relationships between data can be modeled in various ways, such as one-to-one, one-to-many, and many-to-many.\n", "\n", "4. **Connecting a Database to a Web Application**: In Python web development, libraries like SQLAlchemy (for SQL databases) and PyMongo (for MongoDB) are often used to connect web applications to databases.\n", "\n", "5. **Database Use Cases in Web Development**: Databases underpin many features of web applications, including sessions, user authentication, and content management.\n", "\n", "6. **Database Security**: Protecting your database is crucial. This includes encrypting sensitive data, managing user privileges and permissions, and protecting against SQL injection attacks.\n", "\n", "7. **Practical Application**: By creating a simple database-backed web application, you've seen how these concepts come together in practice.\n", "\n", "By understanding these principles, you are well-equipped to leverage databases in your web development projects. In the next chapter, we will dive into another critical aspect of web development - front-end technologies and their role in creating dynamic and interactive websites.\n", "\n", "## Resources for Learning More about Databases and Web Development\n", "\n", "* [Mark Liffiton's SQL Links](https://sun.iwu.edu/~mliffito/cs_codex/posts/sql/)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.11.3" } }, "nbformat": 4, "nbformat_minor": 1 }