Django 是否允许在 MongoDB 中为每个文档定义不同的字段集?



Django 和 MongoDB

支持different set of fields for each document in a collection是MongoDB的功能之一。它允许您在同一集合中存储类似的数据,但具有不同的属性。

例如:

{
        _id: ObjectId("51156a1e056d6f966f268f81"),
        type: "Article",
        author: "Derick Rethans",
        title: "Introduction to Document Databases with MongoDB",
        date: ISODate("2013-04-24T16:26:31.911Z"),
        body: "This arti…"
},
{
        _id: ObjectId("51156a1e056d6f966f268f82"),
        type: "Book",
        author: "Derick Rethans",
        title: "php|architect's Guide to Date and Time Programming with PHP",
        isbn: "978-0-9738621-5-7"
}

默认情况下,Django 不支持像 mongodb 这样的非关系数据库,但有一些用于此目的的库。 例如,Django MongoDB Engine 是 Django 的 MongoDB 后端。

MongoDB允许为集合中的每个文档使用不同的字段集,但是在django中,您必须定义models.py

from django.db import models
from djangotoolbox.fields import ListField

class Post(models.Model):
    title = models.CharField()
    text = models.TextField()
    tags = ListField()
    comments = ListField()

问题是:使用 Django 时,有没有办法为 MongoDB 中集合中的每个文档定义不同的字段集?

替代方案

我喜欢使用 django-mongoengine,因为它在处理 MongoDB 模型时让事情变得更加清晰。

例如,您可以创建要转换为模型的结构化Document,也可以创建要在已存在的模型中使用的结构化文档Embedded文档。

from django_mongoengine import Document, EmbeddedDocument, fields
class Comment(EmbeddedDocument):
    created_at = fields.DateTimeField(
        default=datetime.datetime.now, editable=False,
    )
    author = fields.StringField(verbose_name="Name", max_length=255)
    email  = fields.EmailField(verbose_name="Email")
    body = fields.StringField(verbose_name="Comment")
class Post(Document):
    created_at = fields.DateTimeField(
        default=datetime.datetime.now, editable=False,
    )
    title = fields.StringField(max_length=255)
    slug = fields.StringField(max_length=255, primary_key=True)
    comments = fields.ListField(
        fields.EmbeddedDocumentField('Comment'), blank=True,
    )

答案

因此,对于您的情况,您需要使用的是动态文档架构,其工作方式与文档相同,但设置为它们的任何数据/属性也将保存。

class Page(DynamicDocument):
    title = StringField(max_length=200, required=True)
# Create a new page and add tags
>>> page = Page(title='Using MongoEngine')
>>> page.tags = ['mongodb', 'mongoengine']
>>> page.save()
>>> Page.objects(tags='mongoengine').count()
>>> 1

我在用户配置文件页面中遇到了这个问题。这是我的解决方案。

model.py

from django.contrib.auth.models import User
from django.db import models
from django.core.validators import RegexValidator
# Create your models here.
class Profile(models.Model): 

    
    user = models.OneToOneField(User,on_delete=models.CASCADE,primary_key=True,related_name="user_profile")
    fullname = models.CharField(max_length=100,verbose_name="full name")     
    about = models.CharField(max_length=300,blank=True,null=True)
    hobies = models.CharField(max_length=200,blank=True)
    recent_aktivity = models.CharField(max_length=150,verbose_name="recent activity",null=True)
    photo = models.ImageField(blank=True,null=True,upload_to="images/")
    recent_badges = models.CharField(max_length=100,verbose_name="recent badges",null=True)
    phone_regex = RegexValidator(regex=r'^+?1?d{9,15}$', message="Phone number must be entered in the format: '+999999999'. Up to 15 digits allowed.")
    phone_number = models.CharField(validators=[phone_regex], max_length=17, blank=True,null=True,verbose_name="phone number") 
    website_url = models.URLField(blank=True,null=True,verbose_name="company website")
    projects =models.CharField(max_length=200,blank=True,null=True)
    bio = models.CharField(max_length=300,blank=True,null=True)
    
    
    
    def __str__(self):
        return f'{self.user.username}-ProfileModel'

signals.py

from django.db.models.signals import post_save
from django.dispatch import receiver
from django.contrib.auth.models import User
from .models import Profile
@receiver(post_save,sender=User)
def update_user_profile(sender,instance,created,**kwargs):
    if created:
        profile = Profile.objects.create(user =instance)

app.py

from django.apps import AppConfig

class ProfileConfig(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'Profile'
    def ready(self):
        import Profile.signals

forms.py

from django import forms
from.models import Profile

class ProfileForm(forms.ModelForm):   
        
    
      class Meta:
          model = Profile
          fields = '__all__'
          exclude = ['user']

views.py

 from django.contrib import messages
    from django.contrib.auth.decorators import login_required
    from django.http import HttpResponseRedirect
    from django.urls.base import reverse
    from .forms import ProfileForm
    from .models import Profile
    from django.shortcuts import redirect, render,get_object_or_404
    from django.contrib.auth import update_session_auth_hash
    from django.contrib.auth.forms import PasswordChangeForm
    
    login_required(login_url="user:login")
    def dashboard(request):
        return render(request,"dashboard.html")
    
    
    @login_required(login_url="user:login")
    def get_profile(request):    
        
        profile = get_object_or_404(Profile,user=request.user)
        
    return render(request,"profile.html",{"profile":profile})

最新更新