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

时间:2018-04-11 10:56:37

标签: python 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这样的非关系数据库,但是有一些lib用于此目的。例如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中的集合中的每个文档定义不同的字段集?

2 个答案:

答案 0 :(得分:3)

替代

我喜欢使用django-mongoengine,因为它可以在处理MongoDB模型时更清楚。

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

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,
    )

答案

因此,对于您的情况,您需要使用的是Dynamic document schemas,其工作方式与Document相同,但设置为它们的任何数据/属性也将被保存。

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

答案 1 :(得分:0)

我在用户个人资料页面中遇到了这个问题。这是我的解决方案。

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})