Django 1.1 forms, models and hiding fields - python

Consider the following Django models:
class Host(models.Model):
# This is the hostname only
name = models.CharField(max_length=255)
class Url(models.Model):
# The complete url
url = models.CharField(max_length=255, db_index=True, unique=True)
# A foreign key identifying the host of this url
# (e.g. for http://www.example.com/index.html it will
# point to a record in Host containing 'www.example.com'
host = models.ForeignKey(Host, db_index=True)
I also have this form:
class UrlForm(forms.ModelForm):
class Meta:
model = Urls
The problem is the following: I want to compute the value of the host field automatically,
so I don't want it to appear on the HTML form displayed in the web page.
If I use 'exclude' to omit this field from the form, how can I then use the form to save information
in the database (which requires the host field to be present) ?

Use commit=False:
result = form.save(commit=False)
result.host = calculate_the_host_from(result)
result.save()

You can use exclude and then in the forms "clean" method set whatever you want.
So in your form:
class myform(models.ModelForm):
class Meta:
model=Urls
exclude= ("field_name")
def clean(self):
self.cleaned_data["field_name"] = "whatever"
return self.cleaned_data

Related

Django - Create or Update reverse foreign key object from parents DetailView

I would like to Create or Update a Child object when on the Parent object DetailView.
I have two models, as follows:
class Parent(models.Model):
name = models.CharField(max_length=50)
class Child(models.Model):
name = models.CharField(max_length=50)
parent = models.ForeignKey(
'Parent', related_name='children', on_delete=models.CASCADE)
I have the following view:
class ParentDetailView(DetailView):
model = Parent
What would be the best approach to allow the Creating or Updating of a Child object whilst on the ParentDetailView ?
I have seen the following approach in Django docs - https://docs.djangoproject.com/en/2.2/topics/class-based-views/mixins/#using-formmixin-with-detailview
Many Thanks
The "key", so to speak, is to use the primary_key parameter when creating a new field in a model class object. Consider this a modified part of an Account model from my program.
class Account(models.Model):
username = models.CharField(max_length=50)
email = models.EmailField(max_length=50, primary_key=True)
password = models.CharField(max_length=50)
posts = models.IntegerField(default=0)
The email field is set so that it is a primary_key that can be used to access this particular Account object from a program. Lets see it in views.py:
email = request.COOKIES.get('email')
user = Account.objects.get(pk=email)
user.posts = users.posts + 1
user.save()
Cool so we can update that object. You can also create a new one, and you don't have to define every field, but you do need to make sure they have default values for the database in models.py.
new_acc = Account(username = form_username, email = form_email, password = form_password)
new_acc.save()
Now, if you're super cool and with it you don't even wanna save personal information as a cookie. check it
class Account(models.Model):
username = models.CharField(max_length=50)
email = models.EmailField(max_length=50, primary_key=True)
password = models.CharField(max_length=50)
uuid = models.CharField(max_length=500, default='defaultforDB')
Creating in views.py
new_acc = Account(username = form_username, email = form_email, password = form_password, uuid = unique_uuid)
new_acc.save()
Now I still want to be able to find my account with only an email. So I created another ProfileKey model where the impersonal information username is used and stored locally on the browser to access my database.
if not(request.COOKIES.get('user', 'default') == 'default'):
user = request.COOKIES.get('user')
uuid = request.COOKIES.get('uuid')
userDB_uuid = (Account.objects.get(pk=(ProfileKey.objects.get(pk=(user))).email)).uuid
if uuid == userDB_uuid:
return render(request, 'forum/personalhome.html', {'form':form, 'user':user})
In general, create the object. Use save. Find the object, change a value, use save.

Recover user of creation and last modification

I have a model using TimeStampedModel where created and updated is already integrated
class Universo(TimeStampedModel):
nombre = models.CharField('Universo', max_length=10)
class Meta:
verbose_name = 'Universo'
verbose_name_plural = 'Universos'
ordering = ['nombre']
def __str__(self):
return self.nombre
In the administrator view indicate the user who created and modified it
Image Admin
In template I can call its attributes with
{{u}} {{u.created}} {{u.modified}}
But I can't find how to bring the user I think I have made the modification to the template
You have to do a bit more to achieve what you want. I'll give the starting point:
You must first establish a relationship between your Universo model and Django user model.
from django.auth.models import User:
class Universo(TimeStampedModel):
nombre = models.CharField('Universo', max_length=10)
created_by = models.ForeignKey(User, on_delete=models.CASCADE)
class Meta:
verbose_name = 'Universo'
verbose_name_plural = 'Universos'
ordering = ['nombre']
def __str__(self):
return self.nombre
You can use the admin login to use your superuser as the logged-in user. But, in your views, you need to include the logged-in user (from request.user) in the creation of the instance for your Univeso model.
Then, in your template, you can render who has created it by doing this:
{{ u.created_by }}
you can further probe the fields of created_by:
{{u.created_by.name}}
Modify your template like this:
{{u}} {{u.created}} {{u.modified}} {{u.created_by.username}}
You can use another of the fields like username,email or any other
This should give the user that modified it.

Django forms with variable "required" fields

I have a multi-tenant app where each "tenant" (Company model object) have multiple clients.
Each tenant may set up which required fields they need for their app.
class Client(models.Model):
"""
Client information
"""
company = models.ForeignKey(Company, blank=True, null=True, default=1, on_delete=models.SET_NULL)
name = models.CharField(max_length=150, blank=True)
email = models.EmailField(max_length=255, unique=True)
phone_number = models.CharField(max_length=50, blank=True, null=True)
class RequiredClientFields(models.Model):
"""
Let each business decide how to enforce the data filling requirements for its staff/clients.
0 - dont even show it
1 - show it, but dont require (default)
2 - require field for either staff or client
3 - require for clients when self-filling their form, but not the staff members
"""
company = models.ForeignKey(Company, db_index=True, on_delete=models.CASCADE)
field_name = models.CharField(max_length=50)
status = models.PositiveSmallIntegerField(choices=FIELD_STATUS_CHOICES, default=1)
So, when creating the django forms to use on the template, whats to best way to display (and validate) each field according to the Company's policies?
thanks
Something like this might work.
Declare a ModelForm and overwrite __init__() with logic to delete fields or change their required status:
class ClientForm(forms.ModelForm):
class Meta:
model = Client
fields = '__all__'
def __init__(self, company, user, *args, **kwargs):
super(ClientForm, self).__init__(*args, **kwargs)
# For each RequiredClientFields instance,
# get the matching form field and make changes
for rule in RequiredClientFields.objects.filter(company=company):
# get the form field
field = self.fields.get(rule.field_name, None)
if field:
if rule.status == 0:
# remove field from form
self.fields.pop(rule.field_name)
elif rule.status == 2:
# require field
field.required = True
elif rule.status == 3 and not user.is_staff:
# require for clients when self-filling their form,
# but not the staff members
field.required = True
Then create an instance of the ModelForm in your view, passing arguments for the company and user.
company = Company.objects.get(pk=1)
client_form = ClientForm(company=company, user=request.user)
Be aware that there are potential security implications when controlling form fields this way. Take a look at the relevant section in the Django ModelForm docs.

Django auto save m2m relationship in form using through table

I have a m2m relationship between Servers and Products in Django with a through table called ServerProducts.
class ServerProduct(TimeStampedModel):
# Additional fields may be required in the future
server = models.ForeignKey('Server', on_delete=models.CASCADE)
product = models.ForeignKey('Product', on_delete=models.CASCADE)
class Server(TimeStampedModel):
name = models.CharField(max_length=35)
# ...
products = models.ManyToManyField('Product', through='ServerProduct',
related_name='products', blank=True)
class Product(TimeStampedModel):
name = models.CharField(max_length=45, unique=True)
# ...
servers = models.ManyToManyField(
'Server', through='ServerProduct', related_name='servers')
In my view I have a form which allows users to create a Server and select from a list of all products for the Server to be associted with.
In order to create the ServerProduct objects (for the through table) on each save I have to write the following code inside save().
class ServerForm(forms.ModelForm):
class Meta:
model = Server
fields = '__all__'
def save(self, commit=True):
instance = super(ServerForm, self).save(commit=False)
instance.save()
if instance.products.count():
instance.products.clear()
for product in self.cleaned_data['products']:
ServerProduct.objects.create(server=instance, product=product)
return instance
I want to be able to reuse the form for both Create and Update views. Hence why I have to check if the current Server is associated with any products, and then do instance.products.clear(). To make sure it removes any previous products if they get deselected by a user.
This entire process feels unecessary, especially when I've read a lot about Django's built-in form.save_m2m() method. My question is, is there a simpler way do achieve what I'm doing using Django built-in's?

How to relative urls in Django URLField

How i can get relative urls in my field after serialize? now i get abolute.
My model:
class Article(models.Model):
title = models.CharField(max_length=120)
image = models.ImageField()
text = models.TextField()
link = models.URLField()
And serializer:
class ArticleSerializer(ModelSerializer):
link = URLField()
class Meta:
model = Article
fields = '__all__'
Actually, without the http://... prefix, the url will not be a valid url. If you want to link somewhere inside your app, you can take the output of something like django's reverse and store it in a CharField (or just do some string manipulation by declaring a method, prior to inserting to the database or prior to serialization-deserialization).

Categories

Resources