Mysql
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Mysql

Django views.py Phiên bản SQL Tham gia với Truy vấn Nhiều Bảng

Chà, đó là một số tên bảng và trường không rõ ràng, nhưng tốt nhất tôi có thể nói rằng truy vấn sẽ trông giống như sau:

(Restaurant.objects.filter(city=8, 
     cuisine__cuisinetype__cuisine="Italian").distinct().order_by('name')[:20])

Nhưng trừ khi bạn bị khóa trong lược đồ cơ sở dữ liệu đó, các mô hình của bạn sẽ trông đẹp hơn như:

class CuisineType(models.Model):
    name = models.CharField(max_length=50)
    class Meta:
        db_table = 'cuisinetype'

class Restaurants(models.Model):
    city = models.ForeignKey("City", null=True, blank=True) # Apparently defined elsewhere. Should be part of location?
    name = models.CharField(max_length=50)
    location = models.ForeignKey("Location", null=True, blank=True) # Apparently defined elsewhere.
    cuisines = models.ManyToManyField(CuisineType)

Sau đó, truy vấn sẽ giống như sau:

Restaurant.objects.filter(city=8, cuisines__name="Italian").order_by('name')[:20]

OK, hãy xem qua truy vấn của bạn, giả sử không có thay đổi nào đối với mã của bạn. Chúng ta sẽ bắt đầu với truy vấn con.

SELECT DISTINCT res_id FROM cuisine 
        JOIN    cuisinetype ON cuisine.cuisineid = cuisinetype.`cuisineid`
        WHERE   cuisinetype.`cuisine` = 'Italian'

Chúng tôi xem xét mệnh đề WHERE và thấy rằng chúng tôi cần một JOIN. Để thực hiện một phép nối, bạn phải khai báo một trường quan hệ trong một trong các mô hình đã nối (Django sẽ thêm một quan hệ đảo ngược, mà chúng ta nên đặt tên). Vì vậy, chúng tôi đang đối sánh cuisine.cuisineid với `isinetype.cuisineid. Đó là một số cách đặt tên kinh khủng.

Đó là mối quan hệ nhiều-nhiều, vì vậy chúng ta cần một ManyToManyField . Chà, xem Cuisine mô hình, nó thực sự là bảng tham gia cho M2M này. Django mong muốn một bảng tham gia có hai ForeignKey các trường, một chỉ đến mỗi bên của khớp. Thông thường, nó sẽ tạo ra điều này để bạn tiết kiệm sự tỉnh táo. Rõ ràng là bạn không may mắn như vậy. Vì vậy, bạn phải kết nối nó theo cách thủ công.

Có vẻ như trường "GID" là trường ID (vô dụng) cho bản ghi, vì vậy hãy giả sử đó là số nguyên tăng tự động. (Để chắc chắn, hãy kiểm tra các lệnh TẠO BẢNG.) Bây giờ chúng ta có thể viết lại Cuisine mô hình thành một cái gì đó tiếp cận lành mạnh:

class Cuisine(models.Model):
    cuisinegid = models.AutoField(primary_key=True, db_column='CuisineGID')
    cuisineid = models.ForeignKey("Cuisinetype", null=True, 
        db_column='CuisineID', blank=True)
    res_id = models.ForeignKey("Restaurant", null=True, db_column='Res_ID', 
        blank=True)
    class Meta:
        db_table = 'cuisine'

Tên mô hình được trích dẫn bởi vì mô hình chưa được xác định (sau này chúng có trong tệp). Bây giờ không có yêu cầu rằng tên trường Django phải khớp với tên cột, vì vậy hãy thay đổi chúng thành một cái gì đó dễ đọc hơn. Trường ID bản ghi thường chỉ được đặt tên là id và các khóa ngoại thường được đặt tên theo những gì chúng liên quan đến:

class Cuisine(models.Model):
    id = models.AutoField(primary_key=True, db_column='CuisineGID')
    cuisine_type = models.ForeignKey("CuisineType", null=True, 
        db_column='CuisineID', blank=True)
    restaurant = models.ForeignKey("Restaurant", null=True, db_column='Res_ID', 
        blank=True)
    class Meta:
        db_table = 'cuisine'

OK, chúng ta đã xác định xong bảng chung của mình. Trong khi chúng ta đang ở đây, hãy áp dụng những thứ tương tự cho Cuisinetype của chúng ta mô hình. Lưu ý tên lớp vỏ camel đã sửa:

class CuisineType(models.Model):
    id = models.AutoField(primary_key=True, db_column='CuisineID')
    name = models.CharField(max_length=50, db_column='Cuisine', blank=True)
    class Meta:
        db_table = 'cuisinetype'

Vì vậy, cuối cùng chúng tôi đã đến Restaurant của chúng tôi mô hình. Lưu ý rằng tên là số ít; một đối tượng chỉ đại diện cho một bản ghi.

Tôi nhận thấy rằng nó thiếu bất kỳ dp_table nào hoặc db_column , vì vậy tôi đang đi chơi và đoán Django đang tạo ra nó. Điều đó có nghĩa là chúng ta có thể để nó tạo id trường cho chúng tôi và chúng tôi có thể bỏ qua trường đó khỏi mã của mình. (Nếu không phải như vậy, thì chúng tôi chỉ cần thêm nó giống như với các mô hình khác. Nhưng bạn thực sự không nên có ID bản ghi nullable.) Và đây là nơi loại ẩm thực của chúng tôi ManyToManyField cuộc sống:

class Restaurants(models.Model):
    city_id = models.ForeignKey(null=True, blank=True)
    name = models.CharField(max_length=50, blank=True)
    location = models.ForeignKey(null=True, blank=True)
    cuisine_types = models.ManyToManyField(CuisineType, through=Cuisine,
        null=True, blank=True)

Lưu ý rằng tên cho trường M2M là số nhiều, vì mối quan hệ đó dẫn đến nhiều bản ghi.

Một điều nữa chúng tôi sẽ muốn thêm vào mô hình này là tên cho các mối quan hệ ngược lại. Nói cách khác, làm thế nào để đi từ các mô hình khác trở lại Restaurant . Chúng tôi thực hiện việc này bằng cách thêm related_name thông số. Không có gì lạ khi chúng giống nhau.

class Restaurant(models.Model):
    city_id = models.ForeignKey(null=True, blank=True, 
        related_name="restaurants")
    name = models.CharField(max_length=50, blank=True)
    location = models.ForeignKey(null=True, blank=True, 
        related_name="restaurants")
    cuisine_types = models.ManyToManyField(CuisineType, through=Cuisine,
        null=True, blank=True, related_name="restaurants")

Bây giờ chúng tôi cuối cùng đã thiết lập. Vì vậy, hãy xem xét truy vấn của bạn:

SELECT  restaurants.`name`, restaurants.`address`, cuisinetype.`cuisine`
FROM    restaurants
JOIN    cuisinetype ON cuisinetype.cuisineid = restaurants.`cuisine`
WHERE   city_id = 8 AND restaurants.id IN (
        SELECT DISTINCT res_id FROM cuisine 
        JOIN    cuisinetype ON cuisine.cuisineid = cuisinetype.`cuisineid`
        WHERE   cuisinetype.`cuisine` = 'Italian')
ORDER BY restaurants.`name`
LIMIT 20

Vì đây là FROM restaurants , chúng ta sẽ bắt đầu với trình quản lý đối tượng mặc định của mô hình đó, objects :

Restaurant.objects

WHERE mệnh đề trong trường hợp này là filter() gọi, vì vậy chúng tôi thêm nó cho thuật ngữ đầu tiên:

Restaurant.objects.filter(city=8)

Bạn có thể xóa giá trị khóa chính hoặc City đối tượng bên tay phải của thuật ngữ đó. Tuy nhiên, phần còn lại của truy vấn trở nên phức tạp hơn vì nó cần JOIN . Một tham gia trong Django trông giống như tham khảo thông qua trường quan hệ. Trong một truy vấn, điều đó có nghĩa là kết hợp các tên trường có liên quan bằng một dấu gạch dưới kép:

Restaurant.objects.filter(city=8, cuisine_type__name="Italian")

Django biết trường nào nên tham gia vì điều đó được khai báo trong Cuisine bảng được kéo vào bởi through=Cuisine tham số trong cuisine_types . nó cũng biết thực hiện một truy vấn con vì bạn đang trải qua một quan hệ M2M.

Vì vậy, chúng ta có SQL tương đương với:

SELECT  restaurants.`name`, restaurants.`address`
FROM    restaurants
WHERE   city_id = 8 AND restaurants.id IN (
        SELECT res_id FROM cuisine 
        JOIN    cuisinetype ON cuisine.cuisineid = cuisinetype.`cuisineid`
        WHERE   cuisinetype.`cuisine` = 'Italian')

Nửa đường. Bây giờ chúng ta cần SELECT DISTINCT vì vậy chúng tôi không nhận được nhiều bản sao của cùng một bản ghi:

Restaurant.objects.filter(city=8, cuisine_type__name="Italian").distinct()

Và bạn cần kéo các loại ẩm thực vào để trưng bày. Hóa ra rằng truy vấn bạn có ở đó không hiệu quả, vì nó chỉ đưa bạn đến bảng tham gia và bạn cần phải chạy thêm các truy vấn để lấy CuisineType có liên quan Hồ sơ. Đoán xem:Django đã bảo vệ bạn.

(Restaurant.objects.filter(city=8, cuisine_type__name="Italian").distinct()
    .prefetch_related("cuisine_types"))

Django sẽ chạy hai truy vấn:một truy vấn giống như của bạn để lấy các ID chung và một truy vấn nữa để lấy CuisineType có liên quan Hồ sơ. Sau đó, các truy cập thông qua kết quả truy vấn không cần quay lại cơ sở dữ liệu.

Hai điều cuối cùng là thứ tự:

(Restaurant.objects.filter(city=8, cuisine_type__name="Italian").distinct()
    .prefetch_related("cuisine_types").order_by("name"))

LIMIT :

(Restaurant.objects.filter(city=8, cuisine_type__name="Italian").distinct()
    .prefetch_related("cuisine_types").order_by("name")[:20])

Và có truy vấn của bạn (và truy vấn liên quan) được đóng gói thành hai dòng Python. Xin lưu ý bạn, tại thời điểm này, truy vấn thậm chí chưa được thực thi. Bạn phải đặt nó vào một thứ gì đó, chẳng hạn như một khuôn mẫu, trước khi nó thực hiện bất cứ điều gì:

def cuisinesearch(request, cuisine):
    return render_to_response('cuisinesearch.html', {
        'restaurants': (Restaurant.objects.filter(city=8, 
             cuisine_type__name="Italian").distinct()
             .prefetch_related("cuisine_types").order_by("name")[:20])
        })

Bản mẫu:

{% for restaurant in cuisinesearch %}
<h2>{{ restaurant.name }}</h2>
<div class="location">{{ restaurant.location }}</div>
<h3>Cuisines:</h3>
<ul class="cuisines">{% for ct in restaurant.cuisine_types.all %}
<li>{{ ct.name }}</li>{% endfor %}
</ul>
{% endfor %}



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. varchar (255) v tinyblob v tinytext

  2. Lưu trữ ngày và tháng (không tính năm)

  3. Sử dụng MySQL C API - kiểm tra thành công của việc chèn các hàng bằng cách sử dụng các câu lệnh đã chuẩn bị

  4. Khóa ngoại Sequelize.js

  5. Kết nối MySql với Android mà không cần sử dụng PHP